merge down trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hssf_cryptoapi@1755463 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0bfefdfc04
commit
680683cf77
77
build.xml
77
build.xml
@ -17,7 +17,6 @@ KIND, either express or implied. See the License for the
|
|||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This build was tested with ant 1.9.4 although it will probably work with
|
This build was tested with ant 1.9.4 although it will probably work with
|
||||||
other versions, however at least 1.8.0 is required.
|
other versions, however at least 1.8.0 is required.
|
||||||
@ -133,6 +132,7 @@ under the License.
|
|||||||
<property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
|
<property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
|
||||||
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
|
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
|
||||||
<property name="ooxml.lite.output.dir" location="build/ooxml-lite-classes"/>
|
<property name="ooxml.lite.output.dir" location="build/ooxml-lite-classes"/>
|
||||||
|
<property name="ooxml.lite.testokfile" location="build/ooxml-lite-testokfile.txt"/>
|
||||||
|
|
||||||
<!-- XSSF/SXSSF subset of OOXML: -->
|
<!-- XSSF/SXSSF subset of OOXML: -->
|
||||||
<property name="ooxml.ss.testokfile" location="build/ooxml-ss-testokfile.txt"/>
|
<property name="ooxml.ss.testokfile" location="build/ooxml-ss-testokfile.txt"/>
|
||||||
@ -169,6 +169,9 @@ under the License.
|
|||||||
<property name="main.ant.url" value="${repository.m2}/maven2/org/apache/ant/ant/1.9.4/ant-1.9.4.jar"/>
|
<property name="main.ant.url" value="${repository.m2}/maven2/org/apache/ant/ant/1.9.4/ant-1.9.4.jar"/>
|
||||||
<property name="main.antlauncher.jar" location="${main.lib}/ant-launcher-1.9.4.jar"/>
|
<property name="main.antlauncher.jar" location="${main.lib}/ant-launcher-1.9.4.jar"/>
|
||||||
<property name="main.antlauncher.url" value="${repository.m2}/maven2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar"/>
|
<property name="main.antlauncher.url" value="${repository.m2}/maven2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar"/>
|
||||||
|
<property name="main.commons-collections4.jar" location="${main.lib}/commons-collections4-4.1.jar"/>
|
||||||
|
<property name="main.commons-collections4.url"
|
||||||
|
value="${repository.m2}/maven2/org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.jar"/>
|
||||||
|
|
||||||
<!-- xml signature libs -->
|
<!-- xml signature libs -->
|
||||||
<property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.0.6.jar"/>
|
<property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.0.6.jar"/>
|
||||||
@ -192,8 +195,8 @@ under the License.
|
|||||||
value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar"/>
|
value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar"/>
|
||||||
|
|
||||||
<!-- coverage libs -->
|
<!-- coverage libs -->
|
||||||
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.6.201602180812.zip"/>
|
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.7.201606060606.zip"/>
|
||||||
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.6.201602180812/jacoco-0.7.6.201602180812.zip"/>
|
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.7.201606060606/jacoco-0.7.7.201606060606.zip"/>
|
||||||
<property name="asm.jar" location="${main.lib}/asm-all-5.0.3.jar"/>
|
<property name="asm.jar" location="${main.lib}/asm-all-5.0.3.jar"/>
|
||||||
<property name="asm.url" value="${repository.m2}/maven2/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar"/>
|
<property name="asm.url" value="${repository.m2}/maven2/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar"/>
|
||||||
|
|
||||||
@ -285,6 +288,7 @@ under the License.
|
|||||||
</condition>
|
</condition>
|
||||||
<property name="findbugs.version" value="2.0.3" if:set="findbugs.jdk6"/>
|
<property name="findbugs.version" value="2.0.3" if:set="findbugs.jdk6"/>
|
||||||
<property name="findbugs.version" value="3.0.1" unless:set="findbugs.jdk6"/>
|
<property name="findbugs.version" value="3.0.1" unless:set="findbugs.jdk6"/>
|
||||||
|
<echo message="Findbugs-Version: ${findbugs.version} for Java ${ant.java.version}"/>
|
||||||
<property name="findbugs.url" value="http://prdownloads.sourceforge.net/findbugs/findbugs-noUpdateChecks-${findbugs.version}.zip?download"/>
|
<property name="findbugs.url" value="http://prdownloads.sourceforge.net/findbugs/findbugs-noUpdateChecks-${findbugs.version}.zip?download"/>
|
||||||
<property name="findbugs.jar" location="${main.lib}/findbugs-noUpdateChecks-${findbugs.version}.zip"/>
|
<property name="findbugs.jar" location="${main.lib}/findbugs-noUpdateChecks-${findbugs.version}.zip"/>
|
||||||
|
|
||||||
@ -303,6 +307,8 @@ under the License.
|
|||||||
|
|
||||||
<!-- this can be overwriten to empty when running with Java 9 -->
|
<!-- this can be overwriten to empty when running with Java 9 -->
|
||||||
<property name="maxpermsize" value="-XX:MaxPermSize=256m"/>
|
<property name="maxpermsize" value="-XX:MaxPermSize=256m"/>
|
||||||
|
<property name="java9addmods" value="-Dthis.is.a.dummy=true"/>
|
||||||
|
<property name="java9addmodsvalue" value="-Dthis.is.a.dummy=true"/>
|
||||||
|
|
||||||
<path id="main.classpath">
|
<path id="main.classpath">
|
||||||
<pathelement location="${main.commons-logging.jar}"/>
|
<pathelement location="${main.commons-logging.jar}"/>
|
||||||
@ -310,6 +316,7 @@ under the License.
|
|||||||
<pathelement location="${main.log4j.jar}"/>
|
<pathelement location="${main.log4j.jar}"/>
|
||||||
<pathelement location="${main.junit.jar}"/>
|
<pathelement location="${main.junit.jar}"/>
|
||||||
<pathelement location="${main.hamcrest.jar}"/>
|
<pathelement location="${main.hamcrest.jar}"/>
|
||||||
|
<pathelement location="${main.commons-collections4.jar}"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<path id="scratchpad.classpath">
|
<path id="scratchpad.classpath">
|
||||||
@ -498,9 +505,7 @@ under the License.
|
|||||||
<attribute name="src"/>
|
<attribute name="src"/>
|
||||||
<attribute name="dest"/>
|
<attribute name="dest"/>
|
||||||
<sequential>
|
<sequential>
|
||||||
<local name="exists"/>
|
<!--fail
|
||||||
<available file="@{dest}" property="exists"/>
|
|
||||||
<!--fail unless:true="${exists}"
|
|
||||||
message="Java version might be uncapable to download https URLs - see https://stackoverflow.com/questions/6851461/java-why-does-ssl-handshake-give-could-not-generate-dh-keypair-exception">
|
message="Java version might be uncapable to download https URLs - see https://stackoverflow.com/questions/6851461/java-why-does-ssl-handshake-give-could-not-generate-dh-keypair-exception">
|
||||||
<condition>
|
<condition>
|
||||||
<and>
|
<and>
|
||||||
@ -509,7 +514,7 @@ under the License.
|
|||||||
</and>
|
</and>
|
||||||
</condition>
|
</condition>
|
||||||
</fail-->
|
</fail-->
|
||||||
<get src="@{src}" dest="@{dest}" unless:true="${exists}"/>
|
<get src="@{src}" dest="@{dest}" skipexisting="true"/>
|
||||||
</sequential>
|
</sequential>
|
||||||
</macrodef>
|
</macrodef>
|
||||||
|
|
||||||
@ -531,12 +536,14 @@ under the License.
|
|||||||
<include name="jacoco-0.7.2*"/>
|
<include name="jacoco-0.7.2*"/>
|
||||||
<include name="jacoco-0.7.3*"/>
|
<include name="jacoco-0.7.3*"/>
|
||||||
<include name="jacoco-0.7.4*"/>
|
<include name="jacoco-0.7.4*"/>
|
||||||
|
<include name="jacoco-0.7.6*"/>
|
||||||
<include name="log4j-1.2.13*"/>
|
<include name="log4j-1.2.13*"/>
|
||||||
<include name="org.jacoco.*-0.6.*"/>
|
<include name="org.jacoco.*-0.6.*"/>
|
||||||
<include name="org.jacoco.*-0.7.1*"/>
|
<include name="org.jacoco.*-0.7.1*"/>
|
||||||
<include name="org.jacoco.*-0.7.2*"/>
|
<include name="org.jacoco.*-0.7.2*"/>
|
||||||
<include name="org.jacoco.*-0.7.3*"/>
|
<include name="org.jacoco.*-0.7.3*"/>
|
||||||
<include name="org.jacoco.*-0.7.4*"/>
|
<include name="org.jacoco.*-0.7.4*"/>
|
||||||
|
<include name="org.jacoco.*-0.7.6*"/>
|
||||||
<include name="dom4j*"/>
|
<include name="dom4j*"/>
|
||||||
<include name="apache-rat-0.10*"/>
|
<include name="apache-rat-0.10*"/>
|
||||||
<include name="xercesImpl-*.jar"/>
|
<include name="xercesImpl-*.jar"/>
|
||||||
@ -587,6 +594,7 @@ under the License.
|
|||||||
<available file="${dsig.bouncycastle-pkix.jar}"/>
|
<available file="${dsig.bouncycastle-pkix.jar}"/>
|
||||||
<available file="${dsig.xmlsec.jar}"/>
|
<available file="${dsig.xmlsec.jar}"/>
|
||||||
<available file="${dsig.sl4j-api.jar}"/>
|
<available file="${dsig.sl4j-api.jar}"/>
|
||||||
|
<available file="${main.commons-collections4.jar}"/>
|
||||||
</and>
|
</and>
|
||||||
<isset property="disconnected"/>
|
<isset property="disconnected"/>
|
||||||
</or>
|
</or>
|
||||||
@ -605,6 +613,7 @@ under the License.
|
|||||||
<downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
|
<downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
|
||||||
<downloadfile src="${asm.url}" dest="${asm.jar}"/>
|
<downloadfile src="${asm.url}" dest="${asm.jar}"/>
|
||||||
<downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/>
|
<downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/>
|
||||||
|
<downloadfile src="${main.commons-collections4.url}" dest="${main.commons-collections4.jar}"/>
|
||||||
<unzip src="${jacoco.zip}" dest=".">
|
<unzip src="${jacoco.zip}" dest=".">
|
||||||
<patternset>
|
<patternset>
|
||||||
<include name="lib/*.jar"/>
|
<include name="lib/*.jar"/>
|
||||||
@ -1161,6 +1170,8 @@ under the License.
|
|||||||
<group name="Main">
|
<group name="Main">
|
||||||
<classfiles>
|
<classfiles>
|
||||||
<fileset dir="${main.output.dir}">
|
<fileset dir="${main.output.dir}">
|
||||||
|
<!-- exclude some generated classes -->
|
||||||
|
<exclude name="org/apache/poi/sl/draw/binding/*.class"/>
|
||||||
<!-- exclude large test-class -->
|
<!-- exclude large test-class -->
|
||||||
<exclude name="org/apache/poi/hssf/usermodel/DummyGraphics2d.class"/>
|
<exclude name="org/apache/poi/hssf/usermodel/DummyGraphics2d.class"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
@ -1242,6 +1253,8 @@ under the License.
|
|||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
<jvmarg value="-Xmx256m"/>
|
<jvmarg value="-Xmx256m"/>
|
||||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${main.reports.test}">
|
<batchtest todir="${main.reports.test}">
|
||||||
@ -1258,6 +1271,16 @@ under the License.
|
|||||||
<antcall target="-test-main-write-testfile"/>
|
<antcall target="-test-main-write-testfile"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="test-report" depends="init">
|
||||||
|
<mkdir dir="build/report"/>
|
||||||
|
<junitreport todir="build/report">
|
||||||
|
<fileset dir="build">
|
||||||
|
<include name="*results/**/TEST-*.xml"/>
|
||||||
|
</fileset>
|
||||||
|
<report format="frames" todir="build/report"/>
|
||||||
|
</junitreport>
|
||||||
|
</target>
|
||||||
|
|
||||||
<target name="-test-property-check" unless="testcase">
|
<target name="-test-property-check" unless="testcase">
|
||||||
<echo message="Please use -Dtestcase=org.your.testcase to run a single test"/>
|
<echo message="Please use -Dtestcase=org.your.testcase to run a single test"/>
|
||||||
<fail/>
|
<fail/>
|
||||||
@ -1288,6 +1311,8 @@ under the License.
|
|||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
<jvmarg value="-Xmx256m"/>
|
<jvmarg value="-Xmx256m"/>
|
||||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${main.reports.test}">
|
<batchtest todir="${main.reports.test}">
|
||||||
@ -1335,6 +1360,8 @@ under the License.
|
|||||||
and on Windows with jdk-1.5.22
|
and on Windows with jdk-1.5.22
|
||||||
-->
|
-->
|
||||||
<jvmarg value="-Xmx256M"/>
|
<jvmarg value="-Xmx256M"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${scratchpad.reports.test}">
|
<batchtest todir="${scratchpad.reports.test}">
|
||||||
@ -1373,6 +1400,8 @@ under the License.
|
|||||||
<jvmarg value="${maxpermsize}"/>
|
<jvmarg value="${maxpermsize}"/>
|
||||||
<jvmarg value="-Xmx768M"/>
|
<jvmarg value="-Xmx768M"/>
|
||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
@ -1396,6 +1425,8 @@ under the License.
|
|||||||
<syspropertyset refid="junit.properties"/>
|
<syspropertyset refid="junit.properties"/>
|
||||||
<jvmarg value="-Xmx768M"/>
|
<jvmarg value="-Xmx768M"/>
|
||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${ooxml.reports.test}">
|
<batchtest todir="${ooxml.reports.test}">
|
||||||
@ -1439,6 +1470,8 @@ under the License.
|
|||||||
<jvmarg value="${maxpermsize}"/>
|
<jvmarg value="${maxpermsize}"/>
|
||||||
<jvmarg value="-Xmx768M"/>
|
<jvmarg value="-Xmx768M"/>
|
||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
@ -1485,6 +1518,8 @@ under the License.
|
|||||||
<syspropertyset refid="junit.properties"/>
|
<syspropertyset refid="junit.properties"/>
|
||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
<jvmarg value="-Xmx1512M"/>
|
<jvmarg value="-Xmx1512M"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${integration.reports.test}">
|
<batchtest todir="${integration.reports.test}">
|
||||||
@ -1503,7 +1538,20 @@ under the License.
|
|||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- Section: test-ooxml-lite -->
|
<!-- Section: test-ooxml-lite -->
|
||||||
<target name="compile-ooxml-lite" depends="compile-ooxml">
|
<target name="-compile-ooxml-lite-check">
|
||||||
|
<uptodate property="ooxml.lite.test.notRequired" targetfile="${ooxml.lite.testokfile}">
|
||||||
|
<srcfiles dir="${ooxml.src}"/>
|
||||||
|
<srcfiles dir="${ooxml.src.test}"/>
|
||||||
|
<srcfiles file="${ooxml.xsds.jar}"/>
|
||||||
|
<srcfiles file="${ooxml.security.jar}"/>
|
||||||
|
</uptodate>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="compile-ooxml-lite" depends="-compile-ooxml-lite-check,compile-ooxml"
|
||||||
|
unless="ooxml.lite.test.notRequired">
|
||||||
|
<delete file="${ooxml.lite.testokfile}"/>
|
||||||
|
<echo message="Running ooxml-lite generator"/>
|
||||||
|
|
||||||
<property name="ooxml.lite-merged.dir" location="build/ooxml-lite-merged"/>
|
<property name="ooxml.lite-merged.dir" location="build/ooxml-lite-merged"/>
|
||||||
<mkdir dir="${ooxml.lite-merged.dir}"/>
|
<mkdir dir="${ooxml.lite-merged.dir}"/>
|
||||||
|
|
||||||
@ -1522,6 +1570,8 @@ under the License.
|
|||||||
<syspropertyset refid="junit.properties"/>
|
<syspropertyset refid="junit.properties"/>
|
||||||
<jvmarg value="${maxpermsize}"/>
|
<jvmarg value="${maxpermsize}"/>
|
||||||
<jvmarg value="-Xmx512m"/>
|
<jvmarg value="-Xmx512m"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<arg value="-ooxml"/>
|
<arg value="-ooxml"/>
|
||||||
<arg value="${ooxml.lite-merged.dir}/ooxml-lite-merged.jar"/>
|
<arg value="${ooxml.lite-merged.dir}/ooxml-lite-merged.jar"/>
|
||||||
<arg value="-test"/>
|
<arg value="-test"/>
|
||||||
@ -1529,6 +1579,8 @@ under the License.
|
|||||||
<arg value="-dest"/>
|
<arg value="-dest"/>
|
||||||
<arg value="${ooxml.lite.output.dir}"/>
|
<arg value="${ooxml.lite.output.dir}"/>
|
||||||
</java>
|
</java>
|
||||||
|
|
||||||
|
<echo file="${ooxml.lite.testokfile}" append="false" message="testok"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-xsds,compile-ooxml-lite">
|
<target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-xsds,compile-ooxml-lite">
|
||||||
@ -1557,6 +1609,8 @@ under the License.
|
|||||||
<classpath refid="test.excelant.classpath"/>
|
<classpath refid="test.excelant.classpath"/>
|
||||||
<syspropertyset refid="junit.properties"/>
|
<syspropertyset refid="junit.properties"/>
|
||||||
<jvmarg value="-ea"/>
|
<jvmarg value="-ea"/>
|
||||||
|
<jvmarg value="${java9addmods}" />
|
||||||
|
<jvmarg value="${java9addmodsvalue}" />
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
<batchtest todir="${excelant.reports.test}">
|
<batchtest todir="${excelant.reports.test}">
|
||||||
@ -1868,6 +1922,7 @@ under the License.
|
|||||||
<fileset dir="${main.lib}">
|
<fileset dir="${main.lib}">
|
||||||
<include name="commons-codec-*.jar"/>
|
<include name="commons-codec-*.jar"/>
|
||||||
<include name="commons-logging-*.jar"/>
|
<include name="commons-logging-*.jar"/>
|
||||||
|
<include name="commons-collections4-*.jar"/>
|
||||||
<include name="junit-*.jar"/>
|
<include name="junit-*.jar"/>
|
||||||
<include name="log4j-*.jar"/>
|
<include name="log4j-*.jar"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
@ -2083,7 +2138,7 @@ under the License.
|
|||||||
</forbiddenapis>
|
</forbiddenapis>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="findbugs" depends="assemble">
|
<target name="findbugs" depends="jar">
|
||||||
<downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
|
<downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
|
||||||
|
|
||||||
<property name="findbugs.home" value="build/findbugs" />
|
<property name="findbugs.home" value="build/findbugs" />
|
||||||
@ -2103,11 +2158,13 @@ under the License.
|
|||||||
output="xml:withMessages"
|
output="xml:withMessages"
|
||||||
outputFile="build/findbugs.xml"
|
outputFile="build/findbugs.xml"
|
||||||
effort="max"
|
effort="max"
|
||||||
|
failOnError="true"
|
||||||
excludeFilter="src/resources/devtools/findbugs-filters.xml">
|
excludeFilter="src/resources/devtools/findbugs-filters.xml">
|
||||||
<fileset dir="${dist.dir}/maven">
|
<fileset dir="${dist.dir}/maven">
|
||||||
<include name="poi/poi-${version.id}.jar"/>
|
<include name="poi/poi-${version.id}.jar"/>
|
||||||
<include name="poi-scratchpad/poi-scratchpad-${version.id}.jar"/>
|
<include name="poi-scratchpad/poi-scratchpad-${version.id}.jar"/>
|
||||||
<include name="poi-ooxml/poi-ooxml-${version.id}.jar"/>
|
<include name="poi-ooxml/poi-ooxml-${version.id}.jar"/>
|
||||||
|
<include name="poi-excelant/poi-excelant-${version.id}.jar"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<auxClasspath path="${dsig.bouncycastle-pkix.jar}" />
|
<auxClasspath path="${dsig.bouncycastle-pkix.jar}" />
|
||||||
<auxClasspath path="${dsig.bouncycastle-prov.jar}" />
|
<auxClasspath path="${dsig.bouncycastle-prov.jar}" />
|
||||||
@ -2117,9 +2174,11 @@ under the License.
|
|||||||
<auxClasspath path="${ooxml.security.jar}" />
|
<auxClasspath path="${ooxml.security.jar}" />
|
||||||
<auxClasspath path="${ooxml.curvesapi.jar}" />
|
<auxClasspath path="${ooxml.curvesapi.jar}" />
|
||||||
<auxClasspath path="${ooxml.xmlbeans26.jar}" />
|
<auxClasspath path="${ooxml.xmlbeans26.jar}" />
|
||||||
|
<auxClasspath path="${main.commons-collections4.jar}" />
|
||||||
<auxClasspath path="${main.commons-codec.jar}" />
|
<auxClasspath path="${main.commons-codec.jar}" />
|
||||||
<auxClasspath path="${main.commons-logging.jar}" />
|
<auxClasspath path="${main.commons-logging.jar}" />
|
||||||
<auxClasspath path="${main.junit.jar}" />
|
<auxClasspath path="${main.junit.jar}" />
|
||||||
|
<auxClasspath path="${main.ant.jar}" />
|
||||||
<sourcePath path="src/java" />
|
<sourcePath path="src/java" />
|
||||||
<sourcePath path="src/ooxml/java" />
|
<sourcePath path="src/ooxml/java" />
|
||||||
<sourcePath path="src/scratchpad/src" />
|
<sourcePath path="src/scratchpad/src" />
|
||||||
|
@ -91,6 +91,11 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
<version>4.12</version>
|
<version>4.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -110,6 +110,11 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
|
@ -34,184 +34,184 @@ import org.apache.poi.ss.formula.FormulaShifter;
|
|||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class RowRecordsAggregate extends RecordAggregate {
|
public final class RowRecordsAggregate extends RecordAggregate {
|
||||||
private int _firstrow = -1;
|
private int _firstrow = -1;
|
||||||
private int _lastrow = -1;
|
private int _lastrow = -1;
|
||||||
private final Map<Integer, RowRecord> _rowRecords;
|
private final Map<Integer, RowRecord> _rowRecords;
|
||||||
private final ValueRecordsAggregate _valuesAgg;
|
private final ValueRecordsAggregate _valuesAgg;
|
||||||
private final List<Record> _unknownRecords;
|
private final List<Record> _unknownRecords;
|
||||||
private final SharedValueManager _sharedValueManager;
|
private final SharedValueManager _sharedValueManager;
|
||||||
|
|
||||||
// Cache values to speed up performance of
|
// Cache values to speed up performance of
|
||||||
// getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405
|
// getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405
|
||||||
private RowRecord[] _rowRecordValues = null;
|
private RowRecord[] _rowRecordValues = null;
|
||||||
|
|
||||||
/** Creates a new instance of ValueRecordsAggregate */
|
/** Creates a new instance of ValueRecordsAggregate */
|
||||||
public RowRecordsAggregate() {
|
public RowRecordsAggregate() {
|
||||||
this(SharedValueManager.createEmpty());
|
this(SharedValueManager.createEmpty());
|
||||||
}
|
}
|
||||||
private RowRecordsAggregate(SharedValueManager svm) {
|
private RowRecordsAggregate(SharedValueManager svm) {
|
||||||
if (svm == null) {
|
if (svm == null) {
|
||||||
throw new IllegalArgumentException("SharedValueManager must be provided.");
|
throw new IllegalArgumentException("SharedValueManager must be provided.");
|
||||||
}
|
}
|
||||||
_rowRecords = new TreeMap<Integer, RowRecord>();
|
_rowRecords = new TreeMap<Integer, RowRecord>();
|
||||||
_valuesAgg = new ValueRecordsAggregate();
|
_valuesAgg = new ValueRecordsAggregate();
|
||||||
_unknownRecords = new ArrayList<Record>();
|
_unknownRecords = new ArrayList<Record>();
|
||||||
_sharedValueManager = svm;
|
_sharedValueManager = svm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param rs record stream with all {@link SharedFormulaRecord}
|
* @param rs record stream with all {@link SharedFormulaRecord}
|
||||||
* {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
|
* {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
|
||||||
* @param svm an initialised {@link SharedValueManager} (from the shared formula, array
|
* @param svm an initialised {@link SharedValueManager} (from the shared formula, array
|
||||||
* and table records of the current sheet). Never <code>null</code>.
|
* and table records of the current sheet). Never <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
|
public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
|
||||||
this(svm);
|
this(svm);
|
||||||
while(rs.hasNext()) {
|
while(rs.hasNext()) {
|
||||||
Record rec = rs.getNext();
|
Record rec = rs.getNext();
|
||||||
switch (rec.getSid()) {
|
switch (rec.getSid()) {
|
||||||
case RowRecord.sid:
|
case RowRecord.sid:
|
||||||
insertRow((RowRecord) rec);
|
insertRow((RowRecord) rec);
|
||||||
continue;
|
continue;
|
||||||
case DConRefRecord.sid:
|
case DConRefRecord.sid:
|
||||||
addUnknownRecord(rec);
|
addUnknownRecord(rec);
|
||||||
continue;
|
continue;
|
||||||
case DBCellRecord.sid:
|
case DBCellRecord.sid:
|
||||||
// end of 'Row Block'. Should only occur after cell records
|
// end of 'Row Block'. Should only occur after cell records
|
||||||
// ignore DBCELL records because POI generates them upon re-serialization
|
// ignore DBCELL records because POI generates them upon re-serialization
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rec instanceof UnknownRecord) {
|
if (rec instanceof UnknownRecord) {
|
||||||
// might need to keep track of where exactly these belong
|
// might need to keep track of where exactly these belong
|
||||||
addUnknownRecord(rec);
|
addUnknownRecord(rec);
|
||||||
while (rs.peekNextSid() == ContinueRecord.sid) {
|
while (rs.peekNextSid() == ContinueRecord.sid) {
|
||||||
addUnknownRecord(rs.getNext());
|
addUnknownRecord(rs.getNext());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rec instanceof MulBlankRecord) {
|
if (rec instanceof MulBlankRecord) {
|
||||||
_valuesAgg.addMultipleBlanks((MulBlankRecord) rec);
|
_valuesAgg.addMultipleBlanks((MulBlankRecord) rec);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(rec instanceof CellValueRecordInterface)) {
|
if (!(rec instanceof CellValueRecordInterface)) {
|
||||||
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
|
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
_valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
|
_valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Handles UnknownRecords which appear within the row/cell records
|
* Handles UnknownRecords which appear within the row/cell records
|
||||||
*/
|
*/
|
||||||
private void addUnknownRecord(Record rec) {
|
private void addUnknownRecord(Record rec) {
|
||||||
// ony a few distinct record IDs are encountered by the existing POI test cases:
|
// ony a few distinct record IDs are encountered by the existing POI test cases:
|
||||||
// 0x1065 // many
|
// 0x1065 // many
|
||||||
// 0x01C2 // several
|
// 0x01C2 // several
|
||||||
// 0x0034 // few
|
// 0x0034 // few
|
||||||
// No documentation could be found for these
|
// No documentation could be found for these
|
||||||
|
|
||||||
// keep the unknown records for re-serialization
|
// keep the unknown records for re-serialization
|
||||||
_unknownRecords.add(rec);
|
_unknownRecords.add(rec);
|
||||||
}
|
}
|
||||||
public void insertRow(RowRecord row) {
|
public void insertRow(RowRecord row) {
|
||||||
// Integer integer = Integer.valueOf(row.getRowNumber());
|
// Integer integer = Integer.valueOf(row.getRowNumber());
|
||||||
_rowRecords.put(Integer.valueOf(row.getRowNumber()), row);
|
_rowRecords.put(Integer.valueOf(row.getRowNumber()), row);
|
||||||
// Clear the cached values
|
// Clear the cached values
|
||||||
_rowRecordValues = null;
|
_rowRecordValues = null;
|
||||||
if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) {
|
if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) {
|
||||||
_firstrow = row.getRowNumber();
|
_firstrow = row.getRowNumber();
|
||||||
}
|
}
|
||||||
if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) {
|
if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) {
|
||||||
_lastrow = row.getRowNumber();
|
_lastrow = row.getRowNumber();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeRow(RowRecord row) {
|
public void removeRow(RowRecord row) {
|
||||||
int rowIndex = row.getRowNumber();
|
int rowIndex = row.getRowNumber();
|
||||||
_valuesAgg.removeAllCellsValuesForRow(rowIndex);
|
_valuesAgg.removeAllCellsValuesForRow(rowIndex);
|
||||||
Integer key = Integer.valueOf(rowIndex);
|
Integer key = Integer.valueOf(rowIndex);
|
||||||
RowRecord rr = _rowRecords.remove(key);
|
RowRecord rr = _rowRecords.remove(key);
|
||||||
if (rr == null) {
|
if (rr == null) {
|
||||||
throw new RuntimeException("Invalid row index (" + key.intValue() + ")");
|
throw new RuntimeException("Invalid row index (" + key.intValue() + ")");
|
||||||
}
|
}
|
||||||
if (row != rr) {
|
if (row != rr) {
|
||||||
_rowRecords.put(key, rr);
|
_rowRecords.put(key, rr);
|
||||||
throw new RuntimeException("Attempt to remove row that does not belong to this sheet");
|
throw new RuntimeException("Attempt to remove row that does not belong to this sheet");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the cached values
|
// Clear the cached values
|
||||||
_rowRecordValues = null;
|
_rowRecordValues = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RowRecord getRow(int rowIndex) {
|
public RowRecord getRow(int rowIndex) {
|
||||||
int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
|
int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
|
||||||
if (rowIndex < 0 || rowIndex > maxrow) {
|
if (rowIndex < 0 || rowIndex > maxrow) {
|
||||||
throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
|
throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
|
||||||
}
|
}
|
||||||
return _rowRecords.get(Integer.valueOf(rowIndex));
|
return _rowRecords.get(Integer.valueOf(rowIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPhysicalNumberOfRows()
|
public int getPhysicalNumberOfRows()
|
||||||
{
|
{
|
||||||
return _rowRecords.size();
|
return _rowRecords.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFirstRowNum()
|
public int getFirstRowNum()
|
||||||
{
|
{
|
||||||
return _firstrow;
|
return _firstrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLastRowNum()
|
public int getLastRowNum()
|
||||||
{
|
{
|
||||||
return _lastrow;
|
return _lastrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the number of row blocks.
|
/** Returns the number of row blocks.
|
||||||
* <p/>The row blocks are goupings of rows that contain the DBCell record
|
* <p/>The row blocks are goupings of rows that contain the DBCell record
|
||||||
* after them
|
* after them
|
||||||
*/
|
*/
|
||||||
public int getRowBlockCount() {
|
public int getRowBlockCount() {
|
||||||
int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
|
int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
|
||||||
if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
|
if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
|
||||||
size++;
|
size++;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRowBlockSize(int block) {
|
private int getRowBlockSize(int block) {
|
||||||
return RowRecord.ENCODED_SIZE * getRowCountForBlock(block);
|
return RowRecord.ENCODED_SIZE * getRowCountForBlock(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the number of physical rows within a block*/
|
/** Returns the number of physical rows within a block*/
|
||||||
public int getRowCountForBlock(int block) {
|
public int getRowCountForBlock(int block) {
|
||||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||||
int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
|
int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
|
||||||
if (endIndex >= _rowRecords.size())
|
if (endIndex >= _rowRecords.size())
|
||||||
endIndex = _rowRecords.size()-1;
|
endIndex = _rowRecords.size()-1;
|
||||||
|
|
||||||
return endIndex-startIndex+1;
|
return endIndex-startIndex+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the physical row number of the first row in a block*/
|
/** Returns the physical row number of the first row in a block*/
|
||||||
private int getStartRowNumberForBlock(int block) {
|
private int getStartRowNumberForBlock(int block) {
|
||||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||||
|
|
||||||
if(_rowRecordValues == null){
|
if (_rowRecordValues == null) {
|
||||||
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return _rowRecordValues[startIndex].getRowNumber();
|
return _rowRecordValues[startIndex].getRowNumber();
|
||||||
} catch(ArrayIndexOutOfBoundsException e) {
|
} catch(ArrayIndexOutOfBoundsException e) {
|
||||||
throw new RuntimeException("Did not find start row for block " + block);
|
throw new RuntimeException("Did not find start row for block " + block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the physical row number of the end row in a block*/
|
/** Returns the physical row number of the end row in a block*/
|
||||||
private int getEndRowNumberForBlock(int block) {
|
private int getEndRowNumberForBlock(int block) {
|
||||||
int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
|
int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
|
||||||
if (endIndex >= _rowRecords.size())
|
if (endIndex >= _rowRecords.size())
|
||||||
endIndex = _rowRecords.size()-1;
|
endIndex = _rowRecords.size()-1;
|
||||||
|
|
||||||
if(_rowRecordValues == null){
|
if (_rowRecordValues == null){
|
||||||
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,287 +219,287 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
|||||||
return _rowRecordValues[endIndex].getRowNumber();
|
return _rowRecordValues[endIndex].getRowNumber();
|
||||||
} catch(ArrayIndexOutOfBoundsException e) {
|
} catch(ArrayIndexOutOfBoundsException e) {
|
||||||
throw new RuntimeException("Did not find end row for block " + block);
|
throw new RuntimeException("Did not find end row for block " + block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
|
private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
|
||||||
final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
|
final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
|
||||||
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
|
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
|
||||||
|
|
||||||
Iterator<RowRecord> rowIterator = _rowRecords.values().iterator();
|
Iterator<RowRecord> rowIterator = _rowRecords.values().iterator();
|
||||||
|
|
||||||
//Given that we basically iterate through the rows in order,
|
//Given that we basically iterate through the rows in order,
|
||||||
//For a performance improvement, it would be better to return an instance of
|
//For a performance improvement, it would be better to return an instance of
|
||||||
//an iterator and use that instance throughout, rather than recreating one and
|
//an iterator and use that instance throughout, rather than recreating one and
|
||||||
//having to move it to the right position.
|
//having to move it to the right position.
|
||||||
int i=0;
|
int i=0;
|
||||||
for (;i<startIndex;i++)
|
for (;i<startIndex;i++)
|
||||||
rowIterator.next();
|
rowIterator.next();
|
||||||
int result = 0;
|
int result = 0;
|
||||||
while(rowIterator.hasNext() && (i++ < endIndex)) {
|
while(rowIterator.hasNext() && (i++ < endIndex)) {
|
||||||
Record rec = rowIterator.next();
|
Record rec = rowIterator.next();
|
||||||
result += rec.getRecordSize();
|
result += rec.getRecordSize();
|
||||||
rv.visitRecord(rec);
|
rv.visitRecord(rec);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitContainedRecords(RecordVisitor rv) {
|
public void visitContainedRecords(RecordVisitor rv) {
|
||||||
|
|
||||||
PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
|
PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
|
||||||
//DBCells are serialized before row records.
|
//DBCells are serialized before row records.
|
||||||
final int blockCount = getRowBlockCount();
|
final int blockCount = getRowBlockCount();
|
||||||
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
|
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
|
||||||
// Serialize a block of rows.
|
// Serialize a block of rows.
|
||||||
// Hold onto the position of the first row in the block
|
// Hold onto the position of the first row in the block
|
||||||
int pos=0;
|
int pos=0;
|
||||||
// Hold onto the size of this block that was serialized
|
// Hold onto the size of this block that was serialized
|
||||||
final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv);
|
final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv);
|
||||||
pos += rowBlockSize;
|
pos += rowBlockSize;
|
||||||
// Serialize a block of cells for those rows
|
// Serialize a block of cells for those rows
|
||||||
final int startRowNumber = getStartRowNumberForBlock(blockIndex);
|
final int startRowNumber = getStartRowNumberForBlock(blockIndex);
|
||||||
final int endRowNumber = getEndRowNumberForBlock(blockIndex);
|
final int endRowNumber = getEndRowNumberForBlock(blockIndex);
|
||||||
DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder();
|
DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder();
|
||||||
// Note: Cell references start from the second row...
|
// Note: Cell references start from the second row...
|
||||||
int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
|
int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
|
||||||
for (int row = startRowNumber; row <= endRowNumber; row++) {
|
for (int row = startRowNumber; row <= endRowNumber; row++) {
|
||||||
if (_valuesAgg.rowHasCells(row)) {
|
if (_valuesAgg.rowHasCells(row)) {
|
||||||
stv.setPosition(0);
|
stv.setPosition(0);
|
||||||
_valuesAgg.visitCellsForRow(row, stv);
|
_valuesAgg.visitCellsForRow(row, stv);
|
||||||
int rowCellSize = stv.getPosition();
|
int rowCellSize = stv.getPosition();
|
||||||
pos += rowCellSize;
|
pos += rowCellSize;
|
||||||
// Add the offset to the first cell for the row into the
|
// Add the offset to the first cell for the row into the
|
||||||
// DBCellRecord.
|
// DBCellRecord.
|
||||||
dbcrBuilder.addCellOffset(cellRefOffset);
|
dbcrBuilder.addCellOffset(cellRefOffset);
|
||||||
cellRefOffset = rowCellSize;
|
cellRefOffset = rowCellSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Calculate Offset from the start of a DBCellRecord to the first Row
|
// Calculate Offset from the start of a DBCellRecord to the first Row
|
||||||
rv.visitRecord(dbcrBuilder.build(pos));
|
rv.visitRecord(dbcrBuilder.build(pos));
|
||||||
}
|
}
|
||||||
for (Record _unknownRecord : _unknownRecords) {
|
for (Record _unknownRecord : _unknownRecords) {
|
||||||
// Potentially breaking the file here since we don't know exactly where to write these records
|
// Potentially breaking the file here since we don't know exactly where to write these records
|
||||||
rv.visitRecord(_unknownRecord);
|
rv.visitRecord(_unknownRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<RowRecord> getIterator() {
|
public Iterator<RowRecord> getIterator() {
|
||||||
return _rowRecords.values().iterator();
|
return _rowRecords.values().iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int findStartOfRowOutlineGroup(int row) {
|
public int findStartOfRowOutlineGroup(int row) {
|
||||||
// Find the start of the group.
|
// Find the start of the group.
|
||||||
RowRecord rowRecord = this.getRow( row );
|
RowRecord rowRecord = this.getRow( row );
|
||||||
int level = rowRecord.getOutlineLevel();
|
int level = rowRecord.getOutlineLevel();
|
||||||
int currentRow = row;
|
int currentRow = row;
|
||||||
while (currentRow >= 0 && this.getRow( currentRow ) != null) {
|
while (currentRow >= 0 && this.getRow( currentRow ) != null) {
|
||||||
rowRecord = this.getRow( currentRow );
|
rowRecord = this.getRow( currentRow );
|
||||||
if (rowRecord.getOutlineLevel() < level) {
|
if (rowRecord.getOutlineLevel() < level) {
|
||||||
return currentRow + 1;
|
return currentRow + 1;
|
||||||
}
|
}
|
||||||
currentRow--;
|
currentRow--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRow + 1;
|
return currentRow + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int findEndOfRowOutlineGroup(int row) {
|
public int findEndOfRowOutlineGroup(int row) {
|
||||||
int level = getRow( row ).getOutlineLevel();
|
int level = getRow( row ).getOutlineLevel();
|
||||||
int currentRow;
|
int currentRow;
|
||||||
for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
|
for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
|
||||||
if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) {
|
if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRow-1;
|
return currentRow-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide all rows at or below the current outline level
|
* Hide all rows at or below the current outline level
|
||||||
* @return index of the <em>next<em> row after the last row that gets hidden
|
* @return index of the <em>next<em> row after the last row that gets hidden
|
||||||
*/
|
*/
|
||||||
private int writeHidden(RowRecord pRowRecord, int row) {
|
private int writeHidden(RowRecord pRowRecord, int row) {
|
||||||
int rowIx = row;
|
int rowIx = row;
|
||||||
RowRecord rowRecord = pRowRecord;
|
RowRecord rowRecord = pRowRecord;
|
||||||
int level = rowRecord.getOutlineLevel();
|
int level = rowRecord.getOutlineLevel();
|
||||||
while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
|
while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
|
||||||
rowRecord.setZeroHeight(true);
|
rowRecord.setZeroHeight(true);
|
||||||
rowIx++;
|
rowIx++;
|
||||||
rowRecord = getRow(rowIx);
|
rowRecord = getRow(rowIx);
|
||||||
}
|
}
|
||||||
return rowIx;
|
return rowIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collapseRow(int rowNumber) {
|
public void collapseRow(int rowNumber) {
|
||||||
|
|
||||||
// Find the start of the group.
|
// Find the start of the group.
|
||||||
int startRow = findStartOfRowOutlineGroup(rowNumber);
|
int startRow = findStartOfRowOutlineGroup(rowNumber);
|
||||||
RowRecord rowRecord = getRow(startRow);
|
RowRecord rowRecord = getRow(startRow);
|
||||||
|
|
||||||
// Hide all the columns until the end of the group
|
// Hide all the columns until the end of the group
|
||||||
int nextRowIx = writeHidden(rowRecord, startRow);
|
int nextRowIx = writeHidden(rowRecord, startRow);
|
||||||
|
|
||||||
RowRecord row = getRow(nextRowIx);
|
RowRecord row = getRow(nextRowIx);
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
row = createRow(nextRowIx);
|
row = createRow(nextRowIx);
|
||||||
insertRow(row);
|
insertRow(row);
|
||||||
}
|
}
|
||||||
// Write collapse field
|
// Write collapse field
|
||||||
row.setColapsed(true);
|
row.setColapsed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a row record.
|
* Create a row record.
|
||||||
*
|
*
|
||||||
* @param rowNumber row number
|
* @param rowNumber row number
|
||||||
* @return RowRecord created for the passed in row number
|
* @return RowRecord created for the passed in row number
|
||||||
* @see org.apache.poi.hssf.record.RowRecord
|
* @see org.apache.poi.hssf.record.RowRecord
|
||||||
*/
|
*/
|
||||||
public static RowRecord createRow(int rowNumber) {
|
public static RowRecord createRow(int rowNumber) {
|
||||||
return new RowRecord(rowNumber);
|
return new RowRecord(rowNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRowGroupCollapsed(int row) {
|
public boolean isRowGroupCollapsed(int row) {
|
||||||
int collapseRow = findEndOfRowOutlineGroup(row) + 1;
|
int collapseRow = findEndOfRowOutlineGroup(row) + 1;
|
||||||
|
|
||||||
return getRow(collapseRow) != null && getRow(collapseRow).getColapsed();
|
return getRow(collapseRow) != null && getRow(collapseRow).getColapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandRow(int rowNumber) {
|
public void expandRow(int rowNumber) {
|
||||||
if (rowNumber == -1)
|
if (rowNumber == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If it is already expanded do nothing.
|
// If it is already expanded do nothing.
|
||||||
if (!isRowGroupCollapsed(rowNumber)) {
|
if (!isRowGroupCollapsed(rowNumber)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the start of the group.
|
// Find the start of the group.
|
||||||
int startIdx = findStartOfRowOutlineGroup(rowNumber);
|
int startIdx = findStartOfRowOutlineGroup(rowNumber);
|
||||||
RowRecord row = getRow(startIdx);
|
RowRecord row = getRow(startIdx);
|
||||||
|
|
||||||
// Find the end of the group.
|
// Find the end of the group.
|
||||||
int endIdx = findEndOfRowOutlineGroup(rowNumber);
|
int endIdx = findEndOfRowOutlineGroup(rowNumber);
|
||||||
|
|
||||||
// expand:
|
// expand:
|
||||||
// collapsed bit must be unset
|
// collapsed bit must be unset
|
||||||
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
|
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
|
||||||
// this by looking at the hidden bit of the enclosing group. You will have
|
// this by looking at the hidden bit of the enclosing group. You will have
|
||||||
// to look at the start and the end of the current group to determine which
|
// to look at the start and the end of the current group to determine which
|
||||||
// is the enclosing group
|
// is the enclosing group
|
||||||
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
|
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
|
||||||
if (!isRowGroupHiddenByParent(rowNumber)) {
|
if (!isRowGroupHiddenByParent(rowNumber)) {
|
||||||
for (int i = startIdx; i <= endIdx; i++) {
|
for (int i = startIdx; i <= endIdx; i++) {
|
||||||
RowRecord otherRow = getRow(i);
|
RowRecord otherRow = getRow(i);
|
||||||
if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) {
|
if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) {
|
||||||
otherRow.setZeroHeight(false);
|
otherRow.setZeroHeight(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write collapse field
|
// Write collapse field
|
||||||
getRow(endIdx + 1).setColapsed(false);
|
getRow(endIdx + 1).setColapsed(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRowGroupHiddenByParent(int row) {
|
public boolean isRowGroupHiddenByParent(int row) {
|
||||||
// Look out outline details of end
|
// Look out outline details of end
|
||||||
int endLevel;
|
int endLevel;
|
||||||
boolean endHidden;
|
boolean endHidden;
|
||||||
int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
|
int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
|
||||||
if (getRow(endOfOutlineGroupIdx + 1) == null) {
|
if (getRow(endOfOutlineGroupIdx + 1) == null) {
|
||||||
endLevel = 0;
|
endLevel = 0;
|
||||||
endHidden = false;
|
endHidden = false;
|
||||||
} else {
|
} else {
|
||||||
endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel();
|
endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel();
|
||||||
endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight();
|
endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look out outline details of start
|
// Look out outline details of start
|
||||||
int startLevel;
|
int startLevel;
|
||||||
boolean startHidden;
|
boolean startHidden;
|
||||||
int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
|
int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
|
||||||
if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
|
if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
|
||||||
startLevel = 0;
|
startLevel = 0;
|
||||||
startHidden = false;
|
startHidden = false;
|
||||||
} else {
|
} else {
|
||||||
startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel();
|
startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel();
|
||||||
startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight();
|
startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endLevel > startLevel) {
|
if (endLevel > startLevel) {
|
||||||
return endHidden;
|
return endHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
return startHidden;
|
return startHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator for the cell values
|
* Returns an iterator for the cell values
|
||||||
*/
|
*/
|
||||||
public Iterator<CellValueRecordInterface> getCellValueIterator() {
|
public Iterator<CellValueRecordInterface> getCellValueIterator() {
|
||||||
return _valuesAgg.iterator();
|
return _valuesAgg.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) {
|
public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) {
|
||||||
IndexRecord result = new IndexRecord();
|
IndexRecord result = new IndexRecord();
|
||||||
result.setFirstRow(_firstrow);
|
result.setFirstRow(_firstrow);
|
||||||
result.setLastRowAdd1(_lastrow + 1);
|
result.setLastRowAdd1(_lastrow + 1);
|
||||||
// Calculate the size of the records from the end of the BOF
|
// Calculate the size of the records from the end of the BOF
|
||||||
// and up to the RowRecordsAggregate...
|
// and up to the RowRecordsAggregate...
|
||||||
|
|
||||||
// Add the references to the DBCells in the IndexRecord (one for each block)
|
// Add the references to the DBCells in the IndexRecord (one for each block)
|
||||||
// Note: The offsets are relative to the Workbook BOF. Assume that this is
|
// Note: The offsets are relative to the Workbook BOF. Assume that this is
|
||||||
// 0 for now.....
|
// 0 for now.....
|
||||||
|
|
||||||
int blockCount = getRowBlockCount();
|
int blockCount = getRowBlockCount();
|
||||||
// Calculate the size of this IndexRecord
|
// Calculate the size of this IndexRecord
|
||||||
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
|
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
|
||||||
|
|
||||||
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
|
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
|
||||||
|
|
||||||
for (int block = 0; block < blockCount; block++) {
|
for (int block = 0; block < blockCount; block++) {
|
||||||
// each row-block has a DBCELL record.
|
// each row-block has a DBCELL record.
|
||||||
// The offset of each DBCELL record needs to be updated in the INDEX record
|
// The offset of each DBCELL record needs to be updated in the INDEX record
|
||||||
|
|
||||||
// account for row records in this row-block
|
// account for row records in this row-block
|
||||||
currentOffset += getRowBlockSize(block);
|
currentOffset += getRowBlockSize(block);
|
||||||
// account for cell value records after those
|
// account for cell value records after those
|
||||||
currentOffset += _valuesAgg.getRowCellBlockSize(
|
currentOffset += _valuesAgg.getRowCellBlockSize(
|
||||||
getStartRowNumberForBlock(block), getEndRowNumberForBlock(block));
|
getStartRowNumberForBlock(block), getEndRowNumberForBlock(block));
|
||||||
|
|
||||||
// currentOffset is now the location of the DBCELL record for this row-block
|
// currentOffset is now the location of the DBCELL record for this row-block
|
||||||
result.addDbcell(currentOffset);
|
result.addDbcell(currentOffset);
|
||||||
// Add space required to write the DBCELL record (whose reference was just added).
|
// Add space required to write the DBCELL record (whose reference was just added).
|
||||||
currentOffset += (8 + (getRowCountForBlock(block) * 2));
|
currentOffset += (8 + (getRowCountForBlock(block) * 2));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public void insertCell(CellValueRecordInterface cvRec) {
|
public void insertCell(CellValueRecordInterface cvRec) {
|
||||||
_valuesAgg.insertCell(cvRec);
|
_valuesAgg.insertCell(cvRec);
|
||||||
}
|
}
|
||||||
public void removeCell(CellValueRecordInterface cvRec) {
|
public void removeCell(CellValueRecordInterface cvRec) {
|
||||||
if (cvRec instanceof FormulaRecordAggregate) {
|
if (cvRec instanceof FormulaRecordAggregate) {
|
||||||
((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
|
((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
|
||||||
}
|
}
|
||||||
_valuesAgg.removeCell(cvRec);
|
_valuesAgg.removeCell(cvRec);
|
||||||
}
|
}
|
||||||
public FormulaRecordAggregate createFormula(int row, int col) {
|
public FormulaRecordAggregate createFormula(int row, int col) {
|
||||||
FormulaRecord fr = new FormulaRecord();
|
FormulaRecord fr = new FormulaRecord();
|
||||||
fr.setRow(row);
|
fr.setRow(row);
|
||||||
fr.setColumn((short) col);
|
fr.setColumn((short) col);
|
||||||
return new FormulaRecordAggregate(fr, null, _sharedValueManager);
|
return new FormulaRecordAggregate(fr, null, _sharedValueManager);
|
||||||
}
|
}
|
||||||
public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) {
|
public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) {
|
||||||
_valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex);
|
_valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex);
|
||||||
}
|
}
|
||||||
public DimensionsRecord createDimensions() {
|
public DimensionsRecord createDimensions() {
|
||||||
DimensionsRecord result = new DimensionsRecord();
|
DimensionsRecord result = new DimensionsRecord();
|
||||||
result.setFirstRow(_firstrow);
|
result.setFirstRow(_firstrow);
|
||||||
result.setLastRow(_lastrow);
|
result.setLastRow(_lastrow);
|
||||||
result.setFirstCol((short) _valuesAgg.getFirstCellNum());
|
result.setFirstCol((short) _valuesAgg.getFirstCellNum());
|
||||||
result.setLastCol((short) _valuesAgg.getLastCellNum());
|
result.setLastCol((short) _valuesAgg.getLastCellNum());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ package org.apache.poi.hssf.usermodel;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
||||||
import org.apache.poi.ss.formula.IStabilityClassifier;
|
import org.apache.poi.ss.formula.IStabilityClassifier;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
|
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.formula.eval.NumericValueEval;
|
import org.apache.poi.ss.formula.eval.NumericValueEval;
|
||||||
@ -33,8 +33,6 @@ import org.apache.poi.ss.usermodel.Cell;
|
|||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
@ -45,362 +43,251 @@ import org.apache.poi.util.Internal;
|
|||||||
* cell values. Be sure to call {@link #clearAllCachedResultValues()} if any workbook cells are changed between
|
* cell values. Be sure to call {@link #clearAllCachedResultValues()} if any workbook cells are changed between
|
||||||
* calls to evaluate~ methods on this class.
|
* calls to evaluate~ methods on this class.
|
||||||
*/
|
*/
|
||||||
public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
public class HSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
||||||
|
private final HSSFWorkbook _book;
|
||||||
|
|
||||||
private final WorkbookEvaluator _bookEvaluator;
|
public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
|
||||||
private final HSSFWorkbook _book;
|
this(workbook, null);
|
||||||
|
}
|
||||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
|
/**
|
||||||
this(workbook, null);
|
* @param workbook The workbook to perform the formula evaluations in
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param workbook The workbook to perform the formula evaluations in
|
|
||||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
|
||||||
* for the (conservative) assumption that any cell may have its definition changed after
|
|
||||||
* evaluation begins.
|
|
||||||
*/
|
|
||||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
|
|
||||||
this(workbook, stabilityClassifier, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param workbook The workbook to perform the formula evaluations in
|
|
||||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||||
* for the (conservative) assumption that any cell may have its definition changed after
|
* for the (conservative) assumption that any cell may have its definition changed after
|
||||||
* evaluation begins.
|
* evaluation begins.
|
||||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
*/
|
||||||
*/
|
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
|
||||||
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
this(workbook, stabilityClassifier, null);
|
||||||
_book = workbook;
|
}
|
||||||
_bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param workbook The workbook to perform the formula evaluations in
|
* @param workbook The workbook to perform the formula evaluations in
|
||||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||||
* for the (conservative) assumption that any cell may have its definition changed after
|
* for the (conservative) assumption that any cell may have its definition changed after
|
||||||
* evaluation begins.
|
* evaluation begins.
|
||||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||||
*/
|
*/
|
||||||
public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||||
return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
|
super(new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder));
|
||||||
}
|
_book = workbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param workbook The workbook to perform the formula evaluations in
|
||||||
|
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||||
|
* for the (conservative) assumption that any cell may have its definition changed after
|
||||||
|
* evaluation begins.
|
||||||
|
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||||
|
*/
|
||||||
|
public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||||
|
return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coordinates several formula evaluators together so that formulas that involve external
|
* Coordinates several formula evaluators together so that formulas that involve external
|
||||||
* references can be evaluated.
|
* references can be evaluated.
|
||||||
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
||||||
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
||||||
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
||||||
*/
|
*/
|
||||||
public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) {
|
public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) {
|
||||||
WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];
|
BaseFormulaEvaluator.setupEnvironment(workbookNames, evaluators);
|
||||||
for (int i = 0; i < wbEvals.length; i++) {
|
}
|
||||||
wbEvals[i] = evaluators[i]._bookEvaluator;
|
|
||||||
}
|
|
||||||
CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
||||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||||
return _bookEvaluator;
|
* has changed.
|
||||||
|
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||||
|
* of the evaluate~ methods of this class
|
||||||
|
*/
|
||||||
|
public void notifyUpdateCell(HSSFCell cell) {
|
||||||
|
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell(cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
|
||||||
* in the evaluated workbook. If performance is not critical, a single call to this method
|
|
||||||
* may be used instead of many specific calls to the notify~ methods.
|
|
||||||
*
|
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
|
||||||
* of the evaluate~ methods of this class
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clearAllCachedResultValues() {
|
|
||||||
_bookEvaluator.clearAllCachedResultValues();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
|
||||||
* has changed.
|
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
|
||||||
* of the evaluate~ methods of this class
|
|
||||||
*/
|
|
||||||
public void notifyUpdateCell(HSSFCell cell) {
|
|
||||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell(cell));
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyUpdateCell(Cell cell) {
|
public void notifyUpdateCell(Cell cell) {
|
||||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Should be called to tell the cell value cache that the specified cell has just been
|
* Should be called to tell the cell value cache that the specified cell has just been
|
||||||
* deleted.
|
* deleted.
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||||
* of the evaluate~ methods of this class
|
* of the evaluate~ methods of this class
|
||||||
*/
|
*/
|
||||||
public void notifyDeleteCell(HSSFCell cell) {
|
public void notifyDeleteCell(HSSFCell cell) {
|
||||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell(cell));
|
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell(cell));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void notifyDeleteCell(Cell cell) {
|
public void notifyDeleteCell(Cell cell) {
|
||||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell((HSSFCell)cell));
|
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||||
* has changed.
|
* has changed.
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||||
* of the evaluate~ methods of this class
|
* of the evaluate~ methods of this class
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void notifySetFormula(Cell cell) {
|
public void notifySetFormula(Cell cell) {
|
||||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If cell contains a formula, the formula is evaluated and returned,
|
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||||
* else the CellValue simply copies the appropriate cell value from
|
* cell remains as a formula cell. If the cell does not contain formula, rather than throwing an
|
||||||
* the cell and also its cell type. This method should be preferred over
|
* exception, this method returns {@link CellType#_NONE} and leaves the cell unchanged.
|
||||||
* evaluateInCell() when the call should not modify the contents of the
|
*
|
||||||
* original cell.
|
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||||
*
|
* cached formula result is also stored with the formula.
|
||||||
* @param cell may be <code>null</code> signifying that the cell is not present (or blank)
|
* <pre>
|
||||||
* @return <code>null</code> if the supplied cell is <code>null</code> or blank
|
* CellType evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||||
*/
|
* </pre>
|
||||||
@Override
|
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||||
public CellValue evaluate(Cell cell) {
|
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||||
if (cell == null) {
|
* @param cell The cell to evaluate
|
||||||
return null;
|
* @return {@link CellType#_NONE} for non-formula cells, or the type of the <em>formula result</em>
|
||||||
}
|
* @since POI 3.15 beta 3
|
||||||
|
* @deprecated POI 3.15 beta 3. Will be deleted when we make the CellType enum transition. See bug 59791.
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
@Override
|
||||||
|
public CellType evaluateFormulaCellEnum(Cell cell) {
|
||||||
|
if (cell == null || cell.getCellTypeEnum() != CellType.FORMULA) {
|
||||||
|
return CellType._NONE;
|
||||||
|
}
|
||||||
|
CellValue cv = evaluateFormulaCellValue(cell);
|
||||||
|
// cell remains a formula cell, but the cached value is changed
|
||||||
|
setCellValue(cell, cv);
|
||||||
|
return cv.getCellType();
|
||||||
|
}
|
||||||
|
|
||||||
switch (cell.getCellTypeEnum()) {
|
/**
|
||||||
case BOOLEAN:
|
* If cell contains formula, it evaluates the formula, and
|
||||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
* puts the formula result back into the cell, in place
|
||||||
case ERROR:
|
* of the old formula.
|
||||||
return CellValue.getError(cell.getErrorCellValue());
|
* Else if cell does not contain formula, this method leaves
|
||||||
case FORMULA:
|
* the cell unchanged.
|
||||||
return evaluateFormulaCellValue(cell);
|
* Note that the same instance of HSSFCell is returned to
|
||||||
case NUMERIC:
|
* allow chained calls like:
|
||||||
return new CellValue(cell.getNumericCellValue());
|
* <pre>
|
||||||
case STRING:
|
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
|
||||||
return new CellValue(cell.getRichStringCellValue().getString());
|
* </pre>
|
||||||
case BLANK:
|
* Be aware that your cell value will be changed to hold the
|
||||||
return null;
|
* result of the formula. If you simply want the formula
|
||||||
default:
|
* value computed for you, use {@link #evaluateFormulaCellEnum(Cell)}}
|
||||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
*/
|
||||||
}
|
@Override
|
||||||
|
public HSSFCell evaluateInCell(Cell cell) {
|
||||||
}
|
if (cell == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HSSFCell result = (HSSFCell) cell;
|
||||||
|
if (cell.getCellTypeEnum() == CellType.FORMULA) {
|
||||||
|
CellValue cv = evaluateFormulaCellValue(cell);
|
||||||
|
setCellValue(cell, cv);
|
||||||
|
setCellType(cell, cv); // cell will no longer be a formula cell
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setCellValue(Cell cell, CellValue cv) {
|
||||||
|
CellType cellType = cv.getCellType();
|
||||||
|
switch (cellType) {
|
||||||
|
case BOOLEAN:
|
||||||
|
cell.setCellValue(cv.getBooleanValue());
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
cell.setCellErrorValue(cv.getErrorValue());
|
||||||
|
break;
|
||||||
|
case NUMERIC:
|
||||||
|
cell.setCellValue(cv.getNumberValue());
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
cell.setCellValue(new HSSFRichTextString(cv.getStringValue()));
|
||||||
|
break;
|
||||||
|
case BLANK:
|
||||||
|
// never happens - blanks eventually get translated to zero
|
||||||
|
case FORMULA:
|
||||||
|
// this will never happen, we have already evaluated the formula
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
* Loops over all cells in all sheets of the supplied
|
||||||
* cell remains as a formula cell. If the cell does not contain formula, this method returns -1
|
* workbook.
|
||||||
* and leaves the cell unchanged.
|
* For cells that contain formulas, their formulas are
|
||||||
*
|
* evaluated, and the results are saved. These cells
|
||||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
* remain as formula cells.
|
||||||
* cached formula result is also stored with the formula.
|
* For cells that do not contain formulas, no changes
|
||||||
* <pre>
|
* are made.
|
||||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
* This is a helpful wrapper around looping over all
|
||||||
* </pre>
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
*/
|
||||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
|
||||||
* @param cell The cell to evaluate
|
evaluateAllFormulaCells(wb, new HSSFFormulaEvaluator(wb));
|
||||||
* @return -1 for non-formula cells, or the type of the <em>formula result</em>
|
}
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int evaluateFormulaCell(Cell cell) {
|
|
||||||
return evaluateFormulaCellEnum(cell).getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
|
||||||
* cell remains as a formula cell. If the cell does not contain formula, rather than throwing an
|
|
||||||
* exception, this method returns {@link CellType#_NONE} and leaves the cell unchanged.
|
|
||||||
*
|
|
||||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
|
||||||
* cached formula result is also stored with the formula.
|
|
||||||
* <pre>
|
|
||||||
* CellType evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
|
||||||
* </pre>
|
|
||||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
|
||||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
|
||||||
* @param cell The cell to evaluate
|
|
||||||
* @return {@link CellType#_NONE} for non-formula cells, or the type of the <em>formula result</em>
|
|
||||||
* @since POI 3.15 beta 3
|
|
||||||
* @deprecated POI 3.15 beta 3. Will be deleted when we make the CellType enum transition. See bug 59791.
|
|
||||||
*/
|
|
||||||
@Internal
|
|
||||||
@Override
|
|
||||||
public CellType evaluateFormulaCellEnum(Cell cell) {
|
|
||||||
if (cell == null || cell.getCellTypeEnum() != CellType.FORMULA) {
|
|
||||||
return CellType._NONE;
|
|
||||||
}
|
|
||||||
CellValue cv = evaluateFormulaCellValue(cell);
|
|
||||||
// cell remains a formula cell, but the cached value is changed
|
|
||||||
setCellValue(cell, cv);
|
|
||||||
return cv.getCellType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If cell contains formula, it evaluates the formula, and
|
* Loops over all cells in all sheets of the supplied
|
||||||
* puts the formula result back into the cell, in place
|
* workbook.
|
||||||
* of the old formula.
|
* For cells that contain formulas, their formulas are
|
||||||
* Else if cell does not contain formula, this method leaves
|
* evaluated, and the results are saved. These cells
|
||||||
* the cell unchanged.
|
* remain as formula cells.
|
||||||
* Note that the same instance of HSSFCell is returned to
|
* For cells that do not contain formulas, no changes
|
||||||
* allow chained calls like:
|
* are made.
|
||||||
* <pre>
|
* This is a helpful wrapper around looping over all
|
||||||
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
* </pre>
|
*/
|
||||||
* Be aware that your cell value will be changed to hold the
|
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||||
* result of the formula. If you simply want the formula
|
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
* value computed for you, use {@link #evaluateFormulaCellEnum(Cell)}}
|
}
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public HSSFCell evaluateInCell(Cell cell) {
|
|
||||||
if (cell == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
HSSFCell result = (HSSFCell) cell;
|
|
||||||
if (cell.getCellTypeEnum() == CellType.FORMULA) {
|
|
||||||
CellValue cv = evaluateFormulaCellValue(cell);
|
|
||||||
setCellValue(cell, cv);
|
|
||||||
setCellType(cell, cv); // cell will no longer be a formula cell
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
private static void setCellType(Cell cell, CellValue cv) {
|
|
||||||
CellType cellType = cv.getCellType();
|
|
||||||
switch (cellType) {
|
|
||||||
case BOOLEAN:
|
|
||||||
case ERROR:
|
|
||||||
case NUMERIC:
|
|
||||||
case STRING:
|
|
||||||
cell.setCellType(cellType);
|
|
||||||
return;
|
|
||||||
case BLANK:
|
|
||||||
// never happens - blanks eventually get translated to zero
|
|
||||||
case FORMULA:
|
|
||||||
// this will never happen, we have already evaluated the formula
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setCellValue(Cell cell, CellValue cv) {
|
/**
|
||||||
CellType cellType = cv.getCellType();
|
* Loops over all cells in all sheets of the supplied
|
||||||
switch (cellType) {
|
* workbook.
|
||||||
case BOOLEAN:
|
* For cells that contain formulas, their formulas are
|
||||||
cell.setCellValue(cv.getBooleanValue());
|
* evaluated, and the results are saved. These cells
|
||||||
break;
|
* remain as formula cells.
|
||||||
case ERROR:
|
* For cells that do not contain formulas, no changes
|
||||||
cell.setCellErrorValue(cv.getErrorValue());
|
* are made.
|
||||||
break;
|
* This is a helpful wrapper around looping over all
|
||||||
case NUMERIC:
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
cell.setCellValue(cv.getNumberValue());
|
*/
|
||||||
break;
|
@Override
|
||||||
case STRING:
|
public void evaluateAll() {
|
||||||
cell.setCellValue(new HSSFRichTextString(cv.getStringValue()));
|
evaluateAllFormulaCells(_book, this);
|
||||||
break;
|
}
|
||||||
case BLANK:
|
|
||||||
// never happens - blanks eventually get translated to zero
|
|
||||||
case FORMULA:
|
|
||||||
// this will never happen, we have already evaluated the formula
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loops over all cells in all sheets of the supplied
|
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||||
* workbook.
|
* @param cell
|
||||||
* For cells that contain formulas, their formulas are
|
*/
|
||||||
* evaluated, and the results are saved. These cells
|
protected CellValue evaluateFormulaCellValue(Cell cell) {
|
||||||
* remain as formula cells.
|
ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
|
||||||
* For cells that do not contain formulas, no changes
|
if (eval instanceof BoolEval) {
|
||||||
* are made.
|
BoolEval be = (BoolEval) eval;
|
||||||
* This is a helpful wrapper around looping over all
|
return CellValue.valueOf(be.getBooleanValue());
|
||||||
* cells, and calling evaluateFormulaCell on each one.
|
}
|
||||||
*/
|
if (eval instanceof NumericValueEval) {
|
||||||
public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
|
NumericValueEval ne = (NumericValueEval) eval;
|
||||||
evaluateAllFormulaCells(wb, new HSSFFormulaEvaluator(wb));
|
return new CellValue(ne.getNumberValue());
|
||||||
}
|
}
|
||||||
|
if (eval instanceof StringValueEval) {
|
||||||
/**
|
StringValueEval ne = (StringValueEval) eval;
|
||||||
* Loops over all cells in all sheets of the supplied
|
return new CellValue(ne.getStringValue());
|
||||||
* workbook.
|
}
|
||||||
* For cells that contain formulas, their formulas are
|
if (eval instanceof ErrorEval) {
|
||||||
* evaluated, and the results are saved. These cells
|
return CellValue.getError(((ErrorEval)eval).getErrorCode());
|
||||||
* remain as formula cells.
|
}
|
||||||
* For cells that do not contain formulas, no changes
|
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||||
* are made.
|
}
|
||||||
* This is a helpful wrapper around looping over all
|
|
||||||
* cells, and calling evaluateFormulaCell on each one.
|
|
||||||
*/
|
|
||||||
public static void evaluateAllFormulaCells(Workbook wb) {
|
|
||||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
|
||||||
evaluateAllFormulaCells(wb, evaluator);
|
|
||||||
}
|
|
||||||
private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
|
||||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
|
||||||
Sheet sheet = wb.getSheetAt(i);
|
|
||||||
|
|
||||||
for(Row r : sheet) {
|
|
||||||
for (Cell c : r) {
|
|
||||||
if (c.getCellTypeEnum() == CellType.FORMULA) {
|
|
||||||
evaluator.evaluateFormulaCellEnum(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loops over all cells in all sheets of the supplied
|
|
||||||
* workbook.
|
|
||||||
* For cells that contain formulas, their formulas are
|
|
||||||
* evaluated, and the results are saved. These cells
|
|
||||||
* remain as formula cells.
|
|
||||||
* For cells that do not contain formulas, no changes
|
|
||||||
* are made.
|
|
||||||
* This is a helpful wrapper around looping over all
|
|
||||||
* cells, and calling evaluateFormulaCell on each one.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void evaluateAll() {
|
|
||||||
evaluateAllFormulaCells(_book, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
|
||||||
* @param cell
|
|
||||||
*/
|
|
||||||
private CellValue evaluateFormulaCellValue(Cell cell) {
|
|
||||||
ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
|
|
||||||
if (eval instanceof BoolEval) {
|
|
||||||
BoolEval be = (BoolEval) eval;
|
|
||||||
return CellValue.valueOf(be.getBooleanValue());
|
|
||||||
}
|
|
||||||
if (eval instanceof NumericValueEval) {
|
|
||||||
NumericValueEval ne = (NumericValueEval) eval;
|
|
||||||
return new CellValue(ne.getNumberValue());
|
|
||||||
}
|
|
||||||
if (eval instanceof StringValueEval) {
|
|
||||||
StringValueEval ne = (StringValueEval) eval;
|
|
||||||
return new CellValue(ne.getStringValue());
|
|
||||||
}
|
|
||||||
if (eval instanceof ErrorEval) {
|
|
||||||
return CellValue.getError(((ErrorEval)eval).getErrorCode());
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,6 +92,7 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
|
|||||||
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
|
import org.apache.poi.ss.usermodel.Name;
|
||||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
@ -548,7 +549,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
* the 'active' sheet (which is the sheet with focus).
|
* the 'active' sheet (which is the sheet with focus).
|
||||||
* Unselects sheets that are not in <code>indexes</code>.
|
* Unselects sheets that are not in <code>indexes</code>.
|
||||||
*
|
*
|
||||||
* @param indexes
|
* @param indexes Array of sheets to select, the index is 0-based.
|
||||||
*/
|
*/
|
||||||
public void setSelectedTabs(int[] indexes) {
|
public void setSelectedTabs(int[] indexes) {
|
||||||
Collection<Integer> list = new ArrayList<Integer>(indexes.length);
|
Collection<Integer> list = new ArrayList<Integer>(indexes.length);
|
||||||
@ -563,7 +564,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
* the 'active' sheet (which is the sheet with focus).
|
* the 'active' sheet (which is the sheet with focus).
|
||||||
* Unselects sheets that are not in <code>indexes</code>.
|
* Unselects sheets that are not in <code>indexes</code>.
|
||||||
*
|
*
|
||||||
* @param indexes
|
* @param indexes Collection of sheets to select, the index is 0-based.
|
||||||
*/
|
*/
|
||||||
public void setSelectedTabs(Collection<Integer> indexes) {
|
public void setSelectedTabs(Collection<Integer> indexes) {
|
||||||
|
|
||||||
@ -893,8 +894,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Sheet> sheetIterator() {
|
public Iterator<Sheet> sheetIterator() {
|
||||||
Iterator<Sheet> result = new SheetIterator<Sheet>();
|
return new SheetIterator<Sheet>();
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1280,9 +1280,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the underlying {@link NPOIFSFileSystem} from which
|
* Closes the underlying {@link NPOIFSFileSystem} from which
|
||||||
* the Workbook was read, if any. Has no effect on Workbooks
|
* the Workbook was read, if any.
|
||||||
* opened from an InputStream, or newly created ones.
|
*
|
||||||
* <p>Once {@link #close()} has been called, no further
|
* <p>Once this has been called, no further
|
||||||
* operations, updates or reads should be performed on the
|
* operations, updates or reads should be performed on the
|
||||||
* Workbook.
|
* Workbook.
|
||||||
*/
|
*/
|
||||||
@ -1531,6 +1531,11 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
return names.get(nameIndex);
|
return names.get(nameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HSSFName> getAllNames() {
|
||||||
|
return Collections.unmodifiableList(names);
|
||||||
|
}
|
||||||
|
|
||||||
public NameRecord getNameRecord(int nameIndex) {
|
public NameRecord getNameRecord(int nameIndex) {
|
||||||
return getWorkbook().getNameRecord(nameIndex);
|
return getWorkbook().getNameRecord(nameIndex);
|
||||||
}
|
}
|
||||||
@ -1702,8 +1707,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
*
|
*
|
||||||
* @param name the name to remove.
|
* @param name the name to remove.
|
||||||
*/
|
*/
|
||||||
void removeName(HSSFName name) {
|
@Override
|
||||||
int index = getNameIndex(name);
|
public void removeName(Name name) {
|
||||||
|
int index = getNameIndex((HSSFName) name);
|
||||||
removeName(index);
|
removeName(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,20 +374,22 @@ public class CryptoFunctions {
|
|||||||
// SET Verifier TO 0x0000
|
// SET Verifier TO 0x0000
|
||||||
short verifier = 0;
|
short verifier = 0;
|
||||||
|
|
||||||
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
|
if (!"".equals(password)) {
|
||||||
for (int i = arrByteChars.length-1; i >= 0; i--) {
|
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
|
||||||
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
|
for (int i = arrByteChars.length-1; i >= 0; i--) {
|
||||||
|
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
|
||||||
|
verifier = rotateLeftBase15Bit(verifier);
|
||||||
|
verifier ^= arrByteChars[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// as we haven't prepended the password length into the input array
|
||||||
|
// we need to do it now separately ...
|
||||||
verifier = rotateLeftBase15Bit(verifier);
|
verifier = rotateLeftBase15Bit(verifier);
|
||||||
verifier ^= arrByteChars[i];
|
verifier ^= arrByteChars.length;
|
||||||
|
|
||||||
|
// RETURN Verifier BITWISE XOR 0xCE4B
|
||||||
|
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
|
||||||
}
|
}
|
||||||
|
|
||||||
// as we haven't prepended the password length into the input array
|
|
||||||
// we need to do it now separately ...
|
|
||||||
verifier = rotateLeftBase15Bit(verifier);
|
|
||||||
verifier ^= arrByteChars.length;
|
|
||||||
|
|
||||||
// RETURN Verifier BITWISE XOR 0xCE4B
|
|
||||||
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
|
|
||||||
|
|
||||||
return verifier & 0xFFFF;
|
return verifier & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
194
src/java/org/apache/poi/ss/formula/BaseFormulaEvaluator.java
Normal file
194
src/java/org/apache/poi/ss/formula/BaseFormulaEvaluator.java
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.ss.formula;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common functionality across file formats for evaluating formula cells.<p/>
|
||||||
|
*/
|
||||||
|
public abstract class BaseFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
||||||
|
protected final WorkbookEvaluator _bookEvaluator;
|
||||||
|
|
||||||
|
protected BaseFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
||||||
|
this._bookEvaluator = bookEvaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates several formula evaluators together so that formulas that involve external
|
||||||
|
* references can be evaluated.
|
||||||
|
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
||||||
|
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
||||||
|
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
||||||
|
*/
|
||||||
|
public static void setupEnvironment(String[] workbookNames, BaseFormulaEvaluator[] evaluators) {
|
||||||
|
WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];
|
||||||
|
for (int i = 0; i < wbEvals.length; i++) {
|
||||||
|
wbEvals[i] = evaluators[i]._bookEvaluator;
|
||||||
|
}
|
||||||
|
CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
||||||
|
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorkbookEvaluator _getWorkbookEvaluator() {
|
||||||
|
return _bookEvaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
||||||
|
* in the evaluated workbook. If performance is not critical, a single call to this method
|
||||||
|
* may be used instead of many specific calls to the notify~ methods.
|
||||||
|
*
|
||||||
|
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||||
|
* of the evaluate~ methods of this class
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clearAllCachedResultValues() {
|
||||||
|
_bookEvaluator.clearAllCachedResultValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If cell contains a formula, the formula is evaluated and returned,
|
||||||
|
* else the CellValue simply copies the appropriate cell value from
|
||||||
|
* the cell and also its cell type. This method should be preferred over
|
||||||
|
* evaluateInCell() when the call should not modify the contents of the
|
||||||
|
* original cell.
|
||||||
|
*
|
||||||
|
* @param cell may be <code>null</code> signifying that the cell is not present (or blank)
|
||||||
|
* @return <code>null</code> if the supplied cell is <code>null</code> or blank
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CellValue evaluate(Cell cell) {
|
||||||
|
if (cell == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cell.getCellTypeEnum()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return CellValue.valueOf(cell.getBooleanCellValue());
|
||||||
|
case ERROR:
|
||||||
|
return CellValue.getError(cell.getErrorCellValue());
|
||||||
|
case FORMULA:
|
||||||
|
return evaluateFormulaCellValue(cell);
|
||||||
|
case NUMERIC:
|
||||||
|
return new CellValue(cell.getNumericCellValue());
|
||||||
|
case STRING:
|
||||||
|
return new CellValue(cell.getRichStringCellValue().getString());
|
||||||
|
case BLANK:
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract CellValue evaluateFormulaCellValue(Cell cell);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||||
|
* cell remains as a formula cell. If the cell does not contain formula, this method returns -1
|
||||||
|
* and leaves the cell unchanged.
|
||||||
|
*
|
||||||
|
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||||
|
* cached formula result is also stored with the formula.
|
||||||
|
* <pre>
|
||||||
|
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||||
|
* </pre>
|
||||||
|
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||||
|
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||||
|
* @param cell The cell to evaluate
|
||||||
|
* @return -1 for non-formula cells, or the type of the <em>formula result</em>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int evaluateFormulaCell(Cell cell) {
|
||||||
|
return evaluateFormulaCellEnum(cell).getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void setCellType(Cell cell, CellValue cv) {
|
||||||
|
CellType cellType = cv.getCellType();
|
||||||
|
switch (cellType) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case ERROR:
|
||||||
|
case NUMERIC:
|
||||||
|
case STRING:
|
||||||
|
cell.setCellType(cellType);
|
||||||
|
return;
|
||||||
|
case BLANK:
|
||||||
|
// never happens - blanks eventually get translated to zero
|
||||||
|
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
||||||
|
case FORMULA:
|
||||||
|
// this will never happen, we have already evaluated the formula
|
||||||
|
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops over all cells in all sheets of the supplied
|
||||||
|
* workbook.
|
||||||
|
* For cells that contain formulas, their formulas are
|
||||||
|
* evaluated, and the results are saved. These cells
|
||||||
|
* remain as formula cells.
|
||||||
|
* For cells that do not contain formulas, no changes
|
||||||
|
* are made.
|
||||||
|
* This is a helpful wrapper around looping over all
|
||||||
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
|
*/
|
||||||
|
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||||
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
|
evaluateAllFormulaCells(wb, evaluator);
|
||||||
|
}
|
||||||
|
protected static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
||||||
|
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
||||||
|
Sheet sheet = wb.getSheetAt(i);
|
||||||
|
|
||||||
|
for(Row r : sheet) {
|
||||||
|
for (Cell c : r) {
|
||||||
|
if (c.getCellTypeEnum() == CellType.FORMULA) {
|
||||||
|
evaluator.evaluateFormulaCellEnum(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void setIgnoreMissingWorkbooks(boolean ignore){
|
||||||
|
_bookEvaluator.setIgnoreMissingWorkbooks(ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void setDebugEvaluationOutputForNextEval(boolean value){
|
||||||
|
_bookEvaluator.setDebugEvaluationOutputForNextEval(value);
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ import org.apache.poi.ss.util.CellReference;
|
|||||||
/**
|
/**
|
||||||
* Provides Lazy Evaluation to a 3D Reference
|
* Provides Lazy Evaluation to a 3D Reference
|
||||||
*/
|
*/
|
||||||
final class LazyRefEval extends RefEvalBase {
|
public final class LazyRefEval extends RefEvalBase {
|
||||||
private final SheetRangeEvaluator _evaluator;
|
private final SheetRangeEvaluator _evaluator;
|
||||||
|
|
||||||
public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) {
|
public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) {
|
||||||
@ -47,14 +47,17 @@ final class LazyRefEval extends RefEvalBase {
|
|||||||
return new LazyAreaEval(area, _evaluator);
|
return new LazyAreaEval(area, _evaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSubTotal() {
|
||||||
|
SheetRefEvaluator sheetEvaluator = _evaluator.getSheetEvaluator(getFirstSheetIndex());
|
||||||
|
return sheetEvaluator.isSubTotal(getRow(), getColumn());
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
CellReference cr = new CellReference(getRow(), getColumn());
|
CellReference cr = new CellReference(getRow(), getColumn());
|
||||||
StringBuffer sb = new StringBuffer();
|
return getClass().getName() + "[" +
|
||||||
sb.append(getClass().getName()).append("[");
|
_evaluator.getSheetNameRange() +
|
||||||
sb.append(_evaluator.getSheetNameRange());
|
'!' +
|
||||||
sb.append('!');
|
cr.formatAsString() +
|
||||||
sb.append(cr.formatAsString());
|
"]";
|
||||||
sb.append("]");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package org.apache.poi.ss.formula.functions;
|
|||||||
|
|
||||||
import static org.apache.poi.ss.formula.functions.AggregateFunction.subtotalInstance;
|
import static org.apache.poi.ss.formula.functions.AggregateFunction.subtotalInstance;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.LazyRefEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.formula.eval.EvaluationException;
|
import org.apache.poi.ss.formula.eval.EvaluationException;
|
||||||
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
||||||
@ -26,6 +27,11 @@ import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
|
|||||||
import org.apache.poi.ss.formula.eval.OperandResolver;
|
import org.apache.poi.ss.formula.eval.OperandResolver;
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation for the Excel function SUBTOTAL<p>
|
* Implementation for the Excel function SUBTOTAL<p>
|
||||||
*
|
*
|
||||||
@ -61,7 +67,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
|||||||
public class Subtotal implements Function {
|
public class Subtotal implements Function {
|
||||||
|
|
||||||
private static Function findFunction(int functionCode) throws EvaluationException {
|
private static Function findFunction(int functionCode) throws EvaluationException {
|
||||||
Function func;
|
|
||||||
switch (functionCode) {
|
switch (functionCode) {
|
||||||
case 1: return subtotalInstance(AggregateFunction.AVERAGE);
|
case 1: return subtotalInstance(AggregateFunction.AVERAGE);
|
||||||
case 2: return Count.subtotalInstance();
|
case 2: return Count.subtotalInstance();
|
||||||
@ -87,7 +92,7 @@ public class Subtotal implements Function {
|
|||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function innerFunc;
|
final Function innerFunc;
|
||||||
try {
|
try {
|
||||||
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
|
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
|
||||||
int functionCode = OperandResolver.coerceValueToInt(ve);
|
int functionCode = OperandResolver.coerceValueToInt(ve);
|
||||||
@ -96,9 +101,24 @@ public class Subtotal implements Function {
|
|||||||
return e.getErrorEval();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueEval[] innerArgs = new ValueEval[nInnerArgs];
|
// ignore the first arg, this is the function-type, we check for the length above
|
||||||
System.arraycopy(args, 1, innerArgs, 0, nInnerArgs);
|
final List<ValueEval> list = new ArrayList<ValueEval>(Arrays.asList(args).subList(1, args.length));
|
||||||
|
|
||||||
return innerFunc.evaluate(innerArgs, srcRowIndex, srcColumnIndex);
|
Iterator<ValueEval> it = list.iterator();
|
||||||
|
|
||||||
|
// See https://support.office.com/en-us/article/SUBTOTAL-function-7b027003-f060-4ade-9040-e478765b9939
|
||||||
|
// "If there are other subtotals within ref1, ref2,... (or nested subtotals), these nested subtotals are ignored to avoid double counting."
|
||||||
|
// For array references it is handled in other evaluation steps, but we need to handle this here for references to subtotal-functions
|
||||||
|
while(it.hasNext()) {
|
||||||
|
ValueEval eval = it.next();
|
||||||
|
if(eval instanceof LazyRefEval) {
|
||||||
|
LazyRefEval lazyRefEval = (LazyRefEval) eval;
|
||||||
|
if(lazyRefEval.isSubTotal()) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return innerFunc.evaluate(list.toArray(new ValueEval[list.size()]), srcRowIndex, srcColumnIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ public interface CellStyle {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* vertically justified vertical alignment
|
* vertically justified vertical alignment
|
||||||
* @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#TOP} instead.
|
* @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#JUSTIFY} instead.
|
||||||
*/
|
*/
|
||||||
static final short VERTICAL_JUSTIFY = 0x3; //VerticalAlignment.JUSTIFY.getCode();
|
static final short VERTICAL_JUSTIFY = 0x3; //VerticalAlignment.JUSTIFY.getCode();
|
||||||
|
|
||||||
|
@ -341,9 +341,11 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the underlying input resource (File or Stream),
|
* Close the underlying input resource (File or Stream),
|
||||||
* from which the Workbook was read. After closing, the
|
* from which the Workbook was read.
|
||||||
* Workbook should no longer be used.
|
*
|
||||||
* <p>This will have no effect newly created Workbooks.
|
* <p>Once this has been called, no further
|
||||||
|
* operations, updates or reads should be performed on the
|
||||||
|
* Workbook.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void close() throws IOException;
|
void close() throws IOException;
|
||||||
@ -367,6 +369,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||||||
*/
|
*/
|
||||||
List<? extends Name> getNames(String name);
|
List<? extends Name> getNames(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all defined names.
|
||||||
|
*
|
||||||
|
* @return a list of the defined names. An empty list is returned if none is found.
|
||||||
|
*/
|
||||||
|
List<? extends Name> getAllNames();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nameIndex position of the named range (0-based)
|
* @param nameIndex position of the named range (0-based)
|
||||||
* @return the defined name at the specified index
|
* @return the defined name at the specified index
|
||||||
@ -405,6 +414,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||||||
*/
|
*/
|
||||||
void removeName(String name);
|
void removeName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a defined name
|
||||||
|
*
|
||||||
|
* @param name the name of the defined name
|
||||||
|
*/
|
||||||
|
void removeName(Name name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the linking required to allow formulas referencing
|
* Adds the linking required to allow formulas referencing
|
||||||
* the specified external workbook to be added to this one.
|
* the specified external workbook to be added to this one.
|
||||||
|
@ -27,19 +27,13 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
* developers to write log calls, while simultaneously making those
|
* developers to write log calls, while simultaneously making those
|
||||||
* calls as cheap as possible by performing lazy evaluation of the log
|
* calls as cheap as possible by performing lazy evaluation of the log
|
||||||
* message.<p>
|
* message.<p>
|
||||||
*
|
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
|
||||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CommonsLogger extends POILogger
|
public class CommonsLogger extends POILogger
|
||||||
{
|
{
|
||||||
|
|
||||||
private static LogFactory _creator = LogFactory.getFactory();
|
private static LogFactory _creator = LogFactory.getFactory();
|
||||||
private Log log = null;
|
private Log log = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initialize(final String cat)
|
public void initialize(final String cat)
|
||||||
{
|
{
|
||||||
this.log = _creator.getInstance(cat);
|
this.log = _creator.getInstance(cat);
|
||||||
@ -51,6 +45,7 @@ public class CommonsLogger extends POILogger
|
|||||||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||||
* @param obj1 The object to log.
|
* @param obj1 The object to log.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void log(final int level, final Object obj1)
|
public void log(final int level, final Object obj1)
|
||||||
{
|
{
|
||||||
if(level==FATAL)
|
if(level==FATAL)
|
||||||
@ -104,6 +99,7 @@ public class CommonsLogger extends POILogger
|
|||||||
* @param obj1 The object to log. This is converted to a string.
|
* @param obj1 The object to log. This is converted to a string.
|
||||||
* @param exception An exception to be logged
|
* @param exception An exception to be logged
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void log(final int level, final Object obj1,
|
public void log(final int level, final Object obj1,
|
||||||
final Throwable exception)
|
final Throwable exception)
|
||||||
{
|
{
|
||||||
@ -175,7 +171,7 @@ public class CommonsLogger extends POILogger
|
|||||||
*
|
*
|
||||||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean check(final int level)
|
public boolean check(final int level)
|
||||||
{
|
{
|
||||||
if(level==FATAL)
|
if(level==FATAL)
|
||||||
|
@ -22,14 +22,10 @@ package org.apache.poi.util;
|
|||||||
* developers to write log calls, while simultaneously making those
|
* developers to write log calls, while simultaneously making those
|
||||||
* calls as cheap as possible by performing lazy evaluation of the log
|
* calls as cheap as possible by performing lazy evaluation of the log
|
||||||
* message.<p>
|
* message.<p>
|
||||||
*
|
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
|
||||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
|
||||||
*/
|
*/
|
||||||
public class NullLogger extends POILogger {
|
public class NullLogger extends POILogger {
|
||||||
@Override
|
@Override
|
||||||
public void initialize(final String cat){
|
public void initialize(final String cat) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +37,7 @@ public class NullLogger extends POILogger {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int level, final Object obj1)
|
public void log(final int level, final Object obj1) {
|
||||||
{
|
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +48,7 @@ public class NullLogger extends POILogger {
|
|||||||
* @param obj1 The object to log. This is converted to a string.
|
* @param obj1 The object to log. This is converted to a string.
|
||||||
* @param exception An exception to be logged
|
* @param exception An exception to be logged
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void log(int level, Object obj1, final Throwable exception) {
|
public void log(int level, Object obj1, final Throwable exception) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,12 @@ package org.apache.poi.util;
|
|||||||
* developers to write log calls, while simultaneously making those
|
* developers to write log calls, while simultaneously making those
|
||||||
* calls as cheap as possible by performing lazy evaluation of the log
|
* calls as cheap as possible by performing lazy evaluation of the log
|
||||||
* message.
|
* message.
|
||||||
*
|
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
|
||||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
|
||||||
*/
|
*/
|
||||||
public class SystemOutLogger extends POILogger
|
public class SystemOutLogger extends POILogger
|
||||||
{
|
{
|
||||||
private String _cat;
|
private String _cat;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initialize(final String cat)
|
public void initialize(final String cat)
|
||||||
{
|
{
|
||||||
this._cat=cat;
|
this._cat=cat;
|
||||||
@ -44,7 +41,7 @@ public class SystemOutLogger extends POILogger
|
|||||||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||||
* @param obj1 The object to log.
|
* @param obj1 The object to log.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void log(final int level, final Object obj1)
|
public void log(final int level, final Object obj1)
|
||||||
{
|
{
|
||||||
log(level, obj1, null);
|
log(level, obj1, null);
|
||||||
@ -57,6 +54,7 @@ public class SystemOutLogger extends POILogger
|
|||||||
* @param obj1 The object to log. This is converted to a string.
|
* @param obj1 The object to log. This is converted to a string.
|
||||||
* @param exception An exception to be logged
|
* @param exception An exception to be logged
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@SuppressForbidden("uses printStackTrace")
|
@SuppressForbidden("uses printStackTrace")
|
||||||
public void log(final int level, final Object obj1,
|
public void log(final int level, final Object obj1,
|
||||||
final Throwable exception) {
|
final Throwable exception) {
|
||||||
@ -78,6 +76,7 @@ public class SystemOutLogger extends POILogger
|
|||||||
* @see #ERROR
|
* @see #ERROR
|
||||||
* @see #FATAL
|
* @see #FATAL
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean check(final int level)
|
public boolean check(final int level)
|
||||||
{
|
{
|
||||||
int currentLevel;
|
int currentLevel;
|
||||||
|
@ -193,8 +193,12 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart implements Close
|
|||||||
/**
|
/**
|
||||||
* Closes the underlying {@link OPCPackage} from which this
|
* Closes the underlying {@link OPCPackage} from which this
|
||||||
* document was read, if there is one
|
* document was read, if there is one
|
||||||
*
|
*
|
||||||
* @throws IOException for writable packages, if an IO exception occur during the saving process.
|
* <p>Once this has been called, no further
|
||||||
|
* operations, updates or reads should be performed on the
|
||||||
|
* document.
|
||||||
|
*
|
||||||
|
* @throws IOException for writable packages, if an IO exception occur during the saving process.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
@ -382,8 +382,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new package
|
// Creates a new package
|
||||||
OPCPackage pkg = null;
|
OPCPackage pkg = new ZipPackage();
|
||||||
pkg = new ZipPackage();
|
|
||||||
pkg.originalPackagePath = file.getAbsolutePath();
|
pkg.originalPackagePath = file.getAbsolutePath();
|
||||||
|
|
||||||
configurePackage(pkg);
|
configurePackage(pkg);
|
||||||
@ -391,8 +390,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static OPCPackage create(OutputStream output) {
|
public static OPCPackage create(OutputStream output) {
|
||||||
OPCPackage pkg = null;
|
OPCPackage pkg = new ZipPackage();
|
||||||
pkg = new ZipPackage();
|
|
||||||
pkg.originalPackagePath = null;
|
pkg.originalPackagePath = null;
|
||||||
pkg.output = output;
|
pkg.output = output;
|
||||||
|
|
||||||
@ -542,7 +540,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||||||
// Create the thumbnail part name
|
// Create the thumbnail part name
|
||||||
String contentType = ContentTypes
|
String contentType = ContentTypes
|
||||||
.getContentTypeFromFileExtension(filename);
|
.getContentTypeFromFileExtension(filename);
|
||||||
PackagePartName thumbnailPartName = null;
|
PackagePartName thumbnailPartName;
|
||||||
try {
|
try {
|
||||||
thumbnailPartName = PackagingURIHelper.createPartName("/docProps/"
|
thumbnailPartName = PackagingURIHelper.createPartName("/docProps/"
|
||||||
+ filename);
|
+ filename);
|
||||||
|
@ -29,10 +29,7 @@ import java.util.TreeMap;
|
|||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
import org.apache.poi.openxml4j.opc.*;
|
||||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
|
||||||
import org.apache.poi.openxml4j.opc.PackagePartName;
|
|
||||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
|
||||||
import org.apache.poi.util.DocumentHelper;
|
import org.apache.poi.util.DocumentHelper;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@ -54,7 +51,7 @@ public abstract class ContentTypeManager {
|
|||||||
/**
|
/**
|
||||||
* Content type namespace
|
* Content type namespace
|
||||||
*/
|
*/
|
||||||
public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
|
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
|
||||||
|
|
||||||
/* Xml elements in content type part */
|
/* Xml elements in content type part */
|
||||||
|
|
||||||
|
@ -304,13 +304,13 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
|
|||||||
@Override
|
@Override
|
||||||
public boolean getFlipHorizontal(){
|
public boolean getFlipHorizontal(){
|
||||||
CTGroupTransform2D xfrm = getXfrm();
|
CTGroupTransform2D xfrm = getXfrm();
|
||||||
return (xfrm == null || !xfrm.isSetFlipH()) ? false : xfrm.getFlipH();
|
return !(xfrm == null || !xfrm.isSetFlipH()) && xfrm.getFlipH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getFlipVertical(){
|
public boolean getFlipVertical(){
|
||||||
CTGroupTransform2D xfrm = getXfrm();
|
CTGroupTransform2D xfrm = getXfrm();
|
||||||
return (xfrm == null || !xfrm.isSetFlipV()) ? false : xfrm.getFlipV();
|
return !(xfrm == null || !xfrm.isSetFlipV()) && xfrm.getFlipV();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -333,7 +333,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
|
|||||||
|
|
||||||
// recursively update each shape
|
// recursively update each shape
|
||||||
for(XSLFShape shape : gr.getShapes()) {
|
for(XSLFShape shape : gr.getShapes()) {
|
||||||
XSLFShape newShape = null;
|
XSLFShape newShape;
|
||||||
if (shape instanceof XSLFTextBox) {
|
if (shape instanceof XSLFTextBox) {
|
||||||
newShape = createTextBox();
|
newShape = createTextBox();
|
||||||
} else if (shape instanceof XSLFAutoShape) {
|
} else if (shape instanceof XSLFAutoShape) {
|
||||||
|
@ -41,7 +41,6 @@ import javax.xml.validation.Schema;
|
|||||||
import javax.xml.validation.SchemaFactory;
|
import javax.xml.validation.SchemaFactory;
|
||||||
import javax.xml.validation.Validator;
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
import org.apache.poi.ss.usermodel.DateUtil;
|
||||||
import org.apache.poi.util.DocumentHelper;
|
import org.apache.poi.util.DocumentHelper;
|
||||||
@ -55,7 +54,6 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|||||||
import org.apache.poi.xssf.usermodel.XSSFTable;
|
import org.apache.poi.xssf.usermodel.XSSFTable;
|
||||||
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
|
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
|
||||||
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
|
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType;
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NamedNodeMap;
|
import org.w3c.dom.NamedNodeMap;
|
||||||
@ -117,8 +115,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
* @param validate if true, validates the XML againts the XML Schema
|
* @param validate if true, validates the XML againts the XML Schema
|
||||||
* @throws SAXException
|
* @throws SAXException
|
||||||
* @throws ParserConfigurationException
|
* @throws ParserConfigurationException
|
||||||
* @throws TransformerException
|
* @throws TransformerException
|
||||||
* @throws InvalidFormatException
|
|
||||||
*/
|
*/
|
||||||
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
|
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
|
||||||
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
|
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
|
||||||
@ -128,10 +125,10 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
|
|
||||||
Document doc = DocumentHelper.createDocument();
|
Document doc = DocumentHelper.createDocument();
|
||||||
|
|
||||||
Element root = null;
|
final Element root;
|
||||||
|
|
||||||
if (isNamespaceDeclared()) {
|
if (isNamespaceDeclared()) {
|
||||||
root=doc.createElementNS(getNamespace(),rootElement);
|
root = doc.createElementNS(getNamespace(),rootElement);
|
||||||
} else {
|
} else {
|
||||||
root = doc.createElementNS("", rootElement);
|
root = doc.createElementNS("", rootElement);
|
||||||
}
|
}
|
||||||
@ -152,7 +149,6 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
tableMappings.put(commonXPath, table);
|
tableMappings.put(commonXPath, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Collections.sort(xpaths,this);
|
Collections.sort(xpaths,this);
|
||||||
|
|
||||||
for(String xpath : xpaths) {
|
for(String xpath : xpaths) {
|
||||||
@ -167,8 +163,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
XSSFCell cell = simpleXmlCell.getReferencedCell();
|
XSSFCell cell = simpleXmlCell.getReferencedCell();
|
||||||
if (cell!=null) {
|
if (cell!=null) {
|
||||||
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
|
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
|
||||||
STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType();
|
mapCellOnNode(cell,currentNode);
|
||||||
mapCellOnNode(cell,currentNode,dataType);
|
|
||||||
|
|
||||||
//remove nodes which are empty in order to keep the output xml valid
|
//remove nodes which are empty in order to keep the output xml valid
|
||||||
if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) {
|
if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) {
|
||||||
@ -202,22 +197,15 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex);
|
XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex);
|
||||||
String localXPath = pointer.getLocalXPath();
|
String localXPath = pointer.getLocalXPath();
|
||||||
Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
|
Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
|
||||||
STXmlDataType.Enum dataType = pointer.getXmlDataType();
|
|
||||||
|
|
||||||
|
mapCellOnNode(cell,currentNode);
|
||||||
mapCellOnNode(cell,currentNode,dataType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} /*else {
|
||||||
// TODO: implement filtering management in xpath
|
// TODO: implement filtering management in xpath
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isValid = true;
|
boolean isValid = true;
|
||||||
@ -225,8 +213,6 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
isValid =isValid(doc);
|
isValid =isValid(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
@ -275,7 +261,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) {
|
private void mapCellOnNode(XSSFCell cell, Node node) {
|
||||||
|
|
||||||
String value ="";
|
String value ="";
|
||||||
switch (cell.getCellTypeEnum()) {
|
switch (cell.getCellTypeEnum()) {
|
||||||
@ -349,11 +335,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
}
|
}
|
||||||
currentNode = selectedNode;
|
currentNode = selectedNode;
|
||||||
} else {
|
} else {
|
||||||
|
currentNode = createAttribute(doc, currentNode, axisName);
|
||||||
|
|
||||||
Node attribute = createAttribute(doc, currentNode, axisName);
|
|
||||||
|
|
||||||
currentNode = attribute;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentNode;
|
return currentNode;
|
||||||
@ -421,12 +403,11 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
|
|
||||||
for(int i =1;i <minLenght; i++) {
|
for(int i =1;i <minLenght; i++) {
|
||||||
|
|
||||||
String leftElementName =leftTokens[i];
|
String leftElementName = leftTokens[i];
|
||||||
String rightElementName = rightTokens[i];
|
String rightElementName = rightTokens[i];
|
||||||
|
|
||||||
if (leftElementName.equals(rightElementName)) {
|
if (leftElementName.equals(rightElementName)) {
|
||||||
Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode);
|
localComplexTypeRootNode = getComplexTypeForElement(leftElementName, xmlSchema, localComplexTypeRootNode);
|
||||||
localComplexTypeRootNode = complexType;
|
|
||||||
} else {
|
} else {
|
||||||
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode);
|
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode);
|
||||||
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
|
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
|
||||||
@ -436,9 +417,9 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
}if ( leftIndex > rightIndex) {
|
}if ( leftIndex > rightIndex) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} /*else {
|
||||||
// NOTE: the xpath doesn't match correctly in the schema
|
// NOTE: the xpath doesn't match correctly in the schema
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +464,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||||||
// Note: we expect that all the complex types are defined at root level
|
// Note: we expect that all the complex types are defined at root level
|
||||||
Node complexTypeNode = null;
|
Node complexTypeNode = null;
|
||||||
if (!"".equals(complexTypeName)) {
|
if (!"".equals(complexTypeName)) {
|
||||||
complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, complexTypeNode, complexTypeName);
|
complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, null, complexTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return complexTypeNode;
|
return complexTypeNode;
|
||||||
|
@ -338,7 +338,11 @@ public class SXSSFCell implements Cell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(_value.getType()==CellType.FORMULA)
|
if(_value.getType()==CellType.FORMULA)
|
||||||
((StringFormulaValue)_value).setPreEvaluatedValue(value);
|
if(_value instanceof NumericFormulaValue) {
|
||||||
|
((NumericFormulaValue) _value).setPreEvaluatedValue(Double.parseDouble(value));
|
||||||
|
} else {
|
||||||
|
((StringFormulaValue) _value).setPreEvaluatedValue(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
((PlainStringValue)_value).setValue(value);
|
((PlainStringValue)_value).setValue(value);
|
||||||
} else {
|
} else {
|
||||||
@ -956,6 +960,7 @@ public class SXSSFCell implements Cell {
|
|||||||
}
|
}
|
||||||
/*package*/ void setFormulaType(CellType type)
|
/*package*/ void setFormulaType(CellType type)
|
||||||
{
|
{
|
||||||
|
Value prevValue = _value;
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case NUMERIC:
|
case NUMERIC:
|
||||||
@ -983,7 +988,13 @@ public class SXSSFCell implements Cell {
|
|||||||
throw new IllegalArgumentException("Illegal type " + type);
|
throw new IllegalArgumentException("Illegal type " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we had a Formula before, we should copy over the _value of the formula
|
||||||
|
if(prevValue instanceof FormulaValue) {
|
||||||
|
((FormulaValue)_value)._value = ((FormulaValue)prevValue)._value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: implement this correctly
|
//TODO: implement this correctly
|
||||||
@NotImplemented
|
@NotImplemented
|
||||||
/*package*/ CellType computeTypeFromFormula(String formula)
|
/*package*/ CellType computeTypeFromFormula(String formula)
|
||||||
|
@ -893,8 +893,11 @@ public class SXSSFWorkbook implements Workbook {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
|
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
|
||||||
* on which this Workbook is based, if any. Has no effect on Workbooks
|
* on which this Workbook is based, if any.
|
||||||
* created from scratch.
|
*
|
||||||
|
* <p>Once this has been called, no further
|
||||||
|
* operations, updates or reads should be performed on the
|
||||||
|
* Workbook.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
@ -1003,12 +1006,25 @@ public class SXSSFWorkbook implements Workbook {
|
|||||||
return _wb.getNames(name);
|
return _wb.getNames(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all defined names
|
||||||
|
*
|
||||||
|
* @return all defined names
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<? extends Name> getAllNames()
|
||||||
|
{
|
||||||
|
return _wb.getAllNames();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nameIndex position of the named range (0-based)
|
* @param nameIndex position of the named range (0-based)
|
||||||
* @return the defined name at the specified index
|
* @return the defined name at the specified index
|
||||||
* @throws IllegalArgumentException if the supplied index is invalid
|
* @throws IllegalArgumentException if the supplied index is invalid
|
||||||
|
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public Name getNameAt(int nameIndex)
|
public Name getNameAt(int nameIndex)
|
||||||
{
|
{
|
||||||
return _wb.getNameAt(nameIndex);
|
return _wb.getNameAt(nameIndex);
|
||||||
@ -1033,8 +1049,12 @@ public class SXSSFWorkbook implements Workbook {
|
|||||||
*
|
*
|
||||||
* @param name the name of the defined name
|
* @param name the name of the defined name
|
||||||
* @return zero based index of the defined name. <code>-1</code> if not found.
|
* @return zero based index of the defined name. <code>-1</code> if not found.
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||||
|
* Use {@link #getName(String)} instead.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public int getNameIndex(String name)
|
public int getNameIndex(String name)
|
||||||
{
|
{
|
||||||
return _wb.getNameIndex(name);
|
return _wb.getNameIndex(name);
|
||||||
@ -1044,8 +1064,11 @@ public class SXSSFWorkbook implements Workbook {
|
|||||||
* Remove the defined name at the specified index
|
* Remove the defined name at the specified index
|
||||||
*
|
*
|
||||||
* @param index named range index (0 based)
|
* @param index named range index (0 based)
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void removeName(int index)
|
public void removeName(int index)
|
||||||
{
|
{
|
||||||
_wb.removeName(index);
|
_wb.removeName(index);
|
||||||
@ -1054,10 +1077,24 @@ public class SXSSFWorkbook implements Workbook {
|
|||||||
/**
|
/**
|
||||||
* Remove a defined name by name
|
* Remove a defined name by name
|
||||||
*
|
*
|
||||||
* @param name the name of the defined name
|
* @param name the name of the defined name
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void removeName(String name)
|
public void removeName(String name)
|
||||||
|
{
|
||||||
|
_wb.removeName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given defined name
|
||||||
|
*
|
||||||
|
* @param name the name to remove
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void removeName(Name name)
|
||||||
{
|
{
|
||||||
_wb.removeName(name);
|
_wb.removeName(name);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
|
|
||||||
// Otherwise, try it as a named range
|
// Otherwise, try it as a named range
|
||||||
if (sheet == null) {
|
if (sheet == null) {
|
||||||
if (_uBook.getNameIndex(name) > -1) {
|
if (!_uBook.getNames(name).isEmpty()) {
|
||||||
return new NameXPxg(null, name);
|
return new NameXPxg(null, name);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -17,12 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import java.util.Map;
|
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
|
||||||
import org.apache.poi.ss.formula.EvaluationCell;
|
import org.apache.poi.ss.formula.EvaluationCell;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
|
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
import org.apache.poi.ss.formula.eval.NumberEval;
|
||||||
@ -31,28 +28,16 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
|||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
|
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
|
||||||
*/
|
*/
|
||||||
public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
||||||
private WorkbookEvaluator _bookEvaluator;
|
|
||||||
|
|
||||||
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
||||||
_bookEvaluator = bookEvaluator;
|
super(bookEvaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
|
||||||
* in the evaluated workbook.
|
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
|
||||||
* of the evaluate~ methods of this class
|
|
||||||
*/
|
|
||||||
public void clearAllCachedResultValues() {
|
|
||||||
_bookEvaluator.clearAllCachedResultValues();
|
|
||||||
}
|
|
||||||
public void notifySetFormula(Cell cell) {
|
public void notifySetFormula(Cell cell) {
|
||||||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||||
}
|
}
|
||||||
@ -63,60 +48,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If cell contains a formula, the formula is evaluated and returned,
|
|
||||||
* else the CellValue simply copies the appropriate cell value from
|
|
||||||
* the cell and also its cell type. This method should be preferred over
|
|
||||||
* evaluateInCell() when the call should not modify the contents of the
|
|
||||||
* original cell.
|
|
||||||
* @param cell
|
|
||||||
*/
|
|
||||||
public CellValue evaluate(Cell cell) {
|
|
||||||
if (cell == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cell.getCellTypeEnum()) {
|
|
||||||
case BOOLEAN:
|
|
||||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
|
||||||
case ERROR:
|
|
||||||
return CellValue.getError(cell.getErrorCellValue());
|
|
||||||
case FORMULA:
|
|
||||||
return evaluateFormulaCellValue(cell);
|
|
||||||
case NUMERIC:
|
|
||||||
return new CellValue(cell.getNumericCellValue());
|
|
||||||
case STRING:
|
|
||||||
return new CellValue(cell.getRichStringCellValue().getString());
|
|
||||||
case BLANK:
|
|
||||||
return null;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If cell contains formula, it evaluates the formula,
|
|
||||||
* and saves the result of the formula. The cell
|
|
||||||
* remains as a formula cell.
|
|
||||||
* Else if cell does not contain formula, this method leaves
|
|
||||||
* the cell unchanged.
|
|
||||||
* Note that the type of the formula result is returned,
|
|
||||||
* so you know what kind of value is also stored with
|
|
||||||
* the formula.
|
|
||||||
* <pre>
|
|
||||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
|
||||||
* </pre>
|
|
||||||
* Be aware that your cell will hold both the formula,
|
|
||||||
* and the result. If you want the cell replaced with
|
|
||||||
* the result of the formula, use {@link #evaluate(org.apache.poi.ss.usermodel.Cell)} }
|
|
||||||
* @param cell The cell to evaluate
|
|
||||||
* @return The type of the formula result (the cell's type remains as CellType.FORMULA however)
|
|
||||||
*/
|
|
||||||
public int evaluateFormulaCell(Cell cell) {
|
|
||||||
return evaluateFormulaCellEnum(cell).getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If cell contains formula, it evaluates the formula,
|
* If cell contains formula, it evaluates the formula,
|
||||||
* and saves the result of the formula. The cell
|
* and saves the result of the formula. The cell
|
||||||
@ -164,27 +95,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
setCellValue(cell, cv);
|
setCellValue(cell, cv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void setCellType(Cell cell, CellValue cv) {
|
|
||||||
CellType cellType = cv.getCellType();
|
|
||||||
switch (cellType) {
|
|
||||||
case BOOLEAN:
|
|
||||||
case ERROR:
|
|
||||||
case NUMERIC:
|
|
||||||
case STRING:
|
|
||||||
cell.setCellType(cellType);
|
|
||||||
return;
|
|
||||||
case BLANK:
|
|
||||||
// never happens - blanks eventually get translated to zero
|
|
||||||
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
|
||||||
case FORMULA:
|
|
||||||
// this will never happen, we have already evaluated the formula
|
|
||||||
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setCellValue(Cell cell, CellValue cv) {
|
private static void setCellValue(Cell cell, CellValue cv) {
|
||||||
CellType cellType = cv.getCellType();
|
CellType cellType = cv.getCellType();
|
||||||
@ -218,7 +128,7 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
/**
|
/**
|
||||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||||
*/
|
*/
|
||||||
private CellValue evaluateFormulaCellValue(Cell cell) {
|
protected CellValue evaluateFormulaCellValue(Cell cell) {
|
||||||
EvaluationCell evalCell = toEvaluationCell(cell);
|
EvaluationCell evalCell = toEvaluationCell(cell);
|
||||||
ValueEval eval = _bookEvaluator.evaluate(evalCell);
|
ValueEval eval = _bookEvaluator.evaluate(evalCell);
|
||||||
if (eval instanceof NumberEval) {
|
if (eval instanceof NumberEval) {
|
||||||
@ -238,22 +148,4 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
}
|
}
|
||||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
|
||||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
|
||||||
return _bookEvaluator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
public void setIgnoreMissingWorkbooks(boolean ignore){
|
|
||||||
_bookEvaluator.setIgnoreMissingWorkbooks(ignore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
public void setDebugEvaluationOutputForNextEval(boolean value){
|
|
||||||
_bookEvaluator.setDebugEvaluationOutputForNextEval(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||||
import org.apache.poi.ss.formula.EvaluationCell;
|
import org.apache.poi.ss.formula.EvaluationCell;
|
||||||
import org.apache.poi.ss.formula.IStabilityClassifier;
|
import org.apache.poi.ss.formula.IStabilityClassifier;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||||
@ -88,7 +88,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||||||
* cells, and calling evaluateFormulaCell on each one.
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
*/
|
*/
|
||||||
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
|
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
|
||||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Loops over all cells in all sheets of the supplied
|
* Loops over all cells in all sheets of the supplied
|
||||||
@ -102,7 +102,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||||||
* cells, and calling evaluateFormulaCell on each one.
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
*/
|
*/
|
||||||
public void evaluateAll() {
|
public void evaluateAll() {
|
||||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(_book);
|
evaluateAllFormulaCells(_book, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,19 +167,18 @@ public final class XSSFName implements Name {
|
|||||||
public void setNameName(String name) {
|
public void setNameName(String name) {
|
||||||
validateName(name);
|
validateName(name);
|
||||||
|
|
||||||
|
String oldName = getNameName();
|
||||||
int sheetIndex = getSheetIndex();
|
int sheetIndex = getSheetIndex();
|
||||||
int numberOfNames = _workbook.getNumberOfNames();
|
|
||||||
//Check to ensure no other names have the same case-insensitive name at the same scope
|
//Check to ensure no other names have the same case-insensitive name at the same scope
|
||||||
for (int i = 0; i < numberOfNames; i++) {
|
for (XSSFName foundName : _workbook.getNames(name)) {
|
||||||
XSSFName nm = _workbook.getNameAt(i);
|
if (foundName.getSheetIndex() == sheetIndex && foundName != this) {
|
||||||
if ((nm != this)
|
|
||||||
&& name.equalsIgnoreCase(nm.getNameName())
|
|
||||||
&& (sheetIndex == nm.getSheetIndex())) {
|
|
||||||
String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
|
String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
|
||||||
throw new IllegalArgumentException(msg);
|
throw new IllegalArgumentException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ctName.setName(name);
|
_ctName.setName(name);
|
||||||
|
//Need to update the name -> named ranges map
|
||||||
|
_workbook.updateName(this, oldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRefersToFormula() {
|
public String getRefersToFormula() {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
|
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
|
||||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
|
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
|
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
|
||||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
|
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@ -29,16 +29,20 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.ListValuedMap;
|
||||||
|
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||||
import org.apache.poi.POIXMLDocument;
|
import org.apache.poi.POIXMLDocument;
|
||||||
import org.apache.poi.POIXMLDocumentPart;
|
import org.apache.poi.POIXMLDocumentPart;
|
||||||
import org.apache.poi.POIXMLException;
|
import org.apache.poi.POIXMLException;
|
||||||
@ -59,6 +63,7 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
|
|||||||
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
|
import org.apache.poi.ss.usermodel.Name;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
@ -140,6 +145,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
*/
|
*/
|
||||||
private List<XSSFSheet> sheets;
|
private List<XSSFSheet> sheets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this holds the XSSFName objects attached to this workbook, keyed by lower-case name
|
||||||
|
*/
|
||||||
|
private ListValuedMap<String, XSSFName> namedRangesByName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this holds the XSSFName objects attached to this workbook
|
* this holds the XSSFName objects attached to this workbook
|
||||||
*/
|
*/
|
||||||
@ -442,6 +452,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
stylesSource.setWorkbook(this);
|
stylesSource.setWorkbook(this);
|
||||||
|
|
||||||
namedRanges = new ArrayList<XSSFName>();
|
namedRanges = new ArrayList<XSSFName>();
|
||||||
|
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
|
||||||
sheets = new ArrayList<XSSFSheet>();
|
sheets = new ArrayList<XSSFSheet>();
|
||||||
pivotTables = new ArrayList<XSSFPivotTable>();
|
pivotTables = new ArrayList<XSSFPivotTable>();
|
||||||
}
|
}
|
||||||
@ -733,8 +744,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
public XSSFName createName() {
|
public XSSFName createName() {
|
||||||
CTDefinedName ctName = CTDefinedName.Factory.newInstance();
|
CTDefinedName ctName = CTDefinedName.Factory.newInstance();
|
||||||
ctName.setName("");
|
ctName.setName("");
|
||||||
|
return createAndStoreName(ctName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private XSSFName createAndStoreName(CTDefinedName ctName) {
|
||||||
XSSFName name = new XSSFName(ctName, this);
|
XSSFName name = new XSSFName(ctName, this);
|
||||||
namedRanges.add(name);
|
namedRanges.add(name);
|
||||||
|
namedRangesByName.put(ctName.getName().toLowerCase(Locale.ENGLISH), name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,28 +954,47 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
return stylesSource.getFontAt(idx);
|
return stylesSource.getFontAt(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first named range with the given name.
|
||||||
|
*
|
||||||
|
* Note: names of named ranges are not unique as they are scoped by sheet.
|
||||||
|
* {@link #getNames(String name)} returns all named ranges with the given name.
|
||||||
|
*
|
||||||
|
* @param name named range name
|
||||||
|
* @return XSSFName with the given name. <code>null</code> is returned no named range could be found.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public XSSFName getName(String name) {
|
public XSSFName getName(String name) {
|
||||||
int nameIndex = getNameIndex(name);
|
Collection<XSSFName> list = getNames(name);
|
||||||
if (nameIndex < 0) {
|
if (list.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return namedRanges.get(nameIndex);
|
return list.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the named ranges with the given name.
|
||||||
|
* <i>Note:</i>Excel named ranges are case-insensitive and
|
||||||
|
* this method performs a case-insensitive search.
|
||||||
|
*
|
||||||
|
* @param name named range name
|
||||||
|
* @return list of XSSFNames with the given name. An empty list if no named ranges could be found
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<XSSFName> getNames(String name) {
|
public List<XSSFName> getNames(String name) {
|
||||||
List<XSSFName> names = new ArrayList<XSSFName>();
|
return Collections.unmodifiableList(namedRangesByName.get(name.toLowerCase(Locale.ENGLISH)));
|
||||||
for(XSSFName nr : namedRanges) {
|
|
||||||
if(nr.getNameName().equals(name)) {
|
|
||||||
names.add(nr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return names;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the named range at the given index.
|
||||||
|
*
|
||||||
|
* @param nameIndex the index of the named range
|
||||||
|
* @return the XSSFName at the given index
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public XSSFName getNameAt(int nameIndex) {
|
public XSSFName getNameAt(int nameIndex) {
|
||||||
int nNames = namedRanges.size();
|
int nNames = namedRanges.size();
|
||||||
if (nNames < 1) {
|
if (nNames < 1) {
|
||||||
@ -973,21 +1008,30 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the named range index by his name
|
* Get a list of all the named ranges in the workbook.
|
||||||
* <i>Note:</i>Excel named ranges are case-insensitive and
|
|
||||||
* this method performs a case-insensitive search.
|
|
||||||
*
|
*
|
||||||
* @param name named range name
|
* @return list of XSSFNames in the workbook
|
||||||
* @return named range index
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
public List<XSSFName> getAllNames() {
|
||||||
|
return Collections.unmodifiableList(namedRanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the named range index by name.
|
||||||
|
*
|
||||||
|
* @param name named range name
|
||||||
|
* @return named range index. <code>-1</code> is returned if no named ranges could be found.
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||||
|
* Use {@link #getName(String)} instead.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
public int getNameIndex(String name) {
|
public int getNameIndex(String name) {
|
||||||
int i = 0;
|
XSSFName nm = getName(name);
|
||||||
for(XSSFName nr : namedRanges) {
|
if (nm != null) {
|
||||||
if(nr.getNameName().equals(name)) {
|
return namedRanges.indexOf(nm);
|
||||||
return i;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1258,22 +1302,40 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
|
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the named range at the given index.
|
||||||
|
*
|
||||||
|
* @param nameIndex the index of the named range name to remove
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void removeName(int nameIndex) {
|
public void removeName(int nameIndex) {
|
||||||
namedRanges.remove(nameIndex);
|
removeName(getNameAt(nameIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the first named range found with the given name.
|
||||||
|
*
|
||||||
|
* Note: names of named ranges are not unique (name + sheet
|
||||||
|
* index is unique), so {@link #removeName(Name)} should
|
||||||
|
* be used if possible.
|
||||||
|
*
|
||||||
|
* @param name the named range name to remove
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if no named range could be found
|
||||||
|
*
|
||||||
|
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void removeName(String name) {
|
public void removeName(String name) {
|
||||||
int idx = 0;
|
List<XSSFName> names = namedRangesByName.get(name.toLowerCase(Locale.ENGLISH));
|
||||||
for (XSSFName nm : namedRanges) {
|
if (names.isEmpty()) {
|
||||||
if(nm.getNameName().equalsIgnoreCase(name)) {
|
throw new IllegalArgumentException("Named range was not found: " + name);
|
||||||
removeName(idx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Named range was not found: " + name);
|
removeName(names.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1282,13 +1344,24 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
* (name + sheet index is unique), this method is more accurate.
|
* (name + sheet index is unique), this method is more accurate.
|
||||||
*
|
*
|
||||||
* @param name the name to remove.
|
* @param name the name to remove.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the named range is not a part of this XSSFWorkbook
|
||||||
*/
|
*/
|
||||||
void removeName(XSSFName name) {
|
@Override
|
||||||
if (!namedRanges.remove(name)) {
|
public void removeName(Name name) {
|
||||||
|
if (!namedRangesByName.removeMapping(name.getNameName().toLowerCase(Locale.ENGLISH), name)
|
||||||
|
|| !namedRanges.remove(name)) {
|
||||||
throw new IllegalArgumentException("Name was not found: " + name);
|
throw new IllegalArgumentException("Name was not found: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateName(XSSFName name, String oldName) {
|
||||||
|
if (!namedRangesByName.removeMapping(oldName.toLowerCase(Locale.ENGLISH), name)) {
|
||||||
|
throw new IllegalArgumentException("Name was not found: " + name);
|
||||||
|
}
|
||||||
|
namedRangesByName.put(name.getNameName().toLowerCase(Locale.ENGLISH), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the printarea for the sheet specified
|
* Delete the printarea for the sheet specified
|
||||||
@ -1297,13 +1370,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void removePrintArea(int sheetIndex) {
|
public void removePrintArea(int sheetIndex) {
|
||||||
int cont = 0;
|
XSSFName name = getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);
|
||||||
for (XSSFName name : namedRanges) {
|
if (name != null) {
|
||||||
if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getSheetIndex() == sheetIndex) {
|
removeName(name);
|
||||||
namedRanges.remove(cont);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cont++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1369,17 +1438,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//adjust indices of names ranges
|
//adjust indices of names ranges
|
||||||
for (Iterator<XSSFName> it = namedRanges.iterator(); it.hasNext();) {
|
List<XSSFName> toRemove = new ArrayList<XSSFName>();
|
||||||
XSSFName nm = it.next();
|
for (XSSFName nm : namedRanges) {
|
||||||
CTDefinedName ct = nm.getCTName();
|
CTDefinedName ct = nm.getCTName();
|
||||||
if(!ct.isSetLocalSheetId()) continue;
|
if(!ct.isSetLocalSheetId()) continue;
|
||||||
if (ct.getLocalSheetId() == index) {
|
if (ct.getLocalSheetId() == index) {
|
||||||
it.remove();
|
toRemove.add(nm);
|
||||||
} else if (ct.getLocalSheetId() > index){
|
} else if (ct.getLocalSheetId() > index){
|
||||||
// Bump down by one, so still points at the same sheet
|
// Bump down by one, so still points at the same sheet
|
||||||
ct.setLocalSheetId(ct.getLocalSheetId()-1);
|
ct.setLocalSheetId(ct.getLocalSheetId()-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (XSSFName nm : toRemove) {
|
||||||
|
removeName(nm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1514,8 +1586,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
|
XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
|
||||||
for (XSSFName name : namedRanges) {
|
for (XSSFName name : namedRangesByName.get(builtInCode.toLowerCase(Locale.ENGLISH))) {
|
||||||
if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getSheetIndex() == sheetNumber) {
|
if (name.getSheetIndex() == sheetNumber) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1537,15 +1609,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
nameRecord.setName(builtInName);
|
nameRecord.setName(builtInName);
|
||||||
nameRecord.setLocalSheetId(sheetNumber);
|
nameRecord.setLocalSheetId(sheetNumber);
|
||||||
|
|
||||||
XSSFName name = new XSSFName(nameRecord, this);
|
if (getBuiltInName(builtInName, sheetNumber) != null) {
|
||||||
for (XSSFName nr : namedRanges) {
|
throw new POIXMLException("Builtin (" + builtInName
|
||||||
if (nr.equals(name))
|
+ ") already exists for sheet (" + sheetNumber + ")");
|
||||||
throw new POIXMLException("Builtin (" + builtInName
|
|
||||||
+ ") already exists for sheet (" + sheetNumber + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namedRanges.add(name);
|
return createAndStoreName(nameRecord);
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1665,10 +1734,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reprocessNamedRanges() {
|
private void reprocessNamedRanges() {
|
||||||
|
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
|
||||||
namedRanges = new ArrayList<XSSFName>();
|
namedRanges = new ArrayList<XSSFName>();
|
||||||
if(workbook.isSetDefinedNames()) {
|
if(workbook.isSetDefinedNames()) {
|
||||||
for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
|
for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
|
||||||
namedRanges.add(new XSSFName(ctName, this));
|
createAndStoreName(ctName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,7 @@ public final class XSSFFormulaUtils {
|
|||||||
*/
|
*/
|
||||||
public void updateSheetName(final int sheetIndex, final String oldName, final String newName) {
|
public void updateSheetName(final int sheetIndex, final String oldName, final String newName) {
|
||||||
// update named ranges
|
// update named ranges
|
||||||
final int numberOfNames = _wb.getNumberOfNames();
|
for (XSSFName nm : _wb.getAllNames()) {
|
||||||
for (int i = 0; i < numberOfNames; i++) {
|
|
||||||
XSSFName nm = _wb.getNameAt(i);
|
|
||||||
if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) {
|
if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) {
|
||||||
updateName(nm, oldName, newName);
|
updateName(nm, oldName, newName);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.xssf.usermodel.helpers;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||||
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
|
import org.apache.xmlbeans.XmlObject;
|
||||||
|
|
||||||
|
@Internal(since="3.15 beta 3")
|
||||||
|
public final class XSSFPasswordHelper {
|
||||||
|
private XSSFPasswordHelper() {
|
||||||
|
// no instances of this static class
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the XORed or hashed password
|
||||||
|
*
|
||||||
|
* @param xobj the xmlbeans object which contains the password attributes
|
||||||
|
* @param password the password, if null, the password attributes will be removed
|
||||||
|
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
||||||
|
* @param prefix the prefix of the password attributes, may be null
|
||||||
|
*/
|
||||||
|
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
||||||
|
XmlCursor cur = xobj.newCursor();
|
||||||
|
|
||||||
|
if (password == null) {
|
||||||
|
cur.removeAttribute(getAttrName(prefix, "password"));
|
||||||
|
cur.removeAttribute(getAttrName(prefix, "algorithmName"));
|
||||||
|
cur.removeAttribute(getAttrName(prefix, "hashValue"));
|
||||||
|
cur.removeAttribute(getAttrName(prefix, "saltValue"));
|
||||||
|
cur.removeAttribute(getAttrName(prefix, "spinCount"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.toFirstContentToken();
|
||||||
|
if (hashAlgo == null) {
|
||||||
|
int hash = CryptoFunctions.createXorVerifier1(password);
|
||||||
|
cur.insertAttributeWithValue(getAttrName(prefix, "password"),
|
||||||
|
String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));
|
||||||
|
} else {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
byte salt[] = random.generateSeed(16);
|
||||||
|
|
||||||
|
// Iterations specifies the number of times the hashing function shall be iteratively run (using each
|
||||||
|
// iteration's result as the input for the next iteration).
|
||||||
|
int spinCount = 100000;
|
||||||
|
|
||||||
|
// Implementation Notes List:
|
||||||
|
// --> In this third stage, the reversed byte order legacy hash from the second stage shall
|
||||||
|
// be converted to Unicode hex string representation
|
||||||
|
byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
|
||||||
|
|
||||||
|
cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
|
||||||
|
cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
|
||||||
|
cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
|
||||||
|
cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
|
||||||
|
}
|
||||||
|
cur.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the password, i.e.
|
||||||
|
* calculates the hash of the given password and compares it against the stored hash
|
||||||
|
*
|
||||||
|
* @param xobj the xmlbeans object which contains the password attributes
|
||||||
|
* @param password the password, if null the method will always return false,
|
||||||
|
* even if there's no password set
|
||||||
|
* @param prefix the prefix of the password attributes, may be null
|
||||||
|
*
|
||||||
|
* @return true, if the hashes match
|
||||||
|
*/
|
||||||
|
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
||||||
|
// TODO: is "velvetSweatshop" the default password?
|
||||||
|
if (password == null) return false;
|
||||||
|
|
||||||
|
XmlCursor cur = xobj.newCursor();
|
||||||
|
String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
|
||||||
|
String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
|
||||||
|
String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
|
||||||
|
String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
|
||||||
|
String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
|
||||||
|
cur.dispose();
|
||||||
|
|
||||||
|
if (xorHashVal != null) {
|
||||||
|
int hash1 = Integer.parseInt(xorHashVal, 16);
|
||||||
|
int hash2 = CryptoFunctions.createXorVerifier1(password);
|
||||||
|
return hash1 == hash2;
|
||||||
|
} else {
|
||||||
|
if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
|
||||||
|
HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
|
||||||
|
byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
|
||||||
|
int spinCnt = Integer.parseInt(spinCount);
|
||||||
|
byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
|
||||||
|
return Arrays.equals(hash1, hash2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static QName getAttrName(String prefix, String name) {
|
||||||
|
if (prefix == null || "".equals(prefix)) {
|
||||||
|
return new QName(name);
|
||||||
|
} else {
|
||||||
|
return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,130 +1,60 @@
|
|||||||
/*
|
/*
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.poi.xssf.usermodel.helpers;
|
package org.apache.poi.xssf.usermodel.helpers;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import java.util.Arrays;
|
import org.apache.poi.util.Internal;
|
||||||
import java.util.Locale;
|
import org.apache.poi.util.Removal;
|
||||||
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
import javax.xml.namespace.QName;
|
/**
|
||||||
|
* @deprecated POI 3.15 beta 3. Use {@link XSSFPasswordHelper} instead.
|
||||||
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
*/
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
@Internal(since="3.15 beta 3")
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
@Deprecated
|
||||||
import org.apache.xmlbeans.XmlObject;
|
@Removal(version="3.17")
|
||||||
|
public class XSSFPaswordHelper {
|
||||||
public class XSSFPaswordHelper {
|
/**
|
||||||
/**
|
* Sets the XORed or hashed password
|
||||||
* Sets the XORed or hashed password
|
*
|
||||||
*
|
* @param xobj the xmlbeans object which contains the password attributes
|
||||||
* @param xobj the xmlbeans object which contains the password attributes
|
* @param password the password, if null, the password attributes will be removed
|
||||||
* @param password the password, if null, the password attributes will be removed
|
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
||||||
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
* @param prefix the prefix of the password attributes, may be null
|
||||||
* @param prefix the prefix of the password attributes, may be null
|
*/
|
||||||
*/
|
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
||||||
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
XSSFPasswordHelper.setPassword(xobj, password, hashAlgo, prefix);
|
||||||
XmlCursor cur = xobj.newCursor();
|
}
|
||||||
|
|
||||||
if (password == null) {
|
/**
|
||||||
cur.removeAttribute(getAttrName(prefix, "password"));
|
* Validates the password, i.e.
|
||||||
cur.removeAttribute(getAttrName(prefix, "algorithmName"));
|
* calculates the hash of the given password and compares it against the stored hash
|
||||||
cur.removeAttribute(getAttrName(prefix, "hashValue"));
|
*
|
||||||
cur.removeAttribute(getAttrName(prefix, "saltValue"));
|
* @param xobj the xmlbeans object which contains the password attributes
|
||||||
cur.removeAttribute(getAttrName(prefix, "spinCount"));
|
* @param password the password, if null the method will always return false,
|
||||||
return;
|
* even if there's no password set
|
||||||
}
|
* @param prefix the prefix of the password attributes, may be null
|
||||||
|
*
|
||||||
cur.toFirstContentToken();
|
* @return true, if the hashes match
|
||||||
if (hashAlgo == null) {
|
*/
|
||||||
int hash = CryptoFunctions.createXorVerifier1(password);
|
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
||||||
cur.insertAttributeWithValue(getAttrName(prefix, "password"),
|
return XSSFPasswordHelper.validatePassword(xobj, password, prefix);
|
||||||
Integer.toHexString(hash).toUpperCase(Locale.ROOT));
|
}
|
||||||
} else {
|
}
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
byte salt[] = random.generateSeed(16);
|
|
||||||
|
|
||||||
// Iterations specifies the number of times the hashing function shall be iteratively run (using each
|
|
||||||
// iteration's result as the input for the next iteration).
|
|
||||||
int spinCount = 100000;
|
|
||||||
|
|
||||||
// Implementation Notes List:
|
|
||||||
// --> In this third stage, the reversed byte order legacy hash from the second stage shall
|
|
||||||
// be converted to Unicode hex string representation
|
|
||||||
byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
|
|
||||||
|
|
||||||
cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
|
|
||||||
cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
|
|
||||||
cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
|
|
||||||
cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
|
|
||||||
}
|
|
||||||
cur.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the password, i.e.
|
|
||||||
* calculates the hash of the given password and compares it against the stored hash
|
|
||||||
*
|
|
||||||
* @param xobj the xmlbeans object which contains the password attributes
|
|
||||||
* @param password the password, if null the method will always return false,
|
|
||||||
* even if there's no password set
|
|
||||||
* @param prefix the prefix of the password attributes, may be null
|
|
||||||
*
|
|
||||||
* @return true, if the hashes match
|
|
||||||
*/
|
|
||||||
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
|
||||||
// TODO: is "velvetSweatshop" the default password?
|
|
||||||
if (password == null) return false;
|
|
||||||
|
|
||||||
XmlCursor cur = xobj.newCursor();
|
|
||||||
String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
|
|
||||||
String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
|
|
||||||
String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
|
|
||||||
String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
|
|
||||||
String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
|
|
||||||
cur.dispose();
|
|
||||||
|
|
||||||
if (xorHashVal != null) {
|
|
||||||
int hash1 = Integer.parseInt(xorHashVal, 16);
|
|
||||||
int hash2 = CryptoFunctions.createXorVerifier1(password);
|
|
||||||
return hash1 == hash2;
|
|
||||||
} else {
|
|
||||||
if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
|
|
||||||
HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
|
|
||||||
byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
|
|
||||||
int spinCnt = Integer.parseInt(spinCount);
|
|
||||||
byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
|
|
||||||
return Arrays.equals(hash1, hash2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static QName getAttrName(String prefix, String name) {
|
|
||||||
if (prefix == null || "".equals(prefix)) {
|
|
||||||
return new QName(name);
|
|
||||||
} else {
|
|
||||||
return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -83,9 +83,7 @@ public final class XSSFRowShifter extends RowShifter {
|
|||||||
public void updateNamedRanges(FormulaShifter shifter) {
|
public void updateNamedRanges(FormulaShifter shifter) {
|
||||||
Workbook wb = sheet.getWorkbook();
|
Workbook wb = sheet.getWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
|
||||||
final int numberOfNames = wb.getNumberOfNames();
|
for (Name name : wb.getAllNames()) {
|
||||||
for (int i = 0; i < numberOfNames; i++) {
|
|
||||||
Name name = wb.getNameAt(i);
|
|
||||||
String formula = name.getRefersToFormula();
|
String formula = name.getRefersToFormula();
|
||||||
int sheetIndex = name.getSheetIndex();
|
int sheetIndex = name.getSheetIndex();
|
||||||
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references
|
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.apache.poi.openxml4j.opc.internal;
|
package org.apache.poi.openxml4j.opc.internal;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
@ -44,16 +45,21 @@ public final class TestContentTypeManager {
|
|||||||
|
|
||||||
// Retrieves core properties part
|
// Retrieves core properties part
|
||||||
OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ);
|
OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ);
|
||||||
PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
|
try {
|
||||||
PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
|
PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
|
||||||
PackagePart coreDocument = p.getPart(corePropertiesRelationship);
|
PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
|
||||||
|
PackagePart coreDocument = p.getPart(corePropertiesRelationship);
|
||||||
assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
|
|
||||||
|
|
||||||
// TODO - finish writing this test
|
assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
|
||||||
assumeTrue("finish writing this test", false);
|
|
||||||
|
// TODO - finish writing this test
|
||||||
ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
|
assumeTrue("finish writing this test", false);
|
||||||
|
|
||||||
|
ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
|
||||||
|
assertNotNull(ctm);
|
||||||
|
} finally {
|
||||||
|
p.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,25 +115,25 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
|
|||||||
assertFalse(wb.isMacroEnabled());
|
assertFalse(wb.isMacroEnabled());
|
||||||
assertEquals(3, wb.getNumberOfNames());
|
assertEquals(3, wb.getNumberOfNames());
|
||||||
|
|
||||||
assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId());
|
assertEquals(0, wb.getName("SheetAA1").getCTName().getLocalSheetId());
|
||||||
assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId());
|
assertFalse(wb.getName("SheetAA1").getCTName().isSetLocalSheetId());
|
||||||
assertEquals("SheetA!$A$1", wb.getNameAt(0).getRefersToFormula());
|
assertEquals("SheetA!$A$1", wb.getName("SheetAA1").getRefersToFormula());
|
||||||
assertEquals("SheetA", wb.getNameAt(0).getSheetName());
|
assertEquals("SheetA", wb.getName("SheetAA1").getSheetName());
|
||||||
|
|
||||||
assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId());
|
assertEquals(0, wb.getName("SheetBA1").getCTName().getLocalSheetId());
|
||||||
assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId());
|
assertFalse(wb.getName("SheetBA1").getCTName().isSetLocalSheetId());
|
||||||
assertEquals("SheetB!$A$1", wb.getNameAt(1).getRefersToFormula());
|
assertEquals("SheetB!$A$1", wb.getName("SheetBA1").getRefersToFormula());
|
||||||
assertEquals("SheetB", wb.getNameAt(1).getSheetName());
|
assertEquals("SheetB", wb.getName("SheetBA1").getSheetName());
|
||||||
|
|
||||||
assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId());
|
assertEquals(0, wb.getName("SheetCA1").getCTName().getLocalSheetId());
|
||||||
assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId());
|
assertFalse(wb.getName("SheetCA1").getCTName().isSetLocalSheetId());
|
||||||
assertEquals("SheetC!$A$1", wb.getNameAt(2).getRefersToFormula());
|
assertEquals("SheetC!$A$1", wb.getName("SheetCA1").getRefersToFormula());
|
||||||
assertEquals("SheetC", wb.getNameAt(2).getSheetName());
|
assertEquals("SheetC", wb.getName("SheetCA1").getSheetName());
|
||||||
|
|
||||||
// Save and re-load, still there
|
// Save and re-load, still there
|
||||||
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
assertEquals(3, nwb.getNumberOfNames());
|
assertEquals(3, nwb.getNumberOfNames());
|
||||||
assertEquals("SheetA!$A$1", nwb.getNameAt(0).getRefersToFormula());
|
assertEquals("SheetA!$A$1", nwb.getName("SheetAA1").getRefersToFormula());
|
||||||
|
|
||||||
nwb.close();
|
nwb.close();
|
||||||
wb.close();
|
wb.close();
|
||||||
|
@ -154,7 +154,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
evaluator.evaluate(cXSL_cell);
|
evaluator.evaluate(cXSL_cell);
|
||||||
fail("Without a fix for #56752, shouldn't be able to evaluate a " +
|
fail("Without a fix for #56752, shouldn't be able to evaluate a " +
|
||||||
"reference to a non-provided linked workbook");
|
"reference to a non-provided linked workbook");
|
||||||
} catch(Exception e) {}
|
} catch(Exception e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the environment
|
// Setup the environment
|
||||||
Map<String,FormulaEvaluator> evaluators = new HashMap<String, FormulaEvaluator>();
|
Map<String,FormulaEvaluator> evaluators = new HashMap<String, FormulaEvaluator>();
|
||||||
@ -171,8 +173,19 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
evaluator.evaluate(c);
|
evaluator.evaluate(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// And evaluate the other way too
|
||||||
|
evaluator.evaluateAll();
|
||||||
|
|
||||||
// Evaluate and check results
|
// Static evaluator won't work, as no references passed in
|
||||||
|
try {
|
||||||
|
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
|
fail("Static method lacks references, shouldn't work");
|
||||||
|
} catch(Exception e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Evaluate specific cells and check results
|
||||||
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
|
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
|
||||||
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
|
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
|
||||||
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
|
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
|
||||||
@ -196,7 +209,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
try {
|
try {
|
||||||
cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1");
|
cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1");
|
||||||
fail("New workbook not linked, shouldn't be able to add");
|
fail("New workbook not linked, shouldn't be able to add");
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
// Link and re-try
|
// Link and re-try
|
||||||
Workbook alt = new XSSFWorkbook();
|
Workbook alt = new XSSFWorkbook();
|
||||||
@ -651,4 +666,20 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
private Cell getCell(Sheet sheet, int rowNo, int column) {
|
private Cell getCell(Sheet sheet, int rowNo, int column) {
|
||||||
return sheet.getRow(rowNo).getCell(column);
|
return sheet.getRow(rowNo).getCell(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test59736() {
|
||||||
|
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("59736.xlsx");
|
||||||
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
|
Cell cell = wb.getSheetAt(0).getRow(0).getCell(0);
|
||||||
|
assertEquals(1, cell.getNumericCellValue(), 0.001);
|
||||||
|
|
||||||
|
cell = wb.getSheetAt(0).getRow(1).getCell(0);
|
||||||
|
CellValue value = evaluator.evaluate(cell);
|
||||||
|
assertEquals(1, value.getNumberValue(), 0.001);
|
||||||
|
|
||||||
|
cell = wb.getSheetAt(0).getRow(2).getCell(0);
|
||||||
|
value = evaluator.evaluate(cell);
|
||||||
|
assertEquals(1, value.getNumberValue(), 0.001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||||||
//sheet.createFreezePane(0, 3);
|
//sheet.createFreezePane(0, 3);
|
||||||
}
|
}
|
||||||
assertEquals(1, wb.getNumberOfNames());
|
assertEquals(1, wb.getNumberOfNames());
|
||||||
XSSFName nr1 = wb.getNameAt(0);
|
XSSFName nr1 = wb.getName(XSSFName.BUILTIN_PRINT_TITLE);
|
||||||
|
|
||||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
|
|
||||||
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
||||||
|
|
||||||
//remove the columns part
|
//remove the columns part
|
||||||
@ -77,9 +76,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||||||
wb.close();
|
wb.close();
|
||||||
|
|
||||||
assertEquals(1, nwb.getNumberOfNames());
|
assertEquals(1, nwb.getNumberOfNames());
|
||||||
nr1 = nwb.getNameAt(0);
|
nr1 = nwb.getName(XSSFName.BUILTIN_PRINT_TITLE);
|
||||||
|
|
||||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
|
|
||||||
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
||||||
|
|
||||||
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
|
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
|
||||||
@ -89,7 +87,7 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||||||
sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
|
sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
|
||||||
|
|
||||||
assertEquals(2, nwb.getNumberOfNames());
|
assertEquals(2, nwb.getNumberOfNames());
|
||||||
XSSFName nr2 = nwb.getNameAt(1);
|
XSSFName nr2 = nwb.getNames(XSSFName.BUILTIN_PRINT_TITLE).get(1);
|
||||||
|
|
||||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
|
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
|
||||||
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
|
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
|
||||||
@ -98,4 +96,38 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||||||
sheet2.setRepeatingColumns(null);
|
sheet2.setRepeatingColumns(null);
|
||||||
nwb.close();
|
nwb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetNameName() throws Exception {
|
||||||
|
// Test that renaming named ranges doesn't break our new named range map
|
||||||
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
|
wb.createSheet("First Sheet");
|
||||||
|
|
||||||
|
// Two named ranges called "name1", one scoped to sheet1 and one globally
|
||||||
|
XSSFName nameSheet1 = wb.createName();
|
||||||
|
nameSheet1.setNameName("name1");
|
||||||
|
nameSheet1.setRefersToFormula("'First Sheet'!$A$1");
|
||||||
|
nameSheet1.setSheetIndex(0);
|
||||||
|
|
||||||
|
XSSFName nameGlobal = wb.createName();
|
||||||
|
nameGlobal.setNameName("name1");
|
||||||
|
nameGlobal.setRefersToFormula("'First Sheet'!$B$1");
|
||||||
|
|
||||||
|
// Rename sheet-scoped name to "name2", check everything is updated properly
|
||||||
|
// and that the other name is unaffected
|
||||||
|
nameSheet1.setNameName("name2");
|
||||||
|
assertEquals(1, wb.getNames("name1").size());
|
||||||
|
assertEquals(1, wb.getNames("name2").size());
|
||||||
|
assertEquals(nameGlobal, wb.getName("name1"));
|
||||||
|
assertEquals(nameSheet1, wb.getName("name2"));
|
||||||
|
|
||||||
|
// Rename the other name to "name" and check everything again
|
||||||
|
nameGlobal.setNameName("name2");
|
||||||
|
assertEquals(0, wb.getNames("name1").size());
|
||||||
|
assertEquals(2, wb.getNames("name2").size());
|
||||||
|
assertTrue(wb.getNames("name2").contains(nameGlobal));
|
||||||
|
assertTrue(wb.getNames("name2").contains(nameSheet1));
|
||||||
|
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
|||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
|
||||||
|
|
||||||
|
|
||||||
public final class TestXSSFSheet extends BaseTestXSheet {
|
public final class TestXSSFSheet extends BaseTestXSheet {
|
||||||
@ -1099,6 +1100,30 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
|||||||
wb.close();
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void protectSheet_emptyPassword() throws IOException {
|
||||||
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
|
XSSFSheet sheet = wb.createSheet();
|
||||||
|
CTSheetProtection pr = sheet.getCTWorksheet().getSheetProtection();
|
||||||
|
assertNull("CTSheetProtection should be null by default", pr);
|
||||||
|
String password = "";
|
||||||
|
sheet.protectSheet(password);
|
||||||
|
pr = sheet.getCTWorksheet().getSheetProtection();
|
||||||
|
assertNotNull("CTSheetProtection should be not null", pr);
|
||||||
|
assertTrue("sheet protection should be on", pr.isSetSheet());
|
||||||
|
assertTrue("object protection should be on", pr.isSetObjects());
|
||||||
|
assertTrue("scenario protection should be on", pr.isSetScenarios());
|
||||||
|
int hashVal = CryptoFunctions.createXorVerifier1(password);
|
||||||
|
STUnsignedShortHex xpassword = pr.xgetPassword();
|
||||||
|
int actualVal = Integer.parseInt(xpassword.getStringValue(),16);
|
||||||
|
assertEquals("well known value for top secret hash should match", hashVal, actualVal);
|
||||||
|
|
||||||
|
sheet.protectSheet(null);
|
||||||
|
assertNull("protectSheet(null) should unset CTSheetProtection", sheet.getCTWorksheet().getSheetProtection());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void protectSheet_lowlevel_2013() throws IOException {
|
public void protectSheet_lowlevel_2013() throws IOException {
|
||||||
String password = "test";
|
String password = "test";
|
||||||
|
@ -1140,4 +1140,44 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
|
|||||||
|
|
||||||
wb.close();
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveSheet() throws IOException {
|
||||||
|
// Test removing a sheet maintains the named ranges correctly
|
||||||
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
|
wb.createSheet("Sheet1");
|
||||||
|
wb.createSheet("Sheet2");
|
||||||
|
|
||||||
|
XSSFName sheet1Name = wb.createName();
|
||||||
|
sheet1Name.setNameName("name1");
|
||||||
|
sheet1Name.setSheetIndex(0);
|
||||||
|
sheet1Name.setRefersToFormula("Sheet1!$A$1");
|
||||||
|
|
||||||
|
XSSFName sheet2Name = wb.createName();
|
||||||
|
sheet2Name.setNameName("name1");
|
||||||
|
sheet2Name.setSheetIndex(1);
|
||||||
|
sheet2Name.setRefersToFormula("Sheet2!$A$1");
|
||||||
|
|
||||||
|
assertTrue(wb.getAllNames().contains(sheet1Name));
|
||||||
|
assertTrue(wb.getAllNames().contains(sheet2Name));
|
||||||
|
|
||||||
|
assertEquals(2, wb.getNames("name1").size());
|
||||||
|
assertEquals(sheet1Name, wb.getNames("name1").get(0));
|
||||||
|
assertEquals(sheet2Name, wb.getNames("name1").get(1));
|
||||||
|
|
||||||
|
// Remove sheet1, we should only have sheet2Name now
|
||||||
|
wb.removeSheetAt(0);
|
||||||
|
|
||||||
|
assertFalse(wb.getAllNames().contains(sheet1Name));
|
||||||
|
assertTrue(wb.getAllNames().contains(sheet2Name));
|
||||||
|
assertEquals(1, wb.getNames("name1").size());
|
||||||
|
assertEquals(sheet2Name, wb.getNames("name1").get(0));
|
||||||
|
|
||||||
|
// Check by index as well for sanity
|
||||||
|
assertEquals(1, wb.getNumberOfNames());
|
||||||
|
assertEquals(0, wb.getNameIndex("name1"));
|
||||||
|
assertEquals(sheet2Name, wb.getNameAt(0));
|
||||||
|
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,20 +571,39 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||||||
return _fields;
|
return _fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning - not currently implemented for HWPF!
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write() throws IOException {
|
public void write() throws IOException {
|
||||||
|
// TODO Implement
|
||||||
throw new IllegalStateException("Coming soon!");
|
throw new IllegalStateException("Coming soon!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out the word file that is represented by an instance of this class.
|
||||||
|
*
|
||||||
|
* If the {@link File} exists, it will be replaced, otherwise a new one
|
||||||
|
* will be created
|
||||||
|
*
|
||||||
|
* @param newFile The File to write to.
|
||||||
|
* @throws IOException If there is an unexpected IOException from writing
|
||||||
|
* to the File.
|
||||||
|
*
|
||||||
|
* @since 3.15 beta 3
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(File newFile) throws IOException {
|
public void write(File newFile) throws IOException {
|
||||||
throw new IllegalStateException("Coming soon!");
|
NPOIFSFileSystem pfs = POIFSFileSystem.create(newFile);
|
||||||
|
write(pfs, true);
|
||||||
|
pfs.writeFilesystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes out the word file that is represented by an instance of this class.
|
* Writes out the word file that is represented by an instance of this class.
|
||||||
*
|
*
|
||||||
* If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
|
* For better performance when writing to files, use {@link #write(File)}.
|
||||||
* or has a high cost/latency associated with each written byte,
|
* If {@code stream} has a high cost/latency associated with each written byte,
|
||||||
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
|
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
|
||||||
* to improve write performance.
|
* to improve write performance.
|
||||||
*
|
*
|
||||||
@ -592,9 +611,12 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||||||
* @throws IOException If there is an unexpected IOException from the passed
|
* @throws IOException If there is an unexpected IOException from the passed
|
||||||
* in OutputStream.
|
* in OutputStream.
|
||||||
*/
|
*/
|
||||||
public void write(OutputStream out)
|
public void write(OutputStream out) throws IOException {
|
||||||
throws IOException
|
NPOIFSFileSystem pfs = new NPOIFSFileSystem();
|
||||||
{
|
write(pfs, true);
|
||||||
|
pfs.writeFilesystem( out );
|
||||||
|
}
|
||||||
|
private void write(NPOIFSFileSystem pfs, boolean copyOtherEntries) throws IOException {
|
||||||
// initialize our streams for writing.
|
// initialize our streams for writing.
|
||||||
HWPFFileSystem docSys = new HWPFFileSystem();
|
HWPFFileSystem docSys = new HWPFFileSystem();
|
||||||
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
|
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
|
||||||
@ -891,7 +913,8 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create new document preserving order of entries
|
// create new document preserving order of entries
|
||||||
NPOIFSFileSystem pfs = new NPOIFSFileSystem();
|
// TODO Check "copyOtherEntries" and tweak behaviour based on that
|
||||||
|
// TODO That's needed for in-place write
|
||||||
boolean docWritten = false;
|
boolean docWritten = false;
|
||||||
boolean dataWritten = false;
|
boolean dataWritten = false;
|
||||||
boolean objectPoolWritten = false;
|
boolean objectPoolWritten = false;
|
||||||
@ -967,7 +990,6 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||||||
if ( !objectPoolWritten )
|
if ( !objectPoolWritten )
|
||||||
_objectPool.writeTo( pfs.getRoot() );
|
_objectPool.writeTo( pfs.getRoot() );
|
||||||
|
|
||||||
pfs.writeFilesystem( out );
|
|
||||||
this.directory = pfs.getRoot();
|
this.directory = pfs.getRoot();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.HWPFDocument;
|
||||||
|
import org.apache.poi.hwpf.HWPFTestCase;
|
||||||
|
import org.apache.poi.hwpf.HWPFTestDataSamples;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
import org.apache.poi.util.TempFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test various write situations
|
||||||
|
*/
|
||||||
|
public final class TestHWPFWrite extends HWPFTestCase {
|
||||||
|
/**
|
||||||
|
* Write to a stream
|
||||||
|
*/
|
||||||
|
public void testWriteStream() throws Exception {
|
||||||
|
HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
|
||||||
|
|
||||||
|
Range r = doc.getRange();
|
||||||
|
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
doc.write(baos);
|
||||||
|
doc.close();
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||||
|
|
||||||
|
doc = new HWPFDocument(bais);
|
||||||
|
r = doc.getRange();
|
||||||
|
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||||
|
doc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to a new file
|
||||||
|
*/
|
||||||
|
public void testWriteNewFile() throws Exception {
|
||||||
|
HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
|
||||||
|
|
||||||
|
Range r = doc.getRange();
|
||||||
|
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||||
|
|
||||||
|
File file = TempFile.createTempFile("TestDocument", ".doc");
|
||||||
|
doc.write(file);
|
||||||
|
doc.close();
|
||||||
|
|
||||||
|
// Check reading from File and Stream
|
||||||
|
doc = new HWPFDocument(new FileInputStream(file));
|
||||||
|
r = doc.getRange();
|
||||||
|
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||||
|
doc.close();
|
||||||
|
|
||||||
|
doc = new HWPFDocument(new POIFSFileSystem(file));
|
||||||
|
r = doc.getRange();
|
||||||
|
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||||
|
doc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO In-place write positive and negative checks
|
||||||
|
}
|
@ -50,14 +50,20 @@ public abstract class BaseTestSlideShow {
|
|||||||
@Test
|
@Test
|
||||||
public void addPicture_Stream() throws IOException {
|
public void addPicture_Stream() throws IOException {
|
||||||
SlideShow<?,?> show = createSlideShow();
|
SlideShow<?,?> show = createSlideShow();
|
||||||
InputStream stream = slTests.openResourceAsStream("clock.jpg");
|
try {
|
||||||
|
InputStream stream = slTests.openResourceAsStream("clock.jpg");
|
||||||
assertEquals(0, show.getPictureData().size());
|
try {
|
||||||
PictureData picture = show.addPicture(stream, PictureType.JPEG);
|
assertEquals(0, show.getPictureData().size());
|
||||||
assertEquals(1, show.getPictureData().size());
|
PictureData picture = show.addPicture(stream, PictureType.JPEG);
|
||||||
assertSame(picture, show.getPictureData().get(0));
|
assertEquals(1, show.getPictureData().size());
|
||||||
|
assertSame(picture, show.getPictureData().get(0));
|
||||||
show.close();
|
|
||||||
|
} finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
show.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -27,6 +27,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
|
|||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
@ -105,6 +106,7 @@ public final class TestIndirect {
|
|||||||
|
|
||||||
// non-error cases
|
// non-error cases
|
||||||
confirm(feA, c, "INDIRECT(\"C2\")", 23);
|
confirm(feA, c, "INDIRECT(\"C2\")", 23);
|
||||||
|
confirm(feA, c, "INDIRECT(\"C2\", TRUE)", 23);
|
||||||
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
|
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
|
||||||
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
|
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
|
||||||
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
|
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
|
||||||
@ -149,7 +151,7 @@ public final class TestIndirect {
|
|||||||
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
|
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
|
||||||
// }
|
// }
|
||||||
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
|
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
|
||||||
|
|
||||||
wbA.close();
|
wbA.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,4 +205,9 @@ public final class TestIndirect {
|
|||||||
+ "' but got '" + cv.formatAsString() + "'.");
|
+ "' but got '" + cv.formatAsString() + "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidInput() {
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, Indirect.instance.evaluate(new ValueEval[] {}, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,8 @@ package org.apache.poi.ss.formula.functions;
|
|||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.formula.eval.AreaEval;
|
import org.apache.poi.ss.formula.FormulaParseException;
|
||||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
import org.apache.poi.ss.formula.eval.*;
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
@ -75,7 +74,6 @@ public final class TestSubtotal extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAvg(){
|
public void testAvg(){
|
||||||
|
|
||||||
Workbook wb = new HSSFWorkbook();
|
Workbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
@ -95,16 +93,18 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(1,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(1,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(1,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(2.0, a3.getNumericCellValue());
|
assertEquals(2.0, a3.getNumericCellValue());
|
||||||
assertEquals(8.0, a6.getNumericCellValue());
|
assertEquals(8.0, a6.getNumericCellValue());
|
||||||
assertEquals(3.0, a7.getNumericCellValue());
|
assertEquals(3.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(3.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSum(){
|
public void testSum(){
|
||||||
|
|
||||||
Workbook wb = new HSSFWorkbook();
|
Workbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
@ -124,12 +124,15 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(9,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(9,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(9,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(4.0, a3.getNumericCellValue());
|
assertEquals(4.0, a3.getNumericCellValue());
|
||||||
assertEquals(26.0, a6.getNumericCellValue());
|
assertEquals(26.0, a6.getNumericCellValue());
|
||||||
assertEquals(12.0, a7.getNumericCellValue());
|
assertEquals(12.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(12.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCount(){
|
public void testCount(){
|
||||||
@ -147,18 +150,21 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a3.setCellFormula("SUBTOTAL(2,B2:B3)");
|
a3.setCellFormula("SUBTOTAL(2,B2:B3)");
|
||||||
Cell a4 = sh.createRow(4).createCell(1);
|
Cell a4 = sh.createRow(4).createCell(1);
|
||||||
a4.setCellValue("POI"); // A4 is string and not counted
|
a4.setCellValue("POI"); // A4 is string and not counted
|
||||||
Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
|
/*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||||
|
|
||||||
Cell a6 = sh.createRow(6).createCell(1);
|
Cell a6 = sh.createRow(6).createCell(1);
|
||||||
a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(2,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(2,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(2,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(2.0, a3.getNumericCellValue());
|
assertEquals(2.0, a3.getNumericCellValue());
|
||||||
assertEquals(6.0, a6.getNumericCellValue());
|
assertEquals(6.0, a6.getNumericCellValue());
|
||||||
assertEquals(2.0, a7.getNumericCellValue());
|
assertEquals(2.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(2.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCounta(){
|
public void testCounta(){
|
||||||
@ -176,18 +182,21 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a3.setCellFormula("SUBTOTAL(3,B2:B3)");
|
a3.setCellFormula("SUBTOTAL(3,B2:B3)");
|
||||||
Cell a4 = sh.createRow(4).createCell(1);
|
Cell a4 = sh.createRow(4).createCell(1);
|
||||||
a4.setCellValue("POI"); // A4 is string and not counted
|
a4.setCellValue("POI"); // A4 is string and not counted
|
||||||
Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
|
/*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||||
|
|
||||||
Cell a6 = sh.createRow(6).createCell(1);
|
Cell a6 = sh.createRow(6).createCell(1);
|
||||||
a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(3,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(3,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(3,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(2.0, a3.getNumericCellValue());
|
assertEquals(2.0, a3.getNumericCellValue());
|
||||||
assertEquals(8.0, a6.getNumericCellValue());
|
assertEquals(8.0, a6.getNumericCellValue());
|
||||||
assertEquals(3.0, a7.getNumericCellValue());
|
assertEquals(3.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(3.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMax(){
|
public void testMax(){
|
||||||
@ -211,12 +220,15 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(4,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(4,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(4,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(3.0, a3.getNumericCellValue());
|
assertEquals(3.0, a3.getNumericCellValue());
|
||||||
assertEquals(16.0, a6.getNumericCellValue());
|
assertEquals(16.0, a6.getNumericCellValue());
|
||||||
assertEquals(7.0, a7.getNumericCellValue());
|
assertEquals(7.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(7.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMin(){
|
public void testMin(){
|
||||||
@ -240,12 +252,15 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(5,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(5,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(5,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(1.0, a3.getNumericCellValue());
|
assertEquals(1.0, a3.getNumericCellValue());
|
||||||
assertEquals(4.0, a6.getNumericCellValue());
|
assertEquals(4.0, a6.getNumericCellValue());
|
||||||
assertEquals(1.0, a7.getNumericCellValue());
|
assertEquals(1.0, a7.getNumericCellValue());
|
||||||
|
assertEquals(1.0, a8.getNumericCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testStdev(){
|
public void testStdev(){
|
||||||
@ -269,12 +284,15 @@ public final class TestSubtotal extends TestCase {
|
|||||||
a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2");
|
a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2");
|
||||||
Cell a7 = sh.createRow(7).createCell(1);
|
Cell a7 = sh.createRow(7).createCell(1);
|
||||||
a7.setCellFormula("SUBTOTAL(7,B2:B7)");
|
a7.setCellFormula("SUBTOTAL(7,B2:B7)");
|
||||||
|
Cell a8 = sh.createRow(8).createCell(1);
|
||||||
|
a8.setCellFormula("SUBTOTAL(7,B2,B3,B4,B5,B6,B7,B8)");
|
||||||
|
|
||||||
fe.evaluateAll();
|
fe.evaluateAll();
|
||||||
|
|
||||||
assertEquals(1.41421, a3.getNumericCellValue(), 0.0001);
|
assertEquals(1.41421, a3.getNumericCellValue(), 0.0001);
|
||||||
assertEquals(7.65685, a6.getNumericCellValue(), 0.0001);
|
assertEquals(7.65685, a6.getNumericCellValue(), 0.0001);
|
||||||
assertEquals(2.82842, a7.getNumericCellValue(), 0.0001);
|
assertEquals(2.82842, a7.getNumericCellValue(), 0.0001);
|
||||||
|
assertEquals(2.82842, a8.getNumericCellValue(), 0.0001);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test50209(){
|
public void test50209(){
|
||||||
@ -328,4 +346,69 @@ public final class TestSubtotal extends TestCase {
|
|||||||
confirmExpectedResult(evaluator, "SUBTOTAL(COUNT;B2:B8,C2:C8)", cellC2, 3.0);
|
confirmExpectedResult(evaluator, "SUBTOTAL(COUNT;B2:B8,C2:C8)", cellC2, 3.0);
|
||||||
confirmExpectedResult(evaluator, "SUBTOTAL(COUNTA;B2:B8,C2:C8)", cellC3, 5.0);
|
confirmExpectedResult(evaluator, "SUBTOTAL(COUNTA;B2:B8,C2:C8)", cellC3, 5.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUnimplemented(){
|
||||||
|
Workbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
|
|
||||||
|
Sheet sh = wb.createSheet();
|
||||||
|
Cell a3 = sh.createRow(3).createCell(1);
|
||||||
|
a3.setCellFormula("SUBTOTAL(8,B2:B3)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
fe.evaluateAll();
|
||||||
|
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||||
|
} catch (NotImplementedException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
a3.setCellFormula("SUBTOTAL(10,B2:B3)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
fe.evaluateAll();
|
||||||
|
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||||
|
} catch (NotImplementedException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
a3.setCellFormula("SUBTOTAL(11,B2:B3)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
fe.evaluateAll();
|
||||||
|
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||||
|
} catch (NotImplementedException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
a3.setCellFormula("SUBTOTAL(107,B2:B3)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
fe.evaluateAll();
|
||||||
|
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||||
|
} catch (NotImplementedException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
a3.setCellFormula("SUBTOTAL(0,B2:B3)");
|
||||||
|
fe.evaluateAll();
|
||||||
|
assertEquals(FormulaError.VALUE.getCode(), a3.getErrorCellValue());
|
||||||
|
|
||||||
|
try {
|
||||||
|
a3.setCellFormula("SUBTOTAL(9)");
|
||||||
|
fail("Should catch an exception here");
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
a3.setCellFormula("SUBTOTAL()");
|
||||||
|
fail("Should catch an exception here");
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
Subtotal subtotal = new Subtotal();
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, subtotal.evaluate(new ValueEval[] {}, 0, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.eval.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
|
||||||
|
public class TestWeekdayFunc {
|
||||||
|
@Test
|
||||||
|
public void testEvaluate() throws Exception {
|
||||||
|
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(0.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
|
||||||
|
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateInvalid() throws Exception {
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0)}, 0, 0));
|
||||||
|
|
||||||
|
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(-1.0)}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("")}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("1"), new StringEval("")}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("2"), BlankEval.instance}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("3"), MissingArgEval.instance}, 0, 0));
|
||||||
|
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(18.0)}, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
@ -33,9 +33,12 @@ import java.awt.font.FontRenderContext;
|
|||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.font.TextLayout;
|
import java.awt.font.TextLayout;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
@ -1606,4 +1609,78 @@ public abstract class BaseTestBugzillaIssues {
|
|||||||
assertNull("Sheet0 after write", wb2.getPrintArea(0)); // CURRENTLY FAILS with "Sheet0!$A$1:$C$6"
|
assertNull("Sheet0 after write", wb2.getPrintArea(0)); // CURRENTLY FAILS with "Sheet0!$A$1:$C$6"
|
||||||
assertEquals("Sheet1 after write", "Sheet1!$A$1:$A$1", wb2.getPrintArea(1));
|
assertEquals("Sheet1 after write", "Sheet1!$A$1:$A$1", wb2.getPrintArea(1));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test55384() throws Exception {
|
||||||
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
|
try {
|
||||||
|
Sheet sh = wb.createSheet();
|
||||||
|
for (int rownum = 0; rownum < 10; rownum++) {
|
||||||
|
org.apache.poi.ss.usermodel.Row row = sh.createRow(rownum);
|
||||||
|
for (int cellnum = 0; cellnum < 3; cellnum++) {
|
||||||
|
Cell cell = row.createCell(cellnum);
|
||||||
|
cell.setCellValue(rownum + cellnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row row = sh.createRow(10);
|
||||||
|
// setting no precalculated value works just fine.
|
||||||
|
Cell cell1 = row.createCell(0);
|
||||||
|
cell1.setCellFormula("SUM(A1:A10)");
|
||||||
|
|
||||||
|
// but setting a precalculated STRING value fails totally in SXSSF
|
||||||
|
Cell cell2 = row.createCell(1);
|
||||||
|
cell2.setCellFormula("SUM(B1:B10)");
|
||||||
|
cell2.setCellValue("55");
|
||||||
|
|
||||||
|
// setting a precalculated int value works as expected
|
||||||
|
Cell cell3 = row.createCell(2);
|
||||||
|
cell3.setCellFormula("SUM(C1:C10)");
|
||||||
|
cell3.setCellValue(65);
|
||||||
|
|
||||||
|
assertEquals(CellType.FORMULA, cell1.getCellTypeEnum());
|
||||||
|
assertEquals(CellType.FORMULA, cell2.getCellTypeEnum());
|
||||||
|
assertEquals(CellType.FORMULA, cell3.getCellTypeEnum());
|
||||||
|
|
||||||
|
assertEquals("SUM(A1:A10)", cell1.getCellFormula());
|
||||||
|
assertEquals("SUM(B1:B10)", cell2.getCellFormula());
|
||||||
|
assertEquals("SUM(C1:C10)", cell3.getCellFormula());
|
||||||
|
|
||||||
|
/*String name = wb.getClass().getCanonicalName();
|
||||||
|
String ext = (wb instanceof HSSFWorkbook) ? ".xls" : ".xlsx";
|
||||||
|
OutputStream output = new FileOutputStream("/tmp" + name + ext);
|
||||||
|
try {
|
||||||
|
wb.write(output);
|
||||||
|
} finally {
|
||||||
|
output.close();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
Workbook wbBack = _testDataProvider.writeOutAndReadBack(wb);
|
||||||
|
checkFormulaPreevaluatedString(wbBack);
|
||||||
|
wbBack.close();
|
||||||
|
} finally {
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFormulaPreevaluatedString(Workbook readFile) {
|
||||||
|
Sheet sheet = readFile.getSheetAt(0);
|
||||||
|
Row row = sheet.getRow(sheet.getLastRowNum());
|
||||||
|
assertEquals(10, row.getRowNum());
|
||||||
|
|
||||||
|
for (Cell cell : row) {
|
||||||
|
String cellValue = null;
|
||||||
|
switch (cell.getCellTypeEnum()) {
|
||||||
|
case STRING:
|
||||||
|
cellValue = cell.getRichStringCellValue().getString();
|
||||||
|
break;
|
||||||
|
case FORMULA:
|
||||||
|
cellValue = cell.getCellFormula();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assertNotNull(cellValue);
|
||||||
|
cellValue = cellValue.isEmpty() ? null : cellValue;
|
||||||
|
assertNotNull(cellValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -201,11 +201,7 @@ public abstract class BaseTestNamedRange {
|
|||||||
assertEquals("The sheet already contains this name: aaa", e.getMessage());
|
assertEquals("The sheet already contains this name: aaa", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
int cnt = 0;
|
assertEquals(3, wb.getNames("aaa").size());
|
||||||
for (int i = 0; i < wb.getNumberOfNames(); i++) {
|
|
||||||
if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;
|
|
||||||
}
|
|
||||||
assertEquals(3, cnt);
|
|
||||||
|
|
||||||
wb.close();
|
wb.close();
|
||||||
}
|
}
|
||||||
@ -250,11 +246,11 @@ public abstract class BaseTestNamedRange {
|
|||||||
// Write the workbook to a file
|
// Write the workbook to a file
|
||||||
// Read the Excel file and verify its content
|
// Read the Excel file and verify its content
|
||||||
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
||||||
Name nm1 = wb2.getNameAt(wb2.getNameIndex("RangeTest1"));
|
Name nm1 = wb2.getName("RangeTest1");
|
||||||
assertTrue("Name is "+nm1.getNameName(),"RangeTest1".equals(nm1.getNameName()));
|
assertTrue("Name is "+nm1.getNameName(),"RangeTest1".equals(nm1.getNameName()));
|
||||||
assertTrue("Reference is "+nm1.getRefersToFormula(),(wb2.getSheetName(0)+"!$A$1:$L$41").equals(nm1.getRefersToFormula()));
|
assertTrue("Reference is "+nm1.getRefersToFormula(),(wb2.getSheetName(0)+"!$A$1:$L$41").equals(nm1.getRefersToFormula()));
|
||||||
|
|
||||||
Name nm2 = wb2.getNameAt(wb2.getNameIndex("RangeTest2"));
|
Name nm2 = wb2.getName("RangeTest2");
|
||||||
assertTrue("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName()));
|
assertTrue("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName()));
|
||||||
assertTrue("Reference is "+nm2.getRefersToFormula(),(wb2.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getRefersToFormula()));
|
assertTrue("Reference is "+nm2.getRefersToFormula(),(wb2.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getRefersToFormula()));
|
||||||
|
|
||||||
@ -466,11 +462,11 @@ public abstract class BaseTestNamedRange {
|
|||||||
wb1.getNameAt(0);
|
wb1.getNameAt(0);
|
||||||
|
|
||||||
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
||||||
Name nm =wb2.getNameAt(wb2.getNameIndex("RangeTest"));
|
Name nm =wb2.getName("RangeTest");
|
||||||
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName()));
|
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName()));
|
||||||
assertTrue("Reference is "+nm.getRefersToFormula(),(wb2.getSheetName(0)+"!$D$4:$E$8").equals(nm.getRefersToFormula()));
|
assertTrue("Reference is "+nm.getRefersToFormula(),(wb2.getSheetName(0)+"!$D$4:$E$8").equals(nm.getRefersToFormula()));
|
||||||
|
|
||||||
nm = wb2.getNameAt(wb2.getNameIndex("AnotherTest"));
|
nm = wb2.getName("AnotherTest");
|
||||||
assertTrue("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName()));
|
assertTrue("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName()));
|
||||||
assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula()));
|
assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula()));
|
||||||
|
|
||||||
@ -499,8 +495,7 @@ public abstract class BaseTestNamedRange {
|
|||||||
namedCell.setRefersToFormula(reference);
|
namedCell.setRefersToFormula(reference);
|
||||||
|
|
||||||
// retrieve the newly created named range
|
// retrieve the newly created named range
|
||||||
int namedCellIdx = wb.getNameIndex(cellName);
|
Name aNamedCell = wb.getName(cellName);
|
||||||
Name aNamedCell = wb.getNameAt(namedCellIdx);
|
|
||||||
assertNotNull(aNamedCell);
|
assertNotNull(aNamedCell);
|
||||||
|
|
||||||
// retrieve the cell at the named range and test its contents
|
// retrieve the cell at the named range and test its contents
|
||||||
@ -540,8 +535,7 @@ public abstract class BaseTestNamedRange {
|
|||||||
namedCell.setRefersToFormula(reference);
|
namedCell.setRefersToFormula(reference);
|
||||||
|
|
||||||
// retrieve the newly created named range
|
// retrieve the newly created named range
|
||||||
int namedCellIdx = wb.getNameIndex(cname);
|
Name aNamedCell = wb.getName(cname);
|
||||||
Name aNamedCell = wb.getNameAt(namedCellIdx);
|
|
||||||
assertNotNull(aNamedCell);
|
assertNotNull(aNamedCell);
|
||||||
|
|
||||||
// retrieve the cell at the named range and test its contents
|
// retrieve the cell at the named range and test its contents
|
||||||
|
@ -261,17 +261,17 @@ public abstract class BaseTestSheetShiftRows {
|
|||||||
name4.setSheetIndex(1);
|
name4.setSheetIndex(1);
|
||||||
|
|
||||||
sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1.
|
sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1.
|
||||||
name1 = wb.getNameAt(0);
|
name1 = wb.getName("name1");
|
||||||
assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula());
|
assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula());
|
||||||
|
|
||||||
name2 = wb.getNameAt(1);
|
name2 = wb.getName("name2");
|
||||||
assertEquals("Sheet1!$A$3", name2.getRefersToFormula());
|
assertEquals("Sheet1!$A$3", name2.getRefersToFormula());
|
||||||
|
|
||||||
//name3 and name4 refer to Sheet2 and should not be affected
|
//name3 and name4 refer to Sheet2 and should not be affected
|
||||||
name3 = wb.getNameAt(2);
|
name3 = wb.getName("name3");
|
||||||
assertEquals("Sheet2!$A$1", name3.getRefersToFormula());
|
assertEquals("Sheet2!$A$1", name3.getRefersToFormula());
|
||||||
|
|
||||||
name4 = wb.getNameAt(3);
|
name4 = wb.getName("name4");
|
||||||
assertEquals("A1", name4.getRefersToFormula());
|
assertEquals("A1", name4.getRefersToFormula());
|
||||||
|
|
||||||
wb.close();
|
wb.close();
|
||||||
|
@ -78,14 +78,16 @@ public class BaseTestCellUtil {
|
|||||||
@Test(expected=RuntimeException.class)
|
@Test(expected=RuntimeException.class)
|
||||||
public void setCellStylePropertyWithInvalidValue() throws IOException {
|
public void setCellStylePropertyWithInvalidValue() throws IOException {
|
||||||
Workbook wb = _testDataProvider.createWorkbook();
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
Sheet s = wb.createSheet();
|
try {
|
||||||
Row r = s.createRow(0);
|
Sheet s = wb.createSheet();
|
||||||
Cell c = r.createCell(0);
|
Row r = s.createRow(0);
|
||||||
|
Cell c = r.createCell(0);
|
||||||
|
|
||||||
// An invalid BorderStyle constant
|
// An invalid BorderStyle constant
|
||||||
CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
|
CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
|
||||||
|
} finally {
|
||||||
wb.close();
|
wb.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
@ -352,10 +354,8 @@ public class BaseTestCellUtil {
|
|||||||
CellUtil.setFont(A1, font2);
|
CellUtil.setFont(A1, font2);
|
||||||
fail("setFont not allowed if font belongs to a different workbook");
|
fail("setFont not allowed if font belongs to a different workbook");
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
if (e.getMessage().startsWith("Font does not belong to this workbook")) {
|
// one specific message is expected
|
||||||
// expected
|
if (!e.getMessage().startsWith("Font does not belong to this workbook")) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -371,7 +371,7 @@ public class BaseTestCellUtil {
|
|||||||
*/
|
*/
|
||||||
// bug 55555
|
// bug 55555
|
||||||
@Test
|
@Test
|
||||||
public void setFillForegroundColorBeforeFillBackgroundColor() {
|
public void setFillForegroundColorBeforeFillBackgroundColor() throws IOException {
|
||||||
Workbook wb1 = _testDataProvider.createWorkbook();
|
Workbook wb1 = _testDataProvider.createWorkbook();
|
||||||
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
@ -386,13 +386,14 @@ public class BaseTestCellUtil {
|
|||||||
assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern());
|
assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern());
|
||||||
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
||||||
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
||||||
|
wb1.close();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* bug 55555
|
* bug 55555
|
||||||
* @since POI 3.15 beta 3
|
* @since POI 3.15 beta 3
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void setFillForegroundColorBeforeFillBackgroundColorEnum() {
|
public void setFillForegroundColorBeforeFillBackgroundColorEnum() throws IOException {
|
||||||
Workbook wb1 = _testDataProvider.createWorkbook();
|
Workbook wb1 = _testDataProvider.createWorkbook();
|
||||||
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
@ -407,5 +408,7 @@ public class BaseTestCellUtil {
|
|||||||
assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum());
|
assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum());
|
||||||
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
||||||
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
||||||
|
|
||||||
|
wb1.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,16 +30,20 @@ public class DummyPOILogger extends POILogger {
|
|||||||
logged = new ArrayList<String>();
|
logged = new ArrayList<String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean check(int level) {
|
public boolean check(int level) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initialize(String cat) {}
|
public void initialize(String cat) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void log(int level, Object obj1) {
|
public void log(int level, Object obj1) {
|
||||||
logged.add(level + " - " + obj1);
|
logged.add(level + " - " + obj1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void log(int level, Object obj1, Throwable exception) {
|
public void log(int level, Object obj1, Throwable exception) {
|
||||||
logged.add(level + " - " + obj1 + " - " + exception);
|
logged.add(level + " - " + obj1 + " - " + exception);
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the log class.
|
* Tests the log class.
|
||||||
*
|
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
|
||||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
|
||||||
*/
|
*/
|
||||||
public final class TestPOILogger extends POILogger {
|
public final class TestPOILogger extends POILogger {
|
||||||
private String lastLog = "";
|
private String lastLog = "";
|
||||||
@ -61,20 +57,26 @@ public final class TestPOILogger extends POILogger {
|
|||||||
POILogFactory._loggerClassName = oldLCN;
|
POILogFactory._loggerClassName = oldLCN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- POI Logger methods implemented for testing ----------
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initialize(String cat) {
|
public void initialize(String cat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void log(int level, Object obj1) {
|
public void log(int level, Object obj1) {
|
||||||
lastLog = (obj1 == null) ? "" : obj1.toString();
|
lastLog = (obj1 == null) ? "" : obj1.toString();
|
||||||
lastEx = null;
|
lastEx = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void log(int level, Object obj1, Throwable exception) {
|
public void log(int level, Object obj1, Throwable exception) {
|
||||||
lastLog = (obj1 == null) ? "" : obj1.toString();
|
lastLog = (obj1 == null) ? "" : obj1.toString();
|
||||||
lastEx = exception;
|
lastEx = exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean check(int level) {
|
public boolean check(int level) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
BIN
test-data/spreadsheet/59736.xlsx
Normal file
BIN
test-data/spreadsheet/59736.xlsx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user