@@ -30,27 +43,17 @@
http://starter.io
-
- https://bitbucket.org/openxls/openxls
- scm:git:ssh://git@bitbucket.org/openxls/openxls.git
- master
-
-
-
- log4j
- log4j
-
-
- log4j
- log4j
- 1.2.16
-
+
org.json
json
- 20090211
+ 20180813
@@ -65,6 +68,17 @@
4.10
test
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-test
+ ${kotlin.version}
+ test
+
@@ -75,21 +89,7 @@
1.2.1
-
-
- false
- ${basedir}/src/main/resources
-
-
-
- true
- ${basedir}/src/main/resources
-
- io/starter/OpenXLS/build.properties
-
-
-
@@ -118,14 +118,22 @@
-
+
+ maven-surefire-plugin
+
+
+ ${exclude.tests}
+
+ alphabetical
+
+
org.apache.maven.plugins
maven-compiler-plugin
2.5.1
- 1.5
- 1.5
+ 1.8
+ 1.8
@@ -139,7 +147,7 @@
- com/extench/profiling/**/*
+ io/starter/profiling/**/*
**/*$*
@@ -148,10 +156,64 @@
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+ 1.8
+
+
+
+
+ false
+ ${basedir}/src/main/resources
+
+
+
+
+ true
+ ${basedir}/src/main/resources
+
+ io/starter/OpenXLS/build.properties
+
+
+
+
+
+ mac-profile
+
+ true
+
+ ${java.home}/../lib/tools.jar
+
+
+
+ ${java.home}/../lib/tools.jar
+
+
+
+
release
@@ -212,22 +274,30 @@
-
+
+
- repo.starter.io
+ snapshot.repo.starter.io
s3://repo.starter.io/snapshot
- repo.starter.io
+ release.repo.starter.io
s3://repo.starter.io/release
+
- repo.starter.io
+ snapshot.repo.starter.io
+ s3://repo.starter.io/snapshot
+
+
+ release.repo.starter.io
s3://repo.starter.io/release
+
+
diff --git a/src/main/java/io/starter/OpenXLS/AutoFilterHandle.java b/src/main/java/io/starter/OpenXLS/AutoFilterHandle.java
deleted file mode 100644
index 14e11d7..0000000
--- a/src/main/java/io/starter/OpenXLS/AutoFilterHandle.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import io.starter.formats.XLS.AutoFilter;
-
-/**
- * AutoFilterHandle allows for manipulation of the AutoFilters within the
- * Spreadsheet
- *
- * @author John McMahon
- *
- */
-public class AutoFilterHandle implements Handle {
- private AutoFilter af = null;
-
- /**
- * For internal use only. Creates an AutoFilter Handle based on the AutoFilter
- * passed in
- *
- * @param AutoFilter
- * af
- */
- protected AutoFilterHandle(AutoFilter af) {
- this.af = af;
- }
-
- /**
- * returns the string representation of this AutoFilter
- *
- * @return the string representation of this AutoFilter
- */
- @Override
- public String toString() {
- if (this.af != null)
- return af.toString();
- return "No AutoFilter";
- }
-
- /**
- * returns the column this AutoFilter is applied to
- * NOTE: this may not be 100% exact
- *
- * @return in column number
- */
- public int getCol() {
- if (this.af != null)
- return af.getCol();
- return -1;
- }
-
- /**
- * Sets the custom comparison of this AutoFilter via a String operator and an
- * Object value
- * Only those rows that meet the equation: (column value) OP value will be shown
- *
- * e.g show all rows where column value >= 2.99
- *
- * Object value can be of type
- *
- * String
- * Boolean
- * Error
- * a Number type object
- *
- * String operator may be one of: "=", ">", ">=", "<>", "<", "<="
- *
- * @param Object
- * val - value to set
- * @param String
- * op - operator
- * @see setVal2
- */
- public void setVal(Object val, String op) {
- if (af != null)
- af.setVal(val, op);
- }
-
- /**
- * Sets the custom comparison of the second condition of this AutoFilter via a
- * String operator and an Object value
- * This method sets the second condition of a two-condition filter
- *
- * Only those rows that meet the equation:
- * first condition AND/OR (column value) OP value will be shown
- * e.g show all rows where (column value) <= 1.99 AND (column value) >= 2.99
- *
- * Object value can be of type
- *
- * String
- * Boolean
- * Error
- * a Number type object
- *
- * String operator may be one of: "=", ">", ">=", "<>", "<", "<="
- *
- * @param Object
- * val - value to set
- * @param String
- * op - operator
- * @param boolean
- * AND - true if two conditions should be AND'ed, false if OR'd
- * @see setVal2
- */
- public void setVal2(Object val, String op, boolean AND) {
- if (af != null)
- af.setVal2(val, op, AND);
- }
-
- /**
- * returns the String representation of the comparison value for this
- * AutoFilter, if any
- *
- *
- * This will return the comparison value of the first condition for those
- * AutoFilters containing two conditions
- *
- * @return String comparison value for the second condition or null if none
- * exists
- * @see getVal2
- */
- public String getVal() {
- if (af != null)
- return (String) af.getVal();
- return null;
- }
-
- /**
- * returns the String representation of the second comparison value for this
- * AutoFilter, if any
- *
- *
- * This will return the comparison value of the second condition for those
- * AutoFilters containing two conditions
- *
- * @return String comparison value for the second condition or null if none
- * exists
- * @see getVal
- */
- public String getVal2() {
- if (af != null)
- return (String) af.getVal2();
- return null;
- }
-
- /**
- * get the operator associated with this AutoFilter
- * NOTE: this will return the operator in the first condition if this AutoFilter
- * contains two conditions
- * Use getOp2 to retrieve the second condition operator
- *
- * @return String operator
- */
- public String getOp() {
- if (af != null)
- return af.getOp();
- return null;
- }
-
- /**
- * Sets this AutoFilter to be a Top-n or Bottom-n type of filter
- * Top-n filters only show the Top n values or percent in the column
- * Bottom-n filters only show the bottom n values or percent in the column
- * n can be from 1-500, or 0 to turn off Top 10 filtering
- *
- * @param int
- * n - 0-500
- * @param boolean
- * percent - true if show Top-n percent; false to show Top-n items
- * @param boolean
- * top10 - true if show Top-n (items or percent), false to show
- * Bottom-n (items or percent)
- */
- public void setTop10(int n, boolean percent, boolean top10) {
- if (af != null)
- af.setTop10(n, percent, top10);
- }
-
- /**
- * returns true if this AutoFilter is set to Top-10
- * Top-n filters only show the Top n values or percent in the column
- *
- * @return
- */
- public boolean isTop10() {
- if (af != null)
- return af.isTop10();
- return false;
- }
-
- /**
- * sets this AutoFilter to filter all blank rows
- */
- public void setFilterBlanks() {
- if (af != null)
- af.setFilterBlanks();
- }
-
- /**
- * sets this AutoFilter to filter all non-blank rows
- */
- public void setFilterNonBlanks() {
- if (af != null)
- af.setFilterNonBlanks();
- }
-
- /**
- * returns true if this AutoFitler is set to filter all blank rows
- *
- * @return true if filter blanks, false otherwise
- */
- public boolean isFilterBlanks() {
- if (af != null)
- return af.isFilterBlanks();
- return false;
- }
-
- /**
- * returns true if this AutoFitler is set to filter all non-blank rows
- *
- * @return true if filter non-blanks, false otherwise
- */
- public boolean isFilterNonBlanks() {
- if (af != null)
- return af.isFilterNonBlanks();
- return false;
- }
-}
diff --git a/src/main/java/io/starter/OpenXLS/AutoFilterHandle.kt b/src/main/java/io/starter/OpenXLS/AutoFilterHandle.kt
new file mode 100644
index 0000000..2d49cc3
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/AutoFilterHandle.kt
@@ -0,0 +1,217 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.AutoFilter
+
+/**
+ * AutoFilterHandle allows for manipulation of the AutoFilters within the
+ * Spreadsheet
+ *
+ * @author John McMahon
+ */
+class AutoFilterHandle
+/**
+ * For internal use only. Creates an AutoFilter Handle based on the AutoFilter
+ * passed in
+ *
+ * @param AutoFilter af
+ */
+(af: AutoFilter) : Handle {
+ private val af: AutoFilter? = null
+
+ /**
+ * returns the column this AutoFilter is applied to
+ * NOTE: this may not be 100% exact
+ *
+ * @return in column number
+ */
+ val col: Int
+ get() = if (this.af != null) af.col else -1
+
+ /**
+ * returns the String representation of the comparison value for this
+ * AutoFilter, if any
+ *
+ *
+ * This will return the comparison value of the first condition for those
+ * AutoFilters containing two conditions
+ *
+ * @return String comparison value for the second condition or null if none
+ * exists
+ * @see getVal2
+ */
+ val `val`: String?
+ get() = if (af != null) af.`val` as String else null
+
+ /**
+ * returns the String representation of the second comparison value for this
+ * AutoFilter, if any
+ *
+ *
+ * This will return the comparison value of the second condition for those
+ * AutoFilters containing two conditions
+ *
+ * @return String comparison value for the second condition or null if none
+ * exists
+ * @see getVal
+ */
+ val val2: String?
+ get() = if (af != null) af.val2 as String else null
+
+ /**
+ * get the operator associated with this AutoFilter
+ * NOTE: this will return the operator in the first condition if this AutoFilter
+ * contains two conditions
+ * Use getOp2 to retrieve the second condition operator
+ *
+ * @return String operator
+ */
+ val op: String?
+ get() = af?.op
+
+ /**
+ * returns true if this AutoFilter is set to Top-10
+ * Top-n filters only show the Top n values or percent in the column
+ *
+ * @return
+ */
+ val isTop10: Boolean
+ get() = af?.isTop10 ?: false
+
+ /**
+ * returns true if this AutoFitler is set to filter all blank rows
+ *
+ * @return true if filter blanks, false otherwise
+ */
+ val isFilterBlanks: Boolean
+ get() = af?.isFilterBlanks ?: false
+
+ /**
+ * returns true if this AutoFitler is set to filter all non-blank rows
+ *
+ * @return true if filter non-blanks, false otherwise
+ */
+ val isFilterNonBlanks: Boolean
+ get() = af?.isFilterNonBlanks ?: false
+
+ init {
+ this.af = af
+ }
+
+ /**
+ * returns the string representation of this AutoFilter
+ *
+ * @return the string representation of this AutoFilter
+ */
+ override fun toString(): String {
+ return if (this.af != null) af.toString() else "No AutoFilter"
+ }
+
+ /**
+ * Sets the custom comparison of this AutoFilter via a String operator and an
+ * Object value
+ * Only those rows that meet the equation: (column value) OP value will be shown
+ *
+ * e.g show all rows where column value >= 2.99
+ *
+ *
+ * Object value can be of type
+ *
+ *
+ * String
+ * Boolean
+ * Error
+ * a Number type object
+ *
+ *
+ * String operator may be one of: "=", ">", ">=", "<>", "<", "<="
+ *
+ * @param Object val - value to set
+ * @param String op - operator
+ * @see setVal2
+ */
+ fun setVal(`val`: Any, op: String) {
+ af?.setVal(`val`, op)
+ }
+
+ /**
+ * Sets the custom comparison of the second condition of this AutoFilter via a
+ * String operator and an Object value
+ * This method sets the second condition of a two-condition filter
+ *
+ *
+ * Only those rows that meet the equation:
+ * first condition AND/OR (column value) OP value will be shown
+ * e.g show all rows where (column value) <= 1.99 AND (column value) >= 2.99
+ *
+ *
+ * Object value can be of type
+ *
+ *
+ * String
+ * Boolean
+ * Error
+ * a Number type object
+ *
+ *
+ * String operator may be one of: "=", ">", ">=", "<>", "<", "<="
+ *
+ * @param Object val - value to set
+ * @param String op - operator
+ * @param boolean AND - true if two conditions should be AND'ed, false if OR'd
+ * @see setVal2
+ */
+ fun setVal2(`val`: Any, op: String, AND: Boolean) {
+ af?.setVal2(`val`, op, AND)
+ }
+
+ /**
+ * Sets this AutoFilter to be a Top-n or Bottom-n type of filter
+ * Top-n filters only show the Top n values or percent in the column
+ * Bottom-n filters only show the bottom n values or percent in the column
+ * n can be from 1-500, or 0 to turn off Top 10 filtering
+ *
+ * @param int n - 0-500
+ * @param boolean percent - true if show Top-n percent; false to show Top-n items
+ * @param boolean top10 - true if show Top-n (items or percent), false to show
+ * Bottom-n (items or percent)
+ */
+ fun setTop10(n: Int, percent: Boolean, top10: Boolean) {
+ af?.setTop10(n, percent, top10)
+ }
+
+ /**
+ * sets this AutoFilter to filter all blank rows
+ */
+ fun setFilterBlanks() {
+ af?.setFilterBlanks()
+ }
+
+ /**
+ * sets this AutoFilter to filter all non-blank rows
+ */
+ fun setFilterNonBlanks() {
+ af?.setFilterNonBlanks()
+ }
+}
diff --git a/src/main/java/io/starter/OpenXLS/Cell.java b/src/main/java/io/starter/OpenXLS/Cell.java
deleted file mode 100644
index b68e53e..0000000
--- a/src/main/java/io/starter/OpenXLS/Cell.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-/**
- * A lightweight subset of Cell methods allowing for low memory overhead
- * streaming implementations
- *
- * @author John McMahon
- *
- */
-public interface Cell {
-
- /**
- * Cell types
- */
- public static final int TYPE_BLANK = -1;
- public static final int TYPE_STRING = 0;
- public static final int TYPE_FP = 1;
- public static final int TYPE_INT = 2;
- public static final int TYPE_FORMULA = 3;
- public static final int TYPE_BOOLEAN = 4;
- public static final int TYPE_DOUBLE = 5;
-
- public boolean isDate();
-
- public int getCellType();
-
- /**
- * Returns the Formatting record ID (FormatId) for this Cell
- * This can be used with 'setFormatId(int i)' to copy the formatting from one
- * Cell to another (e.g. a template cell to a new cell)
- *
- * @return int the FormatId for this Cell
- *
- */
- public int getFormatId();
-
- /**
- * Returns the value of this Cell in the native underlying data type.
- *
- * Formula cells will return the calculated value of the formula in the
- * calculated data type.
- *
- * Use 'getStringVal()' to return a String regardless of underlying value type.
- *
- * @return Object value for this Cell
- */
- public Object getVal();
-
- /**
- * Returns the value of the Cell as a String with formatting pattern applied..
- *
- * see: http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html
- *
- * boolean Cell types will return "true" or "false"
- * Negative numbers that are formatted in excel to show as red values rather
- * than using a "-" will return with a minus symbol.
- *
- * @return String the formatted value of the Cell
- */
- public String getFormattedStringVal();
-
- /**
- * Returns the column number of this Cell.
- *
- * @return int the Column Number of the Cell
- */
- public int getColNum();
-
- /**
- * Returns the row number of this Cell.
- *
- * NOTE: This is the 1-based row number such as you will see in a spreadsheet
- * UI.
- *
- * ie: A1 = row 1
- *
- *
- * @return int the ONE-based Row Number of the Cell
- */
- public int getRowNum();
-
- /**
- * Returns the Address of this Cell as a String.
- *
- * @return String the address of this Cell in the WorkSheet
- */
- public String getCellAddress();
-
- /**
- * Returns the name of this Cell's WorkSheet as a String.
- *
- * @return String the name this Cell's WorkSheet
- */
- public String getWorkSheetName();
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/Cell.kt b/src/main/java/io/starter/OpenXLS/Cell.kt
new file mode 100644
index 0000000..eaa3980
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/Cell.kt
@@ -0,0 +1,122 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+/**
+ * A lightweight subset of Cell methods allowing for low memory overhead
+ * streaming implementations
+ *
+ * @author John McMahon
+ */
+interface Cell {
+
+ val isDate: Boolean
+
+ val cellType: Int
+
+ /**
+ * Returns the Formatting record ID (FormatId) for this Cell
+ * This can be used with 'setFormatId(int i)' to copy the formatting from one
+ * Cell to another (e.g. a template cell to a new cell)
+ *
+ * @return int the FormatId for this Cell
+ */
+ val formatId: Int
+
+ /**
+ * Returns the value of this Cell in the native underlying data type.
+ *
+ *
+ * Formula cells will return the calculated value of the formula in the
+ * calculated data type.
+ *
+ *
+ * Use 'getStringVal()' to return a String regardless of underlying value type.
+ *
+ * @return Object value for this Cell
+ */
+ val `val`: Any
+
+ /**
+ * Returns the value of the Cell as a String with formatting pattern applied..
+ *
+ * see: [http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html](tutorial)
+ *
+ * boolean Cell types will return "true" or "false"
+ * Negative numbers that are formatted in excel to show as red values rather
+ * than using a "-" will return with a minus symbol.
+ *
+ * @return String the formatted value of the Cell
+ */
+ val formattedStringVal: String
+
+ /**
+ * Returns the column number of this Cell.
+ *
+ * @return int the Column Number of the Cell
+ */
+ val colNum: Int
+
+ /**
+ * Returns the row number of this Cell.
+ *
+ *
+ * NOTE: This is the 1-based row number such as you will see in a spreadsheet
+ * UI.
+ *
+ *
+ * ie: A1 = row 1
+ *
+ * @return int the ONE-based Row Number of the Cell
+ */
+ val rowNum: Int
+
+ /**
+ * Returns the Address of this Cell as a String.
+ *
+ * @return String the address of this Cell in the WorkSheet
+ */
+ val cellAddress: String
+
+ /**
+ * Returns the name of this Cell's WorkSheet as a String.
+ *
+ * @return String the name this Cell's WorkSheet
+ */
+ val workSheetName: String
+
+ companion object {
+
+ /**
+ * Cell types
+ */
+ val TYPE_BLANK = -1
+ val TYPE_STRING = 0
+ val TYPE_FP = 1
+ val TYPE_INT = 2
+ val TYPE_FORMULA = 3
+ val TYPE_BOOLEAN = 4
+ val TYPE_DOUBLE = 5
+ }
+
+}
diff --git a/src/main/java/io/starter/OpenXLS/CellComparator.java b/src/main/java/io/starter/OpenXLS/CellComparator.java
deleted file mode 100644
index 3e57121..0000000
--- a/src/main/java/io/starter/OpenXLS/CellComparator.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.util.Comparator;
-
-import io.starter.formats.XLS.FormulaNotFoundException;
-
-/**
- * CellComparitor is a implementation of a comparitor for sorting cell values.
- * In this instance numeric values (whether from a cell or a formula result) are
- * sorted before any string values.
- *
- * Date values are sorted according to their internal date representation. Note
- * that currently this means Dates will always sort above strings due to them
- * storing their value as a long.
- *
- * Starter Inc.
- *
- */
-public class CellComparator implements Comparator {
-
- /**
- * Compare 2 cellHandle classes
- *
- * This method handles comparisons of cells, note that formula results are used
- * rather than formula strings, Numbers are sorted ahead of string values. Dates
- * are stored as numbers internally in excel so are sorted against numbers
- *
- */
- public int compare(Object cellHandle1, Object cellHandle2) {
- CellHandle cell1 = (CellHandle) cellHandle1;
- CellHandle cell2 = (CellHandle) cellHandle2;
-
- int cellType1 = cell1.getCellType();
- int cellType2 = cell1.getCellType();
-
- // numerics - possibly break out more to see if values are floating point or
- // not.
- // would help for equality, which is likely never reached here.
- if (cell1.isNumber() && cell2.isNumber()) {
- if (cell1.getDoubleVal() > cell2.getDoubleVal())
- return 1;
- if (cell1.getDoubleVal() < cell2.getDoubleVal())
- return -1;
- return 0;
- } else if (cell1.isNumber()) {// get formula value if exists and is a numeric value
- if (cellType2 == CellHandle.TYPE_FORMULA) {
- FormulaHandle f = null;
- try {
- f = cell2.getFormulaHandle();
- } catch (FormulaNotFoundException e) {
- }
- Double d = f.getDoubleVal();
- if (!(d == Double.NaN)) {
- if (cell1.getDoubleVal() > d)
- return 1;
- if (cell1.getDoubleVal() < d)
- return -1;
- return 0;
- }
- } else {
- return 1;
- }
- } else if (cell2.isNumber()) {
- if (cellType1 == CellHandle.TYPE_FORMULA) {
- FormulaHandle f = null;
- try {
- f = cell1.getFormulaHandle();
- } catch (FormulaNotFoundException e) {
- }
- Double d = f.getDoubleVal();
- if (!(d == Double.NaN)) {
- if (cell2.getDoubleVal() < d)
- return 1;
- if (cell2.getDoubleVal() > d)
- return -1;
- return 0;
- }
- } else {
- return -1;
- }
- }
-
- // Two formulas;
- if (cellType1 == CellHandle.TYPE_FORMULA && cellType2 == CellHandle.TYPE_FORMULA) {
- try {
- FormulaHandle f1 = cell1.getFormulaHandle();
- FormulaHandle f2 = cell2.getFormulaHandle();
- double d1 = f1.getDoubleVal();
- double d2 = f2.getDoubleVal();
- if (!(d1 == Double.NaN) && !(d2 == Double.NaN)) {
- if (d1 > d2)
- return 1;
- if (d1 < d2)
- return -1;
- return 0;
- } else if (!(d1 == Double.NaN)) {
- return 1;
- } else if (!(d2 == Double.NaN)) {
- return -1;
- }
- } catch (FormulaNotFoundException e) {
- }
- }
-
- // Strings, the last choice
- String val1 = cell1.getStringVal();
- String val2 = cell2.getStringVal();
- return val1.compareTo(val2);
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/CellComparator.kt b/src/main/java/io/starter/OpenXLS/CellComparator.kt
new file mode 100644
index 0000000..5bacbf4
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/CellComparator.kt
@@ -0,0 +1,128 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.FormulaNotFoundException
+
+import java.util.Comparator
+
+/**
+ * CellComparitor is a implementation of a comparitor for sorting cell values.
+ * In this instance numeric values (whether from a cell or a formula result) are
+ * sorted before any string values.
+ *
+ *
+ * Date values are sorted according to their internal date representation. Note
+ * that currently this means Dates will always sort above strings due to them
+ * storing their value as a long.
+ *
+ * [Starter Inc.](http://starter.io)
+ */
+class CellComparator : Comparator {
+
+ /**
+ * Compare 2 cellHandle classes
+ *
+ *
+ * This method handles comparisons of cells, note that formula results are used
+ * rather than formula strings, Numbers are sorted ahead of string values. Dates
+ * are stored as numbers internally in excel so are sorted against numbers
+ */
+ override fun compare(cellHandle1: Any, cellHandle2: Any): Int {
+ val cell1 = cellHandle1 as CellHandle
+ val cell2 = cellHandle2 as CellHandle
+
+ val cellType1 = cell1.cellType
+ val cellType2 = cell1.cellType
+
+ // numerics - possibly break out more to see if values are floating point or
+ // not.
+ // would help for equality, which is likely never reached here.
+ if (cell1.isNumber && cell2.isNumber) {
+ if (cell1.doubleVal > cell2.doubleVal)
+ return 1
+ return if (cell1.doubleVal < cell2.doubleVal) -1 else 0
+ } else if (cell1.isNumber) {// get formula value if exists and is a numeric value
+ if (cellType2 == CellHandle.TYPE_FORMULA) {
+ var f: FormulaHandle? = null
+ try {
+ f = cell2.formulaHandle
+ } catch (e: FormulaNotFoundException) {
+ }
+
+ val d = f!!.doubleVal
+ if (d != java.lang.Double.NaN) {
+ if (cell1.doubleVal > d)
+ return 1
+ return if (cell1.doubleVal < d) -1 else 0
+ }
+ } else {
+ return 1
+ }
+ } else if (cell2.isNumber) {
+ if (cellType1 == CellHandle.TYPE_FORMULA) {
+ var f: FormulaHandle? = null
+ try {
+ f = cell1.formulaHandle
+ } catch (e: FormulaNotFoundException) {
+ }
+
+ val d = f!!.doubleVal
+ if (d != java.lang.Double.NaN) {
+ if (cell2.doubleVal < d)
+ return 1
+ return if (cell2.doubleVal > d) -1 else 0
+ }
+ } else {
+ return -1
+ }
+ }
+
+ // Two formulas;
+ if (cellType1 == CellHandle.TYPE_FORMULA && cellType2 == CellHandle.TYPE_FORMULA) {
+ try {
+ val f1 = cell1.formulaHandle
+ val f2 = cell2.formulaHandle
+ val d1 = f1.doubleVal
+ val d2 = f2.doubleVal
+ if (d1 != java.lang.Double.NaN && d2 != java.lang.Double.NaN) {
+ if (d1 > d2)
+ return 1
+ return if (d1 < d2) -1 else 0
+ } else if (d1 != java.lang.Double.NaN) {
+ return 1
+ } else if (d2 != java.lang.Double.NaN) {
+ return -1
+ }
+ } catch (e: FormulaNotFoundException) {
+ }
+
+ }
+
+ // Strings, the last choice
+ val val1 = cell1.stringVal
+ val val2 = cell2.stringVal
+ return val1!!.compareTo(val2!!)
+ }
+
+}
diff --git a/src/main/java/io/starter/OpenXLS/CellHandle.java b/src/main/java/io/starter/OpenXLS/CellHandle.java
deleted file mode 100644
index b89f64e..0000000
--- a/src/main/java/io/starter/OpenXLS/CellHandle.java
+++ /dev/null
@@ -1,3066 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import static io.starter.OpenXLS.JSONConstants.JSON_CELL_FORMATTED_VALUE;
-import static io.starter.OpenXLS.JSONConstants.JSON_CELL_FORMULA;
-import static io.starter.OpenXLS.JSONConstants.JSON_CELL_VALUE;
-import static io.starter.OpenXLS.JSONConstants.JSON_DATA;
-import static io.starter.OpenXLS.JSONConstants.JSON_DATETIME;
-import static io.starter.OpenXLS.JSONConstants.JSON_DOUBLE;
-import static io.starter.OpenXLS.JSONConstants.JSON_FLOAT;
-import static io.starter.OpenXLS.JSONConstants.JSON_FORMULA_HIDDEN;
-import static io.starter.OpenXLS.JSONConstants.JSON_HIDDEN;
-import static io.starter.OpenXLS.JSONConstants.JSON_HREF;
-import static io.starter.OpenXLS.JSONConstants.JSON_INTEGER;
-import static io.starter.OpenXLS.JSONConstants.JSON_LOCATION;
-import static io.starter.OpenXLS.JSONConstants.JSON_LOCKED;
-import static io.starter.OpenXLS.JSONConstants.JSON_MERGEACROSS;
-import static io.starter.OpenXLS.JSONConstants.JSON_MERGECHILD;
-import static io.starter.OpenXLS.JSONConstants.JSON_MERGEDOWN;
-import static io.starter.OpenXLS.JSONConstants.JSON_MERGEPARENT;
-import static io.starter.OpenXLS.JSONConstants.JSON_RED_FORMAT;
-import static io.starter.OpenXLS.JSONConstants.JSON_STRING;
-import static io.starter.OpenXLS.JSONConstants.JSON_STYLEID;
-import static io.starter.OpenXLS.JSONConstants.JSON_TEXT_ALIGN;
-import static io.starter.OpenXLS.JSONConstants.JSON_TYPE;
-import static io.starter.OpenXLS.JSONConstants.JSON_VALIDATION_MESSAGE;
-import static io.starter.OpenXLS.JSONConstants.JSON_WORD_WRAP;
-
-import java.awt.Color;
-import java.awt.font.TextAttribute;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Stack;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import io.starter.formats.XLS.BiffRec;
-import io.starter.formats.XLS.Blank;
-import io.starter.formats.XLS.Boolerr;
-import io.starter.formats.XLS.Boundsheet;
-import io.starter.formats.XLS.CellNotFoundException;
-import io.starter.formats.XLS.CellPositionConflictException;
-import io.starter.formats.XLS.CellTypeMismatchException;
-import io.starter.formats.XLS.Cf;
-import io.starter.formats.XLS.ColumnNotFoundException;
-import io.starter.formats.XLS.Condfmt;
-import io.starter.formats.XLS.Font;
-import io.starter.formats.XLS.FormatConstantsImpl;
-import io.starter.formats.XLS.Formula;
-import io.starter.formats.XLS.FormulaNotFoundException;
-import io.starter.formats.XLS.FunctionNotSupportedException;
-import io.starter.formats.XLS.Hlink;
-import io.starter.formats.XLS.Labelsst;
-import io.starter.formats.XLS.Mulblank;
-import io.starter.formats.XLS.Note;
-import io.starter.formats.XLS.NumberRec;
-import io.starter.formats.XLS.ReferenceTracker;
-import io.starter.formats.XLS.Rk;
-import io.starter.formats.XLS.Unicodestring;
-import io.starter.formats.XLS.XLSConstants;
-import io.starter.formats.XLS.XLSRecord;
-import io.starter.formats.XLS.Xf;
-import io.starter.formats.XLS.charts.Ai;
-import io.starter.formats.XLS.formulas.Ptg;
-import io.starter.formats.XLS.formulas.PtgRef;
-import io.starter.formats.cellformat.CellFormatFactory;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.StringTool;
-
-/**
- * The CellHandle provides a handle to an XLS Cell and its values.
- * Use the CellHandle to work with individual Cells in an XLS file.
- * To instantiate a CellHandle, you must first have a valid WorkSheetHandle,
- * which in turn requires a valid WorkBookHandle.
- *
- * for example:
- *
- * WorkBookHandle book = newWorkBookHandle("testxls.xls");
- * WorkSheetHandle sheet1 = book.getWorkSheet("Sheet1");
- * CellHandlecell = sheet1.getCell("B22");
- *
- *
- * With a CellHandle you can:
- *
- * - get the value of a Cell
- * - set the value of a Cell
- * - change the color, font, and background formatting of a Cell
- * - change the formatting pattern of a Cell
- * - change the value of a Cell
- * - get a handle to any Formula for this Cell
- *
- *
- * Starter Inc.
- *
- * @see WorkBookHandle
- * @see WorkSheetHandle
- * @see FormulaHandle
- * @see CellNotFoundException
- * @see CellTypeMismatchException
- */
-public class CellHandle implements Cell, Serializable, Handle, Comparable {
-
- /**
- *
- *
- */
- private static final long serialVersionUID = 4737120893891570607L;
- /**
- * Cell types
- */
- public static final int TYPE_BLANK = Cell.TYPE_BLANK;
- public static final int TYPE_STRING = Cell.TYPE_STRING;
- public static final int TYPE_FP = Cell.TYPE_FP;
- public static final int TYPE_INT = Cell.TYPE_INT;
- public static final int TYPE_FORMULA = Cell.TYPE_FORMULA;
- public static final int TYPE_BOOLEAN = Cell.TYPE_BOOLEAN;
- public static final int TYPE_DOUBLE = Cell.TYPE_DOUBLE;
- public static final int NOTATION_STANDARD = 0, NOTATION_SCIENTIFIC = 1, NOTATION_SCIENTIFIC_EXCEL = 2;
-
- private transient WorkBook wbh = null;
- private transient WorkSheetHandle wsh = null;
- private ColHandle mycol;
- private RowHandle myrow;
- private FormatHandle formatter;
- // reusing or creating new xfs is handled in FormatHandle/cloneXf and
- // updateXf
- // boolean useExistingXF = !false;
- private boolean DEBUG = false;
- private XLSRecord mycell;
-
- /**
- * returns the underlying BIFF8 record for the Cell
- * NOTE: the underlying record is not a part of the public API and may change at
- * any time.
- *
- * @return Returns the underlying biff record.
- */
- public XLSRecord getRecord() {
- return mycell;
- }
-
- /**
- * sets the underlying BIFF8 record for the Cell
- * NOTE: the underlying record is not a part of the public API and may change at
- * any time.
- *
- * @param XLSRecord
- * rec - The BIFF record to set.
- */
- public void setRecord(XLSRecord rec) {
- this.mycell = rec;
- }
-
- /**
- * Public Constructor added for use in Bean-context ONLY.
- *
- * Do NOT create CellHandles manually.
- */
- public CellHandle(BiffRec c) {
- mycell = (XLSRecord) c;
- }
-
- /**
- * if this cellhandle refers to a mulblank, ensure internal mulblank properties
- * are set to appropriate cell in the mulblank range
- */
- private void setMulblank() {
- if (mycell.getOpcode() == XLSConstants.MULBLANK) {
- if (mulblankcolnum == -1) { // init
- mulblankcolnum = ((Mulblank) mycell).getColNumber();
- ((Mulblank) mycell).setCurrentCell(mulblankcolnum);
- ((Mulblank) mycell).getIxfe(); // ensure myxf is set to correct
- // xf for the given cell in the
- // set of mulblanks
- } else if (mulblankcolnum != mycell.getColNumber()) {
- ((Mulblank) mycell).setCurrentCell(mulblankcolnum);
- ((Mulblank) mycell).getIxfe(); // ensure myxf is set to correct
- // xf for the given cell in the
- // set of mulblanks
- }
- this.formatter = null;
- }
- }
-
- /**
- * Public Constructor added for use in Bean-context ONLY.
- *
- * Do NOT create CellHandles manually.
- */
- public CellHandle(BiffRec c, WorkBook myb) {
- mycell = (XLSRecord) c;
- setMulblank();
- this.wbh = myb;
- }
-
- /**
- * Get a FormatHandle (a Format Object describing the formats for this Cell)
- * referenced by this CellHandle.
- *
- * @return FormatHandle
- * @see FormatHandle
- */
- void setFormatHandle() {
- setMulblank();
- if (formatter != null && formatter.getFormatId() == this.mycell.getIxfe()) {
- return;
- }
- // reusing or creating new xfs is handled in FormatHandle/cloneXf and
- // updateXf
- if (this.mycell.getXfRec() != null) {
- formatter = new FormatHandle(this.wbh, this.mycell.myxf);
- } else {// should ever happen now?
- // useExistingXF = false;
- if (wbh == null && this.mycell.getWorkBook() != null)
- formatter = new FormatHandle(this.mycell.getWorkBook(), -1);
- else
- formatter = new FormatHandle(this.wbh, -1);
- }
- formatter.addCell(mycell);
- }
-
- /**
- * Sets a default "empty" value appropriate for the cell type of this CellHandle
- *
- * For example, will set the value to 0.0 for TYPE_DOUBLE, an empty String for
- * TYPE_BLANK
- **/
- public void setToDefault() {
- setVal(this.getDefaultVal());
- }
-
- /**
- * Get the default "empty" data value for this CellHandle
- *
- * @return Object a default empty value corresponding to the cell type
- * such as 0.0 for TYPE_DOUBLE or an empty String for TYPE_BLANK
- **/
- public Object getDefaultVal() {
- return mycell.getDefaultVal();
- }
-
- /**
- * Sets the number format pattern for this cell. All Excel built-in number
- * formats are supported. Custom formats will not be applied by OpenXLS (e.g.
- * the {@link #getFormattedStringVal} method) but they will be written correctly
- * to the output file. For more information on number format patterns see
- * Microsoft KB264372 .
- *
- * @param pat
- * the Excel number format pattern to apply
- * @see FormatConstantsImpl#getBuiltinFormats
- */
- public void setFormatPattern(String pat) {
- setFormatHandle();
- formatter.setFormatPattern(pat);
- }
-
- /**
- * Gets the number format pattern for this cell, if set. For more information on
- * number format patterns see
- * Microsoft KB264372 .
- *
- * @return the Excel number format pattern for this cell or null if
- * none is applied
- */
- public String getFormatPattern() {
- if (this.getFont() == null)
- return "";
- return mycell.getFormatPattern();
- }
-
- /**
- * Returns whether this Cell has Date formatting applied.
- * NOTE: This does not guarantee that the value is a valid date.
- *
- * @return boolean true if this Cell has a Date Format applied
- */
- public boolean isDate() {
- if (mycell.myxf == null)
- return false;
- if (mycell.isString)
- return false;
- if (mycell.isBoolean)
- return false;
- if (mycell.isBlank)
- return false;
- return mycell.myxf.isDatePattern();
- }
-
- /** Returns whether this cell is a formula. */
- public boolean isFormula() {
- return mycell.isFormula();
- }
-
- /**
- * Returns whether the formula for the Cell is hidden
- *
- * @return boolean true if formula is hidden
- */
- public boolean isFormulaHidden() {
- return this.getFormatHandle().isFormulaHidden();
- }
-
- /**
- * returns whether this Cell is locked for editing
- *
- * @return boolean true if the cell is locked
- */
- public boolean isLocked() {
- return this.getFormatHandle().isLocked();
- }
-
- /**
- * Returns whether this is a blank cell.
- *
- * @return true if this cell is blank
- */
- public boolean isBlank() {
- return this.mycell.isBlank;
- }
-
- /**
- * Returns whether this Cell has a Currency format applied.
- *
- * @return boolean true if this Cell has a Currency format applied
- */
- public boolean isCurrency() {
- if (mycell.myxf == null)
- return false;
- return mycell.myxf.isCurrencyPattern();
- }
-
- /**
- * Returns whether this Cell has a numeric value
- *
- * @return boolean true if this Cell contains a numeric value
- */
- public boolean isNumber() {
- return this.mycell.isNumber();
- }
-
- /**
- * change the size (in points) of the Font used by this Cell and all other Cells
- * sharing this FormatId.
- * NOTE: To add an entirely new Font use the setFont(String fn, int typ, int sz)
- * method instead.
- *
- * @param int
- * sz - Font size in Points.
- */
- public void setFontSize(int sz) {
- setFormatHandle();
- sz *= 20; // excel size is 1/20 pt.
- formatter.setFontHeight(sz);
- }
-
- /**
- * change the weight (boldness) of the Font used by this Cell.
- * Some examples:
- * a weight of 200 is normal
- * a weight of 700 is bold
- *
- * @param int
- * wt - Font weight range between 100-1000
- */
- public void setFontWeight(int wt) {
- setFormatHandle();
- formatter.setFontWeight(wt);
- }
-
- /**
- * Convenience method for toggling the bold state of the Font used by this Cell.
- *
- * @param boolean
- * bold - true if bold
- */
- public void setBold(boolean bold) {
- setFormatHandle();
- formatter.setBold(bold);
- }
-
- /**
- * get the weight (boldness) of the Font used by this Cell.
- *
- * @return int Font weight range between 100-1000
- */
- public int getFontWeight() {
- if (this.getFont() == null)
- return FormatHandle.DEFAULT_FONT_WEIGHT;
- return mycell.getFont().getFontWeight();
- }
-
- /**
- * get the size in points of the Font used by this Cell
- *
- * @return int Font size in Points.
- */
- public int getFontSize() {
- if (this.getFont() == null)
- return FormatHandle.DEFAULT_FONT_SIZE;
- return mycell.getFont().getFontHeight() / 20;
- }
-
- /**
- * get the Color of the Font used by this Cell.
- *
- * @see FormatHandle.COLOR constants
- * @return int Excel color constant for Font color
- */
- public Color getFontColor() {
- if (this.getFont() == null)
- return FormatHandle.Black;
- int clidx = this.getFont().getColor();
-
- // handle white on white text issue
- Xf x = mycell.getXfRec();
- int clidb = x.getBackgroundColor();
- if (clidx == 64 && clidb == 64) { // return black
- return FormatHandle.Black;
- }
- // black on black
- if (clidx < this.getWorkBook().getColorTable().length) {
- Color mycolr = this.getWorkBook().getColorTable()[clidx];
- return mycolr;
- }
- return Color.black;
- }
-
- /**
- * Set the color of the Font used by this Cell.
- *
- * @param java
- * .Awt.Color col - color of the font
- */
- public void setFontColor(Color col) {
- setFormatHandle();
- formatter.setFontColor(col);
- }
-
- /**
- * set the Foreground Color for this Cell.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param int
- * t - Excel color constant
- * @see FormatHandle.COLOR constants
- */
- public void setForegroundColor(int t) {
- setFormatHandle();
- formatter.setForegroundColor(t);
- }
-
- /**
- * set the Foreground Color for this Cell
- * NOTE: this is the PATTERN Color
- *
- * @param int
- * Excel color constant
- * @see FormatHandle.COLOR constants
- */
- // TODO: is this doc correct?
- public void setForeColor(int i) {
- if (mycell.myxf == null)
- this.getNewXf();
- mycell.myxf.setForeColor(i, null);
- }
-
- /**
- * set the Background Color for this Cell.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param int
- * t - Excel color constant
- * @see FormatHandle.COLOR constants
- */
- public void setBackgroundColor(int t) {
- setFormatHandle();
- formatter.setBackgroundColor(t);
- }
-
- /**
- * get the Color of the Cell Foreground of this Cell and all other cells sharing
- * this FormatId.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @return java.awt.Color of the Font
- */
- public Color getForegroundColor() {
- if (this.mycell.getXfRec() != null) {
- int clidx = mycell.getXfRec().getForegroundColor();
- if (clidx < this.getWorkBook().getColorTable().length) {
- Color mycolr = this.getWorkBook().getColorTable()[clidx];
- return mycolr;
- }
- }
- return Color.black;
- }
-
- /**
- * sets the Color of the Cell Foreground pattern for this Cell.
- *
- *
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param java
- * .awt.Color col - color for the foreground
- */
- public void setForegroundColor(Color col) {
- setFormatHandle();
- formatter.setForegroundColor(col);
- }
-
- /**
- * get the Color of the Cell Background by this Cell and all other cells sharing
- * this FormatId.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @return java.awt.Color for the Font
- */
- public Color getBackgroundColor() {
- if (this.mycell.getXfRec() != null) {
- Xf x = mycell.getXfRec();
- int clidx = x.getBackgroundColor();
- if (clidx < this.getWorkBook().getColorTable().length) {
- Color mycolr = this.getWorkBook().getColorTable()[clidx];
- return mycolr;
- }
- }
- return Color.white;
- }
-
- /**
- * Return the cell background color i.e. the color if a pattern is set, or white
- * if none
- *
- * @return java.awt.Color cell background color
- */
- public Color getCellBackgroundColor() {
- setFormatHandle();
- int clidx = formatter.getCellBackgroundColor();
- if (clidx < this.wbh.getWorkBook().getColorTable().length) {
- Color mycolr = this.getWorkBook().getColorTable()[clidx];
- return mycolr;
- }
- return Color.white;
- }
-
- /**
- * set the Color of the Cell Background pattern for this Cell.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param java
- * .awt.Color col - background color
- */
- public void setBackgroundColor(Color col) {
- setFormatHandle();
- formatter.setBackgroundColor(col);
- }
-
- /**
- * set the Color of the Cell Background for this Cell.
- *
- * see FormatHandle.COLOR constants for valid values
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param int
- * t - Excel color constant for Cell Background color
- */
- public void setCellBackgroundColor(int t) {
- setFormatHandle();
- formatter.setCellBackgroundColor(t);
- }
-
- /**
- * set the Color of the Cell Background for this Cell.
- *
- * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
- * Background color is the PATTERN color for all patterns not equal to
- * PATTERN_SOLID
- * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
- * Background Color is 64 (white).
- *
- * @param java
- * .awt.Color col - color of the cell background
- */
- public void setCellBackgroundColor(Color col) {
- setFormatHandle();
- formatter.setCellBackgroundColor(col);
- }
-
- /**
- * set the Color of the Cell Background Pattern for this Cell.
- *
- * @param java
- * .awt.Color col - color of the pattern background
- */
- public void setPatternBackgroundColor(Color col) {
- setFormatHandle();
- formatter.setBackgroundColor(col);
- }
-
- /**
- * set the Background Pattern for this Cell.
- *
- * @param int
- * t - Excel pattern constant
- * @see FormatHandle.PATTERN constants
- */
- public void setBackgroundPattern(int t) {
- setFormatHandle();
- formatter.setPattern(t);
- }
-
- /**
- * get the Background Pattern for this cell
- *
- * @return int Excel pattern constant
- * @see FormatHandle.PATTERN constants
- */
- public int getBackgroundPattern() {
- return this.mycell.getXfRec().getFillPattern();
- }
-
- /**
- * get the fill pattern for this cell
- * Same as getBackgroundPattern
- *
- * @return int Excel fill pattern constant
- * @see FormatHandle.PATTERN constants
- */
- public int getFillPattern() {
- setFormatHandle();
- return formatter.getFillPattern();
- }
-
- /**
- * set the Color of the Border for this Cell.
- *
- * @param java
- * .awt.Color col - border color
- */
- public void setBorderColor(Color col) {
- setFormatHandle();
- formatter.setBorderColor(col);
- }
-
- /**
- * set the Color of the right Border line for this Cell.
- *
- * @param java
- * .awt.Color col - right border color
- */
- public void setBorderRightColor(Color col) {
- setFormatHandle();
- formatter.setBorderRightColor(col);
- }
-
- /**
- * set the Color of the left Border line for this Cell.
- *
- * @param java
- * .awt.Color col - left border color
- */
- public void setBorderLeftColor(Color col) {
- setFormatHandle();
- formatter.setBorderLeftColor(col);
- }
-
- /**
- * set the Color of the top Border line for this Cell.
- *
- * @param java
- * .awt.Color col - top border color
- */
- public void setBorderTopColor(Color col) {
- setFormatHandle();
- formatter.setBorderTopColor(col);
- }
-
- /**
- * set the Color of the bottom Border line for this Cell.
- *
- * @param java
- * .awt.Color col - bottom border color
- */
- public void setBorderBottomColor(Color col) {
- setFormatHandle();
- formatter.setBorderBottomColor(col);
- }
-
- /**
- * get the Font face used by this Cell.
- *
- * @return String the system name of the font for this Cell
- */
- public String getFontFace() {
- if (this.getFont() == null)
- return FormatHandle.DEFAULT_FONT_FACE;
- return mycell.getFont().getFontName();
- }
-
- /**
- * set the Font face used by this Cell.
- *
- * @param String
- * fn - system name of the font
- */
- public void setFontFace(String fn) {
- setFormatHandle();
- formatter.setFontName(fn);
- }
-
- /**
- * set the Border line style for this Cell.
- *
- * @param short
- * s - border constant
- * @see FormatHandle.BORDER line style constants
- */
- public void setBorderLineStyle(short s) {
- setFormatHandle();
- formatter.setBorderLineStyle(s);
- }
-
- /**
- * set the Right Border line style for this Cell.
- *
- * @param short
- * s - border constant
- * @see FormatHandle.BORDER line style constants
- */
- public void setRightBorderLineStyle(short s) {
- setFormatHandle();
- formatter.setRightBorderLineStyle(s);
- }
-
- /**
- * set the Left Border line style for this Cell.
- *
- * @see FormatHandle.BORDER line style constants
- * @param short
- * s - border constant
- */
- public void setLeftBorderLineStyle(short s) {
- setFormatHandle();
- formatter.setLeftBorderLineStyle(s);
- }
-
- /**
- * set the Top Border line style for this Cell.
- *
- * @param short
- * s - border constant
- * @see FormatHandle.BORDER line style constants
- */
- public void setTopBorderLineStyle(short s) {
- setFormatHandle();
- formatter.setTopBorderLineStyle(s);
- }
-
- /**
- * set the Bottom Border line style for this Cell.
- *
- * @param short
- * s - border constant
- * @see FormatHandle.BORDER line style constants
- */
- public void setBottomBorderLineStyle(short s) {
- setFormatHandle();
- formatter.setBottomBorderLineStyle(s);
- }
-
- /**
- * removes the borders for this cell
- *
- */
- public void removeBorder() {
- setFormatHandle();
- formatter.removeBorders();
- }
-
- /**
- * Get the OpenXLS Font for this Cell, which roughly matches the functionality
- * of the java.awt.Font class.
- * Due to awt problems on console systems, converting the OpenXLS font to a GUI
- * font is up to you.
- *
- * @return OpenXLS font for Cell
- */
- public Font getFont() {
- return mycell.getFont();
- }
-
- /**
- * convert the OpenXLS font used by this Cell to java.awt.Font
- *
- * @return java.awt.Font for this cell
- */
- public java.awt.Font getAwtFont() {
- String fface = "Arial";
- try {
- fface = this.getFontFace();
- } catch (Exception e) {
- ;
- }
- int sz = 12;
- try {
- sz = this.getFontSize();
- } catch (Exception e) {
- sz = 12; // back to default
- }
- sz += 4; // Excel seems to display 1 point larger than Java
- // Logger.logInfo("Displaying font:" + fface);
- HashMap ftmap = new HashMap();
- // implement underlines
- try {
- if (this.getIsUnderlined()) {
- ftmap.put(java.awt.font.TextAttribute.UNDERLINE, java.awt.font.TextAttribute.UNDERLINE);
- }
- } catch (Exception e) {
- ;
- }
- // Ahhh, much cooler fonts here!
- ftmap.put(java.awt.font.TextAttribute.FAMILY, fface);
- float fx = this.getFontWeight();
- ftmap.put(java.awt.font.TextAttribute.SIZE, new Float(sz));
- // TODO: Interpret other weights- LIGHT, DEMI_LIGHT, DEMI_BOLD, etc.
- if (fx == FormatHandle.BOLD)
- ftmap.put(java.awt.font.TextAttribute.WEIGHT, java.awt.font.TextAttribute.WEIGHT_BOLD);
- else
- ftmap.put(java.awt.font.TextAttribute.WEIGHT, java.awt.font.TextAttribute.WEIGHT_REGULAR);
- return new java.awt.Font(ftmap);
- }
-
- /**
- * Set the Font for this Cell via font name, font style and font size
- * This method adds a new Font to the WorkBook.
- * Roughly matches the functionality of the java.awt.Font class.
- *
- * @param String
- * fn - system name of the font e.g. "Arial"
- * @param int
- * stl - font style (either Font.BOLD or Font.PLAIN)
- * @param int
- * sz - font size in points
- */
- public void setFont(String fn, int stl, int sz) {
- setFormatHandle();
- formatter.setFont(fn, stl, sz);
- }
-
- /**
- * Get a CommentHandle to the note attached to this cell
- */
- public CommentHandle getComment() throws DocumentObjectNotFoundException {
- // this needs significant cleanup. We should not have to iterate notes
- ArrayList> notes = mycell.getSheet().getNotes();
- for (int i = 0; i < notes.size(); i++) {
- Note n = (Note) notes.get(i);
- if (n.getCellAddressWithSheet().equals(this.getCellAddressWithSheet())) {
- return new CommentHandle(n);
- }
- }
- throw new DocumentObjectNotFoundException("Note record not found at " + this.getCellAddressWithSheet());
- }
-
- /**
- * Removes any note/comment records attached to this cell
- */
- public void removeComment() {
- try {
- CommentHandle note = this.getComment();
- note.remove();
- } catch (DocumentObjectNotFoundException e) {
- }
- }
-
- /**
- * Creates a new annotation (Note or Comment) to the cell
- *
- * @param comment
- * -- text of note
- * @param author
- * -- name of author
- * @return CommentHandle - handle which allows access to the Note object
- * @see CommentHandle
- */
- public CommentHandle createComment(String comment, String author) {
- Note n = mycell.getSheet().createNote(this.getCellAddress(), comment, author);
- return new CommentHandle(n);
- }
-
- /**
- * returns whether the Font for this Cell is underlined
- *
- * @return boolean true if Font is underlined
- */
- public boolean getIsUnderlined() {
- if (this.getFont() == null)
- return false;
- if (this.getFont().getUnderlineStyle() != 0x0)
- return true;
- return false;
- }
-
- /**
- * Set whether the Font for this Cell is underlined
- *
- * @param boolean
- * b - true if the Font for this Cell should be underlined (single
- * underline only)
- */
- public void setUnderlined(boolean isUnderlined) {
- setFormatHandle();
- if (isUnderlined)
- this.getFont().setUnderlineStyle(Font.STYLE_UNDERLINE_SINGLE);
- else
- this.getFont().setUnderlineStyle(Font.STYLE_UNDERLINE_NONE);
- }
-
- /**
- * set the Font Color for this Cell
- *
- * see FormatHandle.COLOR constants for valid values
- *
- * @param int
- * t - Excel color constant
- */
- public void setFontColor(int t) {
- setFormatHandle();
- formatter.setFontColor(t);
- }
-
- /**
- * Returns any other Cells merged with this one, or null if this Cell is not a
- * part of a merged range.
- * Adding and/or removing Cells from this CellRange will merge or unmerge the
- * Cells.
- *
- * @return CellRange object containing all Cells in this Cell's merged range.
- */
- public CellRange getMergedCellRange() {
- return mycell.getMergeRange();
- }
-
- /**
- * Returns if the Cell is the parent (cell containing display value) of a merged
- * cell range.
- *
- * @return boolean true if this cell is a merge parent cell
- */
- public boolean isMergeParent() {
- try {
- CellRange cr = mycell.getMergeRange();
- if (cr == null)
- return false;
- int[] i = cr.getRangeCoords();
- if (this.getRowNum() + 1 == i[0] && this.getColNum() == i[1])
- return true;
- } catch (Exception e) {
- return false;
- }
- return false;
-
- }
-
- /**
- * Returns the ColHandle for the Cell.
- *
- * @return ColHandle for the Cell
- */
- public ColHandle getCol() {
- try {
- if (mycol == null)
- mycol = wsh.getCol(this.getColNum());
- } catch (ColumnNotFoundException ex) {
- // can't happen, the column has to exist because we're in it
- throw new RuntimeException(ex);
- }
- return this.mycol;
- }
-
- /**
- * Returns the RowHandle for the Cell.
- *
- * @return RowHandle representing the Row for the Cell
- */
- public RowHandle getRow() {
- if (myrow == null)
- myrow = new RowHandle(mycell.getRow(), this.wsh);
- return this.myrow;
- }
-
- /**
- * Returns the value of this Cell in the native underlying data type.
- *
- * Formula cells will return the calculated value of the formula in the
- * calculated data type.
- *
- * Use 'getStringVal()' to return a String regardless of underlying value type.
- *
- * @return Object value for this Cell
- */
- public Object getVal() {
- return FormulaHandle.sanitizeValue(mycell.getInternalVal());
- }
-
- /**/
-
- /**
- * returns the java Type string of the Cell
- * One of:
- * "String"
- * "Float"
- * "Integer"
- * "Formula"
- * "Double"
- *
- * @return String java data type
- */
- public String getCellTypeName() {
- String typename = "Object";
- int tp = getCellType();
- switch (tp) {
- case XLSConstants.TYPE_BLANK:
- typename = "String";
- break;
- case XLSConstants.TYPE_STRING:
- typename = "String";
- break;
- case XLSConstants.TYPE_FP:
- typename = "Float";
- break;
- case XLSConstants.TYPE_INT:
- typename = "Integer";
- break;
- case XLSConstants.TYPE_FORMULA:
- typename = "Formula";
- break;
- case XLSConstants.TYPE_DOUBLE:
- typename = "Double";
- break;
- }
- return typename;
- }
-
- /**
- * Returns the type of the Cell as an int
- * TYPE_STRING = 0,
- * TYPE_FP = 1,
- * TYPE_INT = 2,
- * TYPE_FORMULA = 3,
- * TYPE_BOOLEAN = 4,
- * TYPE_DOUBLE = 5;
- *
- * @return int type for this Cell
- */
- public int getCellType() {
- return mycell.getCellType();
- }
-
- /**
- * return the underlying cell record
- * for internal API use only
- *
- * @return XLS cell record
- */
- public BiffRec getCell() {
- return mycell;
- }
-
- /**
- * returns Border Colors of Cell in: top, left, bottom, right order
- * returns null or a java.awt.Color object for each of 4 sides
- *
- * @return java.awt.Color array representing the 4 borders of the cell
- */
- public Color[] getBorderColors() {
- getFormatHandle();
- return this.formatter.getBorderColors();
- }
-
- /**
- * returns the low-level bytes for the underlying BIFF8 record.
- * For Internal API use only
- *
- * @return bytes for the underlying record
- */
- public byte[] getBytes() {
- return mycell.getData();
- }
-
- /**
- * Returns the column number of this Cell.
- *
- * @return int the Column Number of the Cell
- */
- public int getColNum() {
- setMulblank();
- return mycell.getColNumber();
- }
-
- /**
- * Returns the row number of this Cell.
- *
- * NOTE: This is the 1-based row number such as you will see in a spreadsheet
- * UI.
- *
- * ie: A1 = row 1
- *
- * @return 1-based int the Row Number of the Cell
- */
- public int getRowNum() {
- return mycell.getRowNumber();
- }
-
- /**
- * Returns the Address of this Cell as a String.
- *
- * @return String the address of this Cell in the WorkSheet
- */
- public String getCellAddress() {
- setMulblank();
- return mycell.getCellAddress();
-
- }
-
- public int[] getIntLocation() {
- setMulblank();
- return mycell.getIntLocation();
- }
-
- /**
- * Returns the Address of this Cell as a String. Includes the sheet name in the
- * address.
- *
- * @return String the address of this Cell in the WorkSheet
- */
- public String getCellAddressWithSheet() {
- setMulblank();
- return mycell.getCellAddressWithSheet();
-
- }
-
- /**
- * sets the column number referenced in the set of multiple blanks
- * for multiple blank cells only
- * for Internal Use. Not intended for the End User.
- */
- short mulblankcolnum = -1;
-
- public void setBlankRef(int c) {
- mulblankcolnum = (short) c;
- }
-
- /**
- * Returns the name of this Cell's WorkSheet as a String.
- *
- * @return String the name this Cell's WorkSheet
- */
- public String getWorkSheetName() {
- if (wsh == null) {
- try {
- return mycell.getSheet().getSheetName();
- } catch (Exception e) {
- return "";
- }
- }
- return wsh.getSheetName();
- }
-
- /**
- * Returns the value of the Cell as a String.
- * boolean Cell types will return "true" or "false"
- *
- * @return String the value of the Cell
- */
- public String getStringVal() {
- return mycell.getStringVal();
- }
-
- /**
- * Gets the value of the cell as a String with the number format applied.
- * Boolean cell types will return "true" or "false". Custom number formats are
- * not currently supported, although they will be written correctly to the
- * output file. Patterns that display negative numbers in red are not currently
- * supported; the number will be prefixed with a minus sign instead. For more
- * information on number format patterns see
- * Microsoft KB264372 .
- *
- * @return the value of the cell as a string formatted according to the cell
- * type and, if present, the number format pattern
- */
- public String getFormattedStringVal() {
- FormatHandle myfmt = this.getFormatHandle();
- return CellFormatFactory.fromPatternString(myfmt.getFormatPattern()).format(this);
- }
-
- /**
- * Gets the value of the cell as a String with the number format applied.
- * Boolean cell types will return "true" or "false". Custom number formats are
- * not currently supported, although they will be written correctly to the
- * output file. Patterns that display negative numbers in red are not currently
- * supported; the number will be prefixed with a minus sign instead. For more
- * information on number format patterns see
- * Microsoft KB264372 .
- *
- * @param formatForXML
- * if true non-compliant characters will be properly qualified
- * @return the value of the cell as a string formatted according to the cell
- * type and, if present, the number format pattern
- */
- public String getFormattedStringVal(boolean formatForXML) {
- FormatHandle myfmt = this.getFormatHandle();
- String val = this.getVal().toString();
- if (formatForXML)
- val = io.starter.formats.XLS.OOXMLAdapter.stripNonAscii(val).toString();
- return CellFormatFactory.fromPatternString(myfmt.getFormatPattern()).format(val);
- }
-
- /**
- * Returns the value of the Cell as a String.
- * For numeric cell values, including cells containing a formula which return a
- * numeric value, the notation to be used in representing the value as a String
- * must be specified.
- * The Notation choices are:
- * CellHandle.NOTATION_STANDARD e.g. "8002974342"
- * CellHandle.NOTATION_SCIENTIFIC e.g. "8.002974342E9"
- * CellHandle.NOTATION_SCIENTIFIC_EXCEL e.g. "8.002974342+E9"
- *
- * For non-numeric values, the value of the cell as a string is returned
- * boolean Cell types will return "true" or "false"
- *
- * @param int
- * notation one of the CellHandle.NOTATION constants for numeric cell
- * types; ignored for other cell types
- * @param int
- * notation - notation constant
- * @return String the value of the Cell
- */
- public String getStringVal(int notation) {
- String numval = mycell.getStringVal();
- int i = this.getCellType();
- if (i == TYPE_FP || i == TYPE_INT || i == TYPE_FORMULA || i == TYPE_DOUBLE) {
- return ExcelTools.formatNumericNotation(numval, notation);
- }
- return numval;
- }
-
- /**
- * Returns the value of the Cell as a String with the specified encoding.
- * boolean Cell types will return "true" or "false"
- *
- * @param String
- * encoding
- * @return String the value of the Cell
- */
- public String getStringVal(String encoding) {
- return mycell.getStringVal(encoding);
- }
-
- /**
- * Returns the Formatting record ID (FormatId) for this Cell
- * This can be used with 'setFormatId(int i)' to copy the formatting from one
- * Cell to another (e.g. a template cell to a new cell)
- *
- * @return int the FormatId for this Cell
- */
- public int getFormatId() {
- setMulblank();
- return mycell.getIxfe();
- }
-
- /**
- * get the conditional formatting record ID (FormatId)
- * returns the normal FormatId if the condition(s) in the conditional format
- * have not been met
- *
- * @return int the conditional format id
- */
- public int getConditionalFormatId() {
- ConditionalFormatHandle[] cfhandles = this.getConditionalFormatHandles();
- if (cfhandles == null || cfhandles.length == 0) {
- return this.getFormatId();
- }
- // TODO: only supporting first cfmat handle again
- Condfmt cfmt = cfhandles[0].getCndfmt();
-
- Iterator> x = cfmt.getRules().iterator();
- while (x.hasNext()) {
- Cf cx1 = ((Cf) x.next());
- // create a ptgref for this Cell
- Ptg pref = new PtgRef(this.getCellAddress(), this.mycell, false);
-
- if (cx1.evaluate(pref)) {
- // TODO: evaluate and combine multiple rules...
- // currently returns on first true format
- int ret = cfmt.getCfxe();
- return ret;
- }
- }
- return this.getFormatId();
- }
-
- /**
- * move this cell to another row
- * throws CellPositionConflictException if there is a cell in that position
- * already
- *
- * @param int
- * newrow - new row number
- * @exception CellPositionConflictException
- */
- public void moveToRow(int newrow) throws CellPositionConflictException {
- String newaddr = ExcelTools.getAlphaVal(mycell.getColNumber());
- newaddr += String.valueOf(newrow);
- this.moveTo(newaddr);
- }
-
- /**
- * move this cell to another row
- * overwrite any cells in the destination
- *
- * @param int
- * newrow - new row number
- */
- public void moveAndOverwriteToRow(int newrow) {
- String newaddr = ExcelTools.getAlphaVal(mycell.getColNumber());
- newaddr += String.valueOf(newrow);
- this.moveAndOverwriteTo(newaddr);
- }
-
- /**
- * move this cell to another column
- * throws CellPositionConflictException if there is a cell in that position
- * already
- *
- * @param String
- * newcol - the new column in alpha format e.g. "A", "B" ...
- * @exception CellPositionConflictException
- */
- public void moveToCol(String newcol) throws CellPositionConflictException {
- String newaddr = newcol;
- newaddr += String.valueOf(mycell.getRowNumber() + 1);
- this.moveTo(newaddr);
- }
-
- /**
- * Copy all formats from a source Cell to this Cell
- *
- * @param CellHandle
- * source - source cell
- */
- public void copyFormat(CellHandle source) {
- this.getCell().copyFormat(source.getCell());
- }
-
- /**
- * copy this Cell to another location.
- *
- * @param String
- * newaddr - address for copy of this Cell in Excel-style e.g. "A1"
- * @return returns the newly copied CellHandle
- * @exception CellPositionConflictException
- * if there is a cell in the new address already
- */
- public CellHandle copyTo(String newaddr) throws CellPositionConflictException {
-
- // check for existing
- Boundsheet bs = this.mycell.getSheet();
-
- BiffRec rec = this.mycell;
- XLSRecord nucell = (XLSRecord) ((XLSRecord) rec).clone();
- int[] rc = ExcelTools.getRowColFromString(newaddr);
- nucell.setRowNumber(rc[0]);
- nucell.setCol((short) rc[1]);
- nucell.setXFRecord(this.mycell.getIxfe());
- bs.addRecord(nucell, rc);
-
- CellHandle ret = new CellHandle(nucell, wbh);
- if (mycell.hyperlink != null) {
- // set the bounds of the mycell.hyperlink
- ret.setURL(this.getURL());
- }
- ret.setWorkSheetHandle(this.getWorkSheetHandle());
- // this.getWorkSheetHandle().cellhandles.put(this.getCellAddress(),
- // this);
- return ret;
- }
-
- /**
- * Removes this Cell from the WorkSheet
- *
- * @param boolean
- * nullme - true if this CellHandle should be nullified after removal
- */
- public void remove(boolean nullme) {
- mycell.getSheet().removeCell(mycell);
- if (nullme) {
- try {
- this.finalize();
- } catch (Throwable t) {
- ;
- }
- }
- }
-
- /**
- * move this cell to another location.
- *
- * @param String
- * newaddr - the new address for Cell in Excel-style notation e.g.
- * "A1"
- * @exception CellPositionConflictException
- * if there is a cell in the new address already
- */
- public void moveTo(String newaddr) throws CellPositionConflictException {
-
- // check for existing
- Boundsheet bs = mycell.getSheet();
- BiffRec oldhand = bs.getCell(newaddr);
- if (oldhand != null)
- throw new CellPositionConflictException(newaddr);
- bs.moveCell(this.getCellAddress(), newaddr);
-
- if (mycell.hyperlink != null) {
- // set the bounds of the mycell.hyperlink
- // int[] bnds =
- // ExcelTools.getRowColFromString(this.getCellAddress());
-
- int[] bnds = ExcelTools.getRowColFromString(this.getCellAddress());
-
- Hlink hl = mycell.hyperlink;
- hl.setRowFirst(bnds[0]);
- hl.setRowLast(bnds[0]);
- hl.setColFirst(bnds[1]);
- hl.setColLast(bnds[1]);
- hl.init();
- }
- }
-
- /**
- * move this cell to another location, overwriting any cells that are in the way
- *
- * @param String
- * newaddr - the new address for Cell in Excel-style notation e.g.
- * "A1"
- */
- public void moveAndOverwriteTo(String newaddr) {
-
- // check for existing
- Boundsheet bs = mycell.getSheet();
- BiffRec oldhand = bs.getCell(newaddr);
- bs.moveCell(this.getCellAddress(), newaddr);
-
- if (mycell.hyperlink != null) {
- int[] bnds = ExcelTools.getRowColFromString(this.getCellAddress());
-
- Hlink hl = mycell.hyperlink;
- hl.setRowFirst(bnds[0]);
- hl.setRowLast(bnds[0]);
- hl.setColFirst(bnds[1]);
- hl.setColLast(bnds[1]);
- hl.init();
- }
- }
-
- /**
- * Set a conditional format upon this cell.
- *
- * Note that conditional format handles are bound to a specific worksheet,
- *
- * @param format
- * A ConditionalFormatHandle in the same worksheet
- */
- public void addConditionalFormat(ConditionalFormatHandle format) {
- format.addCell(this);
- }
-
- /**
- * returns an array of FormatHandles for the Cell that have the current
- * conditional format applied to them.
- *
- * This behavior is still in testing, and may change
- *
- * @return an array of FormatHandles, one for each of the Conditional Formatting
- * rules
- */
- public FormatHandle[] getConditionallyFormattedHandles() {
- // TODO, should these be read-only?
- // TODO, this is bad, only handles first cf record for the cell
- ConditionalFormatHandle[] cfhandles = this.getConditionalFormatHandles();
- if (cfhandles != null) {
- FormatHandle[] fmx = new FormatHandle[cfhandles[0].getCndfmt().getRules().size()];
- for (int t = 0; t < fmx.length; t++) {
- fmx[t++] = new FormatHandle(cfhandles[0].getCndfmt(), wbh, t, this);
- }
- return fmx;
- }
- return null;
- }
-
- /**
- * return all the ConditionalFormatHandles for this Cell, if any
- *
- * @return
- */
- public ConditionalFormatHandle[] getConditionalFormatHandles() {
- WorkSheetHandle sh = this.getWorkSheetHandle();
- if (sh == null) {
- return null;
- }
- ConditionalFormatHandle[] cfs = sh.getConditionalFormatHandles();
- ArrayList cfhandles = new ArrayList();
- for (int i = 0; i < cfs.length; i++) {
- if (cfs[i].contains(this))
- cfhandles.add(cfs[i]);
- }
- ConditionalFormatHandle[] c = new ConditionalFormatHandle[cfhandles.size()];
- return (ConditionalFormatHandle[]) cfhandles.toArray(c);
- }
-
- /**
- * Gets the FormatHandle (a Format Object describing the formats for this Cell)
- * for this Cell.
- *
- * @return FormatHandle for this Cell
- */
- public FormatHandle getFormatHandle() {
- if (this.formatter == null)
- this.setFormatHandle();
-
- return this.formatter;
- }
-
- /**
- * locks or unlocks this Cell for editing
- *
- * @param boolean
- * locked - true if Cell should be locked, false otherwise
- */
- public void setLocked(boolean locked) {
- // create a new xf for this
- // this causes formats to be lost this.useExistingXF = false;
- getFormatHandle().setLocked(locked);
- }
-
- /**
- * Hides or shows the formula for this Cell, if present
- *
- * @param boolean
- * hidden - setting whether to hide or show formulas for this Cell
- */
- public void setFormulaHidden(boolean hidden) {
- // create a new xf for this
- // this causes formats to be lost this.useExistingXF = false;
- getFormatHandle().setFormulaHidden(hidden);
- }
-
- /**
- * Sets the FormatHandle (a Format Object describing the formats for this Cell)
- * for this Cell
- *
- * @param FormatHandle
- * to apply to this Cell
- * @see FormatHandle
- */
- public void setFormatHandle(FormatHandle f) {
- f.addCell(this.mycell);
- this.formatter = f;
- }
-
- /**
- * Sets the Formatting record ID (FormatId) for this Cell
- *
- * This can be used with 'getFormatId()' to copy the formatting from one Cell to
- * another (ie: a template cell to a new cell)
- *
- * @param int
- * i - the new index to the Format for this Cell
- */
- public void setFormatId(int i) {
- mycell.setXFRecord(i);
- }
-
- /**
- * Resets this cell's format to the default.
- */
- public void clearFormats() {
- this.setFormatId(this.getWorkBook().getWorkBook().getDefaultIxfe());
- }
-
- /**
- * Resets this cells contents to blank.
- */
- public void clearContents() {
- this.setVal(null);
- }
-
- /**
- * Resets this cell to the default, as if it had just been added.
- */
- public void clear() {
- this.clearFormats();
- this.clearContents();
- }
-
- /**
- * Returns the Formula Handle (an Object describing a Formula) for this Cell, if
- * it contains a formula
- *
- * @return FormulaHandle the Formula of the Cell
- * @see FormulaHandle
- * @exception FormulaNotFoundException
- */
- public FormulaHandle getFormulaHandle() throws FormulaNotFoundException {
- Formula f = mycell.getFormulaRec();
- if (f == null) {
- throw new FormulaNotFoundException("No Formula for: " + getCellAddress());
- }
- FormulaHandle fh = new FormulaHandle(f, this.wbh);
- return fh;
- }
-
- /**
- * Returns the Hyperlink URL String for this Cell, if any
- *
- * @return String URL if this Cell contains a hyperlink
- */
- public String getURL() {
- if (mycell.hyperlink != null)
- return mycell.hyperlink.getURL();
- return null;
- }
-
- /**
- * Returns the URL Description String for this Cell, if any
- *
- * @return String URL Description, if this Cell contains a hyperlink
- */
- public String getURLDescription() {
- if (mycell.hyperlink != null)
- return mycell.hyperlink.getDescription();
- return "";
- }
-
- /**
- * returns true if this Cell contains a hyperlink
- *
- * @return boolean true if this Cell contains a hyperlink
- */
- public boolean hasHyperlink() {
- return (mycell.hyperlink != null);
- }
-
- /**
- * Creates a new Hyperlink for this Cell from a URL String. Can be any valid
- * URL. This URL String must include the protocol.
- * For Example, "http://www.extentech.com/"
- * To remove a hyperlink, pass in null for the URL String
- *
- * @param String
- * urlstr - the URL String for this Cell
- */
- public void setURL(String urlstr) {
- if (urlstr == null) {
- mycell.hyperlink = null;
- // TODO: remove existing Hlink from stream
- // mycell.hyperlink.remove(true);
- return;
- }
- setURL(urlstr, "", "");
- }
-
- /**
- * Creates a new Hyperlink for this Cell from a URL String, a descrpiton and
- * textMark text.
- *
- * The URL String Can be any valid URL. This URL String must include the
- * protocol. For Example, "http://www.extentech.com/"
- * The textMark text is the porition of the URL that follows #
- *
- * NOTE: URL text and textMark text must not be null or ""
- *
- * @param String
- * urlstr - the URL String
- * @param String
- * desc - the description text
- * @param String
- * textMark - the text that follows #
- */
- public void setURL(String urlstr, String desc, String textMark) {
- if (mycell.hyperlink != null) {
- mycell.hyperlink.setURL(urlstr, desc, textMark);
- } else {
- // create new URL
- mycell.hyperlink = (Hlink) Hlink.getPrototype();
- mycell.hyperlink.setURL(urlstr, desc, textMark);
-
- // why would we want to set the val during this operation?
- // if (!desc.equals("")) setVal(desc);
-
- // set the bounds of the mycell.hyperlink
- int[] bnds = ExcelTools.getRowColFromString(this.getCellAddress());
- mycell.hyperlink.setRowFirst(bnds[0]);
- mycell.hyperlink.setColFirst(bnds[1]);
- mycell.hyperlink.setRowLast(bnds[0]);
- mycell.hyperlink.setColLast(bnds[1]);
- }
- }
-
- /**
- * Sets a hyperlink to a location within the current template
- * The URL String should be prefixed with "file://"
- *
- * @param String
- * fileURLStr - the file URL String
- */
- // TODO: document this: NOTE: Excel File URL in actuality does not match
- // documentation
- public void setFileURL(String fileURLStr) {
- setFileURL(fileURLStr, "", "");
- }
-
- /**
- * Sets a hyperlink to a location within the current template, and includes
- * additional optional information: description + textMark text
- *
- * The URL String should be prefixed with "file://"
- *
- * The textMark text is the porition of the URL that follows #
- *
- * @param String
- * fileURLstr - the file URL String
- * @param String
- * desc - the description text
- * @param String
- * textMark - text that follows #
- */
- // TODO: this documentation is contradictory
- public void setFileURL(String fileURLstr, String desc, String textMark) {
- if (mycell.hyperlink != null) {
- mycell.hyperlink.setFileURL(fileURLstr, desc, textMark);
- } else {
- mycell.hyperlink = (Hlink) Hlink.getPrototype();
-
- mycell.hyperlink.setFileURL(fileURLstr, desc, textMark);
- if (!desc.equals(""))
- setVal(desc);
-
- // set the bounds of the mycell.hyperlink
- int[] bnds = ExcelTools.getRowColFromString(this.getCellAddress());
- mycell.hyperlink.setRowFirst(bnds[0]);
- mycell.hyperlink.setColFirst(bnds[1]);
- mycell.hyperlink.setRowLast(bnds[0]);
- mycell.hyperlink.setColLast(bnds[1]);
- }
- }
-
- /**
- * Set the val of this Cell to an object
- *
- * The object may be one of type:
- * String, Float, Integer, Double, Long, Boolean, java.sql.Date, or null
- *
- * To set a Cell to a formula, obj should be a string begining with "="
- *
- * To set a Cell to an array formula, obj should be a string begining with "{="
- *
- * If you wish to put a line break in a string value, use the newline "\n"
- * character. Note this will not function unless you also apply a format handle
- * to the cell with WrapText=true
- *
- * @param Object
- * obj - the object to set the value of the Cell to
- * @exception CellTypeMismatchException
- */
-
- public void setVal(Object obj) throws CellTypeMismatchException {
- if (this.wbh.getFormulaCalculationMode() != WorkBook.CALCULATE_EXPLICIT)
- this.clearAffectedCells(); // blow out cache
-
- if (obj instanceof java.sql.Date) {
- this.setVal((java.sql.Date) obj, null);
- return;
- }
- if (obj instanceof String) {
- String formstr = (String) obj;
- if (formstr.indexOf("=") == 0 || formstr.startsWith("{=")) { // Formula or array string
- try {
- this.setFormula(formstr);
- return;
- } catch (/* 20070212 KSC: FunctionNotSupported */Exception a) {
- Logger.logWarn(
- "CellHandle.setVal() failed. Setting Formula to " + obj.toString() + " failed: " + a);
- }
- }
- }
- try {
- setBiffRecValue(obj);
- } catch (FunctionNotSupportedException fnse) {
- // suppress these -- cell has been changed
- } catch (Exception e) {
- // NOT a CTMME always
-
- throw new CellTypeMismatchException(e.toString());
- }
- }
-
- /**
- * set the value of this cell to String s
- * NOTE: this method will not check for formula references or do any data
- * conversions
- * This method is useful when a string may start with = but you do not want to
- * convert to a Formula value
- *
- * If you wish to put a line break in the string use the newline "\n" character.
- * Note this will not function unless you also apply a format handle to the cell
- * with WrapText=true
- *
- * @param String
- * s - the String value to set the Cell to
- * @see setVal(Object obj)
- * @throws CellTypeMismatchException
- */
- public void setStringVal(String s) {
- try {
- if ((s == null || s.equals("")) && !(mycell instanceof Blank))
- changeCellType(s);
- else if (s != null && !s.equals("")) {
- if (!(mycell instanceof Labelsst))
- changeCellType(" "); // avoid potential issues with string
- // values beginning with "="
- mycell.setStringVal(s);
- }
- } catch (Exception e) {
- throw new CellTypeMismatchException(e.toString());
- }
- }
-
- /**
- * set the value of this cell to Unicodestring us
- * NOTE: This method will not check for formula references or do any data
- * conversions
- * Useful when strings may start with = but you do not want to convert to a
- * formula value
- *
- * @param Unicodestring
- * us - Unicode String
- * @throws CellTypeMismatchException
- */
- public void setStringVal(Unicodestring us) {
- try {
- if ((us == null || us.toString().equals("")) && !(mycell instanceof Blank))
- changeCellType(null); // set to blank
- else if (us != null && !us.toString().equals("")) {
- if (!(mycell instanceof Labelsst))
- changeCellType(" "); // avoid potential issues with string
- // values beginning with "="
- ((Labelsst) mycell).setStringVal(us);
- }
- } catch (Exception e) {
- throw new CellTypeMismatchException(e.toString());
- }
- }
-
- /**
- * this method will be fired as each record is parsed from an input Spreadsheet
- *
- * Dec 15, 2010
- */
- public void fireParserEvent() {
-
- }
-
- /**
- * Returns a String representation of this CellHandle
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- String ret = this.getCellAddress() + ":" + this.getStringVal();
- if (this.getURL() != null)
- ret += this.getURL();
- return ret;
- }
-
- /**
- * Set the Value of the Cell to a double
- *
- * @param double
- * d- double value to set this Cell to
- * @throws CellTypeMismatchException
- */
- public void setVal(double d) throws CellTypeMismatchException {
- this.setVal(new Double(d));
- }
-
- /**
- * Set value of this Cell to a Float
- *
- * @param float
- * f - float value to set this Cell to
- * @throws CellTypeMismatchException
- */
- public void setVal(float f) throws CellTypeMismatchException {
- this.setVal(new Float(f));
- }
-
- /**
- * Sets the value of this Cell to a java.sql.Date.
- * You must also specify a formatting pattern for the new date, or null for the
- * default date format ("m/d/yy h:mm".)
- *
- * valid date format patterns:
- * "m/d/y"
- * "d-mmm-yy"
- * "d-mmm"
- * "mmm-yy"
- * "h:mm AM/PM"
- * "h:mm:ss AM/PM"
- * "h:mm"
- * "h:mm:ss"
- * "m/d/yy h:mm"
- * "mm:ss"
- * "[h]:mm:ss"
- * "mm:ss.0"
- *
- * @param java
- * .sql.Date dt - the value of the new Cell
- * @param String
- * fmt - date formatting pattern
- */
- public void setVal(java.sql.Date dt, String fmt) {
-
- if (this.wbh.getFormulaCalculationMode() != WorkBook.CALCULATE_EXPLICIT)
- this.clearAffectedCells(); // blow out cache
- if (fmt == null)
- fmt = "m/d/yyyy";
- this.setVal(new Double(DateConverter.getXLSDateVal(dt)));
- this.setFormatPattern(fmt);
- }
-
- /**
- * Sets the value of this Cell to a boolean value
- *
- * @param boolean
- * b - boolean value to set this Cell to
- * @throws CellTypeMismatchException
- */
- public void setVal(boolean b) throws CellTypeMismatchException {
- setVal(Boolean.valueOf(b));
- }
-
- /**
- * Set the value of this Cell to an int value
- * NOTE: setting a Boolean Cell type to a zero or a negative number will set the
- * Cell to 'false'; setting it to an int value 1 or greater will set it to true.
- *
- * @param int
- * i - int value to set this Cell to
- * @throws CellTypeMismatchException
- */
- public void setVal(int i) throws CellTypeMismatchException {
- if (mycell.getCellType() == XLSConstants.TYPE_BOOLEAN) {
- if (i > 0)
- setVal(Boolean.valueOf(true));
- else
- setVal(Boolean.valueOf(false));
- } else {
- setVal(Integer.valueOf(i));
- }
- }
-
- /**
- * returns the value of this Cell as a double, if possible, or NaN if Cell value
- * cannot be converted to double
- *
- * @return double value or NaN if the Cell value cannot be converted to a double
- */
- public double getDoubleVal() {
- return mycell.getDblVal();
- }
-
- /**
- * returns the value of this Cell as a int, if possible, or NaN if Cell value
- * cannot be converted to int
- *
- * @return int value or NaN if the Cell value cannot be converted to an int
- */
- public int getIntVal() {
- return mycell.getIntVal();
- }
-
- /**
- * returns the value of this Cell as a float, if possible, or NaN if Cell value
- * cannot be converted to float
- *
- * @return float value or NaN if the Cell value cannot be converted to an float
- */
- public float getFloatVal() {
- return mycell.getFloatVal();
- }
-
- /**
- * returns the value of this Cell as a boolean
- * If the Cell is not of type Boolean, returns false
- *
- * @return boolean value of cell
- */
- public boolean getBooleanVal() {
- return mycell.getBooleanVal();
- }
-
- /**
- * Set a cell to Excel-compatible formula passed in as String.
- *
- * @param String
- * formStr - the Formula String
- * @throws FunctionNotSupportedException
- * if unable to parse string correctly
- */
- public void setFormula(String formStr) throws FunctionNotSupportedException {
- int ixfe = this.mycell.getIxfe();
- this.remove(true);
- this.mycell = wsh.add(formStr, this.getCellAddress()).mycell;
- this.mycell.setXFRecord(ixfe);
- }
-
- /**
- * Set a cell to formula passed in as String. Sets the cachedValue as well, so
- * no calculating is necessary.
- *
- * Parses the string to convert into a Excel formula.
- * IMPORTANT NOTE: if cell is ALREADY a formula String this method will NOT
- * reset it
- *
- * @param String
- * formulaStr - The excel-compatible formula string to pass in
- * @param Object
- * value - The calculated value of the formula
- * @throws Exception
- * if unable to parse string correctly
- */
- public void setFormula(String formStr, Object value) throws Exception {
- if (!(this.mycell instanceof Formula)) {
- int ixfe = this.mycell.getIxfe();
- CellRange cr = this.mycell.getMergeRange();
- int r = this.getRowNum();
- int c = this.getColNum();
- this.remove(true);
- this.mycell = wsh.add(formStr, r, c, ixfe).mycell;
- this.mycell.setMergeRange(cr);
- }
- Formula f = (Formula) this.mycell;
- f.setCachedValue(value);
- }
-
- /**
- * sets the formula for this cellhandle using a stack of Ptgs appropriate for
- * formula records. This method also sets the cachedValue of the formula as
- * well, so no new calculating is necessary.
- *
- * @param Stack
- * newExp - Stack of Ptgs
- * @param Object
- * value - calculated value of formula
- */
- public void setFormula(Stack> newExp, Object value) {
- if (!(this.mycell instanceof Formula)) {
- int ixfe = this.mycell.getIxfe();
- CellRange mccr = this.mycell.getMergeRange();
- int r = this.getRowNum();
- int c = this.getColNum();
- this.remove(true);
- this.mycell = wsh.add("=0", r, c, ixfe).mycell; // add the most
- // basic formula so
- // can modify below
- // ((:
- this.mycell.setMergeRange(mccr);
- }
- try {
- Formula f = (Formula) this.mycell;
- f.setExpression(newExp);
- f.setCachedValue(value);
- } catch (Exception e) {
- ;// do what??
- }
- }
-
- /**
- * Returns the size of the merged cell area, if one exists.
- *
- * @param row
- * this parameter is ignored
- * @param column
- * this parameter is ignored
- * @return a 2 position int array with number of rows and number of cols
- * @deprecated since October 2012. This method duplicates the functionality of
- * {@link #getMergedCellRange()}, which it calls internally. That
- * method should be used instead.
- */
- @Deprecated
- public int[] getSpan(int row, int column) {
- CellRange mergerange = getMergedCellRange();
- if (mergerange != null) {
- if (DEBUG)
- Logger.logInfo("CellHandle " + this.toString() + " getSpan() for range: " + mergerange.toString());
- int[] ret = { 0, 0 };
- // if(check.toString().equals(this.toString())){ //it's the first in
- // the range -- show it!
- try {
- ret[0] = mergerange.getRows().length;
- ret[1] = mergerange.getCols().length; // TODO: test!
- } catch (Exception e) {
- Logger.logWarn("CellHandle getting CellSpan failed: " + e);
- }
- // }
- return ret;
- }
- return null;
- }
-
- /**
- * returns the WorkBookHandle for this Cell
- *
- * @return WorkBook the book
- */
- public WorkBook getWorkBook() {
- return wbh;
- }
-
- /**
- * get the index of the WorkSheet containing this Cell in the list of sheets
- *
- * @return int the WorkSheetHandle index for this Cell
- */
- public int getSheetNum() {
- return this.mycell.getSheet().getSheetNum();
- }
-
- /**
- * get the WorkSheetHandle for this Cell
- *
- * @return the WorkSheetHandle for this Cell
- */
- public WorkSheetHandle getWorkSheetHandle() {
- return wsh;
- }
-
- /**
- * Determines if the cellHandle represents a completely blank/null cell, and can
- * thus be ignored for many operations.
- *
- * Criteria for returning true is a cell type of BLANK, that has a default
- * format id (0), is not part of a merge range, does not contain a URL, and is
- * not a part of a validation
- *
- * @return true if cell is truly blank
- */
- public boolean isDefaultCell() {
- if ((this.getCellType() == CellHandle.TYPE_BLANK)
- && ((this.getFormatId() == 15 && !this.wbh.getWorkBook().getIsExcel2007()) || this.getFormatId() == 0)
- && (this.getMergedCellRange() == null) && (this.getURL() == null)
- && (this.getValidationHandle() == null)) {
- return true;
- }
- return false;
- }
-
- /**
- * set the WorkSheetHandle for this Cell
- *
- * @param WorkSheetHandle
- * handle - the new worksheet for this Cell
- * @see WorkSheetHandle
- */
- public void setWorkSheetHandle(WorkSheetHandle handle) {
- wsh = handle;
-
- // This is redundant, already done in WSH.getCell().
-
- // if (wsh!=null) //20080616 KSC
- // wsh.cellhandles.put(this.getCellAddress(), this);
- }
-
- /**
- * Returns an XML representation of the cell and it's component data
- *
- * @return String of XML
- */
- public String getXML() {
- return getXML(null);
- }
-
- /**
- * Returns an XML representation of the cell and it's component data
- *
- * @param int[]
- * mergedRange - include merged ranges in the XML representation if
- * not null
- * @return String of XML
- */
- public String getXML(int[] mergedRange) {
- String vl = "", fvl = "", sv = "", hd = "", csp = "", hlink = "";
- Object val = null;
- StringBuffer retval = new StringBuffer();
- String typename = this.getCellTypeName();
- // put the formula string in
- if (typename.equals("Formula")) {
- try {
- FormulaHandle fmh = getFormulaHandle();
- String fms = fmh.getFormulaString();
- // use single quotes around formula value to avoid errors in
- // xslt transform
- if (fms.indexOf("\"") > 0) {
- fvl = " Formula='" + StringTool.convertXMLChars(fms) + "'";
- } else {
- fvl = " Formula=\"" + StringTool.convertXMLChars(fms) + "\"";
- }
- try {
- if (this.wbh.getWorkBook().getCalcMode() != WorkBook.CALCULATE_EXPLICIT) {
- val = fmh.calculate();
- } else {
- try {
- // changed from getVal() now that getVal returns a
- // null
- val = fmh.getStringVal();
- } catch (Exception e) {
- Logger.logWarn("CellHandle.getXML formula calc failed: " + e.toString());
- }
- }
- if (val instanceof Float)
- typename = "Float";
- else if (val instanceof Double)
- typename = "Double";
- else if (val instanceof Integer)
- typename = "Integer";
- else if (val instanceof java.util.Date || val instanceof java.sql.Date
- || val instanceof java.sql.Timestamp)
- typename = "DateTime";
- else
- typename = "String";
- } catch (Exception e) {
- typename = "String"; // default
- }
- } catch (Exception e) {
- Logger.logErr("OpenXLS.getXML() failed getting type of Formula for: " + this.toString(), e);
- }
- }
- if (this.isDate())
- typename = "DateTime"; // 20060428 KSC: Moved after Formula parsing
-
- // TODO: when RowHandle.getCells actually contains ALL cells, keep this
- if (this.mycell.getOpcode() != XLSConstants.MULBLANK) {
- // Put the style ID in
- sv = " StyleID=\"s" + getFormatId() + "\"";
- if (mergedRange != null) { // TODO: fix!
- csp += " MergeAcross=\"" + ((mergedRange[3] - mergedRange[1]) + 1) + "\"";
- csp += " MergeDown=\"" + (mergedRange[2] - mergedRange[0]) + "\"";
- }
- if (this.getCol().isHidden()) {
- hd = " Hidden=\"true\"";
- }
- // TODO: HRefScreenTip ????
- if (this.getURL() != null) {
- hlink = " HRef=\"" + StringTool.convertXMLChars(this.getURL()) + "\"";
- }
-
- // put the date formattingin
- // Assemble the string
- retval.append("");
- if (typename.equals("DateTime")) {
- retval.append(DateConverter.getFormattedDateVal(this));
- } else if (this.getCellType() == CellHandle.TYPE_STRING) {
- val = this.getStringVal(); // (String)getVal();
- if (val.equals("")) { // 20070216 KSC: John, had the same edits,
- // seems to work well in cursory tests ...
- // retval.append(" "); does this screw up formulas expecting
- // empty strings? -jm
- } else {
- retval.append(StringTool.convertXMLChars(val.toString()));
- }
- } else {
- try {
- // if(val == null)
- val = this.getVal();
- retval.append(StringTool.convertXMLChars(val.toString()) + vl);
- } catch (Exception e) {
- Logger.logErr("CellHandle.getXML failed for: " + this.getCellAddress() + " in: "
- + this.getWorkBook().toString(), e);
- retval.append("XML ERROR!");
- }
- }
- retval.append(" ");
- retval.append(end_cell_xml);
- } else {
- int c = ((Mulblank) this.mycell).getColFirst();
- int lastcol = ((Mulblank) this.mycell).getColLast();
- for (; c <= lastcol; c++) {
- mulblankcolnum = (short) c;
- // Put the style ID in
- sv = " StyleID=\"s" + getFormatId() + "\"";
- if (this.getCol().isHidden()) {
- hd = " Hidden=\"true\"";
- }
- // TODO: HRefScreenTip ????
- if (this.getURL() != null) {
- hlink = " HRef=\"" + StringTool.convertXMLChars(this.getURL()) + "\"";
- }
-
- // put the date formattingin
- // Assemble the string
- retval.append(" ");
- retval.append(end_cell_xml);
- }
- }
- return retval.toString();
- }
-
- /**
- * Set the horizontal alignment for this Cell
- *
- *
- * @param int
- * align - constant value representing the horizontal alignment.
- * @see FormatHandle.ALIGN* constants
- */
- public void setHorizontalAlignment(int align) {
- setFormatHandle();
- formatter.setHorizontalAlignment(align);
- }
-
- /**
- * Returns an int representing the current horizontal alignment in this Cell.
- *
- * @return int representing horizontal alignment
- * @see FormatHandle.ALIGN* constants
- */
- public int getHorizontalAlignment() {
- if (this.mycell.getXfRec() != null) {
- return this.mycell.getXfRec().getHorizontalAlignment();
- }
- // 0 is default alignment
- return 0;
- }
-
- /**
- * Set the Vertical alignment for this Cell
- *
- * @param int
- * align - constant value representing the vertical alignment.
- * @see FormatHandle.ALIGN* constants
- */
- public void setVerticalAlignment(int align) {
- setFormatHandle();
- formatter.setVerticalAlignment(align);
- }
-
- /**
- * Returns an int representing the current vertical alignment in this Cell.
- *
- * @return int representing vertical alignment
- * @see FormatHandle.ALIGN* constants
- */
- public int getVerticalAlignment() {
- if (this.mycell.getXfRec() != null) {
- return this.mycell.getXfRec().getVerticalAlignment();
- }
- // 1 is default alignment
- return 1;
- }
-
- /**
- * Sets the cell wrapping behavior for this cell
- *
- * @param boolean
- * wrapit - true if cell text should be wrapped (default is false)
- */
- public void setWrapText(boolean wrapit) {
- setFormatHandle();
- formatter.setWrapText(wrapit);
- if (wrapit) { // when wrap text it automatically wraps if row height has
- // NOT been set yet
- try {
- if (!this.getRow().isAlteredHeight()) // has row height been altered??
- this.getRow().setRowHeightAutoFit();
- } catch (Exception e) { /* ignore */
- }
- }
- }
-
- /**
- * Get the cell wrapping behavior for this cell.
- *
- * @return true if cell text is wrapped
- */
- public boolean getWrapText() {
- if (this.mycell.getXfRec() != null) {
- return this.mycell.getXfRec().getWrapText();
- }
- // false is default alignment
- return false;
- }
-
- /**
- * Set the rotation of the cell in degrees.
- * Values 0-90 represent rotation up, 0-90degrees.
- * Values 91-180 represent rotation down, 0-90 degrees.
- * Value 255 is vertical
- *
- * @param int
- * align - an int representing the rotation.
- */
- public void setCellRotation(int align) {
- setFormatHandle();
- formatter.setCellRotation(align);
- }
-
- /**
- * Get the rotation of this Cell in degrees.
- * Values 0-90 represent rotation up, 0-90degrees.
- * Values 91-180 represent rotation down, 0-90 degrees.
- * Value 255 is vertical
- *
- * @return int representing the degrees of cell rotation
- */
- public int getCellRotation() {
- if (this.mycell.getXfRec() != null) {
- return this.mycell.getXfRec().getRotation();
- }
- // false is default alignment
- return 0;
- }
-
- public int compareTo(CellHandle that) {
- int comp = this.getRowNum() - that.getRowNum();
- if (comp != 0)
- return comp;
- return this.getColNum() - that.getColNum();
- }
-
- @Override
- public boolean equals(Object that) {
- if (!(that instanceof CellHandle))
- return false;
- return this.mycell.equals(((CellHandle) that).mycell);
- }
-
- @Override
- public int hashCode() {
- return this.mycell.hashCode();
- }
-
- /**
- * Set the super/sub script for the Font
- *
- * @param int
- * ss - super/sub script constant (0 = none, 1 = super, 2 = sub)
- */
- public void setScript(int ss) {
- if (mycell.myxf == null)
- this.getNewXf();
- mycell.myxf.getFont().setScript(ss);
- }
-
- /**
- * Set the val of the biffrec with an Object
- *
- * @param Object
- * to set the value of the Cell to
- */
- private void setBiffRecValue(Object obj) throws CellTypeMismatchException {
- if (mycell.getOpcode() == XLSConstants.BLANK || mycell.getOpcode() == XLSConstants.MULBLANK) {
- // no reason for this Blank blank = (Blank)mycell;
- // String addr = mycell.getCellAddress();
-
- // trim the Mulblank
- /*
- * KSC: mulblanks are NOT expanded now if (blank.getMyMul() != null){ Mulblank
- * mblank = (Mulblank)blank.getMyMul(); mblank.trim(blank); }
- */
- changeCellType(obj); // 20080206 KSC: Basically replaces all above
- // code
- } else {
- if (obj == null) {
- // should never be false ??? if (!(mycell instanceof Blank))
- changeCellType(obj); // will set to blank
- } else if (obj instanceof Float || obj instanceof Double || obj instanceof Integer || obj instanceof Long) {
- if ((mycell instanceof NumberRec) || (mycell instanceof Rk)) {
- if (obj instanceof Float) {
- Float f = (Float) obj;
- mycell.setFloatVal(f.floatValue());
- } else if (obj instanceof Integer) {
- Integer i = (Integer) obj;
- mycell.setIntVal(i.intValue());
- } else if (obj instanceof Double) {
- Double d = (Double) obj;
- mycell.setDoubleVal(d.doubleValue());
- } else if (obj instanceof Long) {
- Long d = (Long) obj;
- mycell.setDoubleVal(d.longValue());
- }
- } else
- changeCellType(obj);
- } else if (obj instanceof Boolean) {
- if (mycell instanceof Boolerr)
- ((Boolerr) mycell).setBooleanVal(((Boolean) obj).booleanValue());
- else
- changeCellType(obj);
- } else if (obj instanceof String) {
- if (((String) obj).startsWith("="))
- changeCellType(obj); // easier to just redo a formula...
- else if (!obj.toString().equalsIgnoreCase("")) {
- if (mycell instanceof Labelsst)
- mycell.setStringVal(String.valueOf(obj));
- else
- changeCellType(obj);
- } else if (!(mycell instanceof Blank))
- changeCellType(obj);
- }
- }
- }
-
- /**
- * if object type doesn't match current mycell record, remove and add
- * appropriate record type
- *
- * @param obj
- */
- private void changeCellType(Object obj) {
- int[] rc = { mycell.getRowNumber(), mycell.getColNumber() };
- Boundsheet bs = mycell.getSheet();
- int oldXf = mycell.getIxfe();
- bs.removeCell(mycell);
- BiffRec addedrec = bs.addValue(obj, rc, true);
- mycell = (XLSRecord) addedrec;
- mycell.setXFRecord(oldXf);
- }
-
- /**
- * retrieves or creates a new xf for this cell
- *
- * @return
- */
- private Xf getNewXf() {
- if (mycell.myxf != null)
- return mycell.myxf;
- // reusing or creating new xfs is handled in FormatHandle/cloneXf and
- // updateXf
- // this.useExistingXF = true; // flag to re-use this XF
- try {
- mycell.myxf = new Xf(this.getFont().getIdx());
- // get the recidx of the last Xf
- int insertIdx = mycell.getWorkBook().getXf(mycell.getWorkBook().getNumXfs() - 1).getRecordIndex();
- // perform default add rec actions
-
- mycell.myxf.setSheet(null);
- mycell.getWorkBook().getStreamer().addRecordAt(mycell.myxf, insertIdx + 1);
- mycell.getWorkBook().addRecord(mycell.myxf, false);
- // update the pointer
- int xfe = mycell.myxf.getIdx();
- mycell.setIxfe(xfe);
- return mycell.myxf;
- } catch (Exception e) {
- return null;
- }
- }
-
- static final String begin_hidden_emptycell_xml = " | ";
-
- static final String begin_cell_xml = " | ";
- static final String end_cell_xml = " | ";
-
- /**
- * Returns an xml representation of an empty cell
- *
- * @param loc
- * - the cell address
- * @param isVisible
- * - if the cell is visible (not hidden)
- * @return
- */
- protected static String getEmptyCellXML(String loc, boolean isVisible) {
- if (!isVisible) {
- return begin_hidden_emptycell_xml + loc + end_hidden_emptycell_xml;
- } else {
- return begin_cell_xml + loc + end_emptycell_xml;
- }
- }
-
- /**
- * Calculates and returns all formulas that reference this CellHandle.
- * Please note that these cells may have already been calculated, so in order to
- * get their values without re-calculating them Extentech suggests setting the
- * book level non-calculation flag, ie
- * book.setFormulaCalculationMode(WorkBookHandle.CALCULATE_EXPLICIT); or
- * FormulaHandle.getCachedVal()
- *
- * @return List of of calculated cells (CellHandles)
- */
- public List calculateAffectedCells() {
- ReferenceTracker rt = this.wbh.getWorkBook().getRefTracker();
- Iterator> its = rt.clearAffectedFormulaCells(this).values().iterator();
-
- List ret = new ArrayList();
- while (its.hasNext()) {
- CellHandle cx = new CellHandle((BiffRec) its.next(), this.wbh);
- ret.add(cx);
- }
- return ret;
- }
-
- /**
- * Internal method for clearing affected cells, does the same thing as
- * calculateAffectedCells, but does not create a list
- */
- protected void clearAffectedCells() {
- ReferenceTracker rt = this.wbh.getWorkBook().getRefTracker();
- rt.clearAffectedFormulaCells(this);
- }
-
- /**
- * Calculates and returns all formulas on the same sheet that reference this
- * CellHandle.
- * Please note that these cells may have already been calculated, so in order to
- * get their values without re-calculating them Extentech suggests setting the
- * book level non-calculation flag, ie
- * book.setFormulaCalculationMode(WorkBookHandle.CALCULATE_EXPLICIT); or
- * FormulaHandle.getCachedVal()
- *
- * @return List of of calculated cells (CellHandles)
- */
- public List calculateAffectedCellsOnSheet() {
- Iterator> its = this.wbh.getWorkBook().getRefTracker()
- .clearAffectedFormulaCellsOnSheet(this, this.getWorkSheetName()).values().iterator();
- List ret = new ArrayList();
- while (its.hasNext()) {
- CellHandle cx = new CellHandle((BiffRec) its.next(), this.wbh);
- ret.add(cx);
- }
- return ret;
- }
-
- /**
- * flags chart references to the particular cell as dirty/ needing caches
- * rebuilt
- */
- public void clearChartReferences() {
- ArrayList ret = new ArrayList();
- Iterator> ii = this.wbh.getWorkBook().getRefTracker().getChartReferences(this.getCell()).iterator();
- while (ii.hasNext()) {
- Ai ai = (Ai) ii.next();
- if (ai.getParentChart() != null)
- ai.getParentChart().setMetricsDirty();
- }
- }
-
- /**
- * Creates a copy of this cell on the given worksheet at the given address.
- *
- * @param sourcecell
- * the cell to copy
- * @param newsheet
- * the sheet to which the cell should be copied
- * @param row
- * the row in which the copied cell should be placed
- * @param col
- * the row in which the copied cell should be placed
- * @return CellHandle representing the new Cell
- */
- public static final CellHandle copyCellToWorkSheet(CellHandle sourcecell, WorkSheetHandle newsheet, int row,
- int col) throws CellPositionConflictException, CellNotFoundException {
- return copyCellToWorkSheet(sourcecell, newsheet, row, col, false);
- }
-
- /**
- * Creates a copy of this cell on the given worksheet at the given address.
- *
- * @param sourcecell
- * the cell to copy
- * @param newsheet
- * the sheet to which the cell should be copied
- * @param row
- * the row in which the copied cell should be placed
- * @param col
- * the row in which the copied cell should be placed
- * @param copyByValue
- * whether to copy formulas' values instead of the formulas
- * themselves
- * @return CellHandle representing the new cell
- */
- public static CellHandle copyCellToWorkSheet(CellHandle sourcecell, WorkSheetHandle newsheet, int row, int col,
- boolean copyByValue) {
- // copy cell values
- CellHandle newcell = null;
-
- int offsets[] = { row - sourcecell.getRowNum(), col - sourcecell.getColNum() };
-
- if (sourcecell.isFormula() && !copyByValue)
- try {
- FormulaHandle fmh = sourcecell.getFormulaHandle();
- newcell = newsheet.add(fmh.getFormulaString(), row, col);
- FormulaHandle fm2 = newcell.getFormulaHandle();
- FormulaHandle.moveCellRefs(fm2, offsets);
- } catch (FormulaNotFoundException ex) {
- newcell = null;
- }
-
- if (newcell == null)
- newcell = newsheet.add(sourcecell.getVal(), row, col);
-
- return copyCellHelper(sourcecell, newcell);
- }
-
- /**
- * Create a copy of this Cell in another WorkBook
- *
- *
- * @param sourcecell
- * the cell to copy
- * @param target
- * worksheet to copy this cell into
- * @return
- */
- public static final CellHandle copyCellToWorkSheet(CellHandle sourcecell, WorkSheetHandle newsheet) {
- // copy cell values
- CellHandle newcell = null;
- try {
- FormulaHandle fmh = sourcecell.getFormulaHandle();
- // Logger.logInfo("testFormats Formula encountered: "+
- // fmh.getFormulaString());
-
- newcell = newsheet.add(fmh.getFormulaString(), sourcecell.getCellAddress());
- } catch (FormulaNotFoundException ex) {
- newcell = newsheet.add(sourcecell.getVal(), sourcecell.getCellAddress());
- }
- return copyCellHelper(sourcecell, newcell);
- }
-
- /**
- * Get the JSON object for this cell.
- *
- * @return String representing the JSON for this Cell
- */
- public String getJSON() {
- return getJSONObject().toString();
- }
-
- /** Get the JSON object for this cell. */
- public JSONObject getJSONObject() {
- CellRange cr = getMergedCellRange();
- int[] mergedCellRange = null;
- if (cr != null) {
- try {
- mergedCellRange = cr.getRangeCoords();
- if (mycell.getOpcode() == XLSRecord.MULBLANK) {
- Mulblank m = (Mulblank) mycell;
- if (!cr.contains(m.getIntLocation())) {
- mergedCellRange = null;
- }
- }
- } catch (CellNotFoundException e) {
- ;
- }
- }
-
- return getJSONObject(mergedCellRange);
- }
-
- /**
- * Get a JSON Object representation of a cell utilizing a merged range
- * identifier.
- *
- * @deprecated The {@code mergedRange} parameter is unnecessary. This method
- * will be removed in a future version. Use {@link #getJSONObject()}
- * instead.
- */
- @Deprecated
- public JSONObject getJSONObject(int[] mergedRange) {
- JSONObject theCell = new JSONObject();
- try {
- theCell.put(JSON_LOCATION, getCellAddress());
-
- Object val;
- try {
- val = getVal();
- if (val == null)
- val = "";
- } catch (Exception ex) {
- Logger.logWarn("OpenXLS.getJSONObject failed: " + ex.toString());
- val = "#ERR!";
- }
-
- String typename = getCellTypeName();
- JSONObject dataval = new JSONObject();
-
- if (typename.equals("Formula")) {
- try {
- FormulaHandle fmh = getFormulaHandle();
- String fms = fmh.getFormulaString();
-
- theCell.put(JSON_CELL_FORMULA, fms);
-
- try {
- if (Float.parseFloat(val.toString()) == (Float.NaN)) {
- typename = JSON_FLOAT;
- } else if (val instanceof Float)
- typename = JSON_FLOAT;
- else if (val instanceof Double)
- typename = JSON_DOUBLE;
- else if (val instanceof Integer)
- typename = JSON_INTEGER;
- else if (val instanceof java.util.Date || val instanceof java.sql.Date
- || val instanceof java.sql.Timestamp) {
- typename = JSON_DATETIME;
- } else
- typename = JSON_STRING;
- } catch (Exception e) {
- typename = JSON_STRING; // default
- }
- } catch (Exception e) {
- Logger.logErr("OpenXLS.getJSON() failed getting type of Formula for: " + toString(), e);
- }
- }
-
- if (isDate())
- typename = JSON_DATETIME;
-
- dataval.put(JSON_TYPE, typename);
-
- // TODO: Handle Conditional Format
- // cell should return the style id for its condition
- // this is an ID that begins incrementing after the last Xf
- // and should be contained in the CSS for the output
-
- // if the conditional format evaluates to TRUE
- // then we use *that* style ID not the default
-
- // We can have multiple CF styles per cell, one per each rule... we'll need that
- // from CSS standpoint so...
-
- // style
- theCell.put(JSON_STYLEID, getConditionalFormatId());
-
- // merges
- if (mergedRange != null) {
- theCell.put(JSON_MERGEACROSS, (mergedRange[3] - mergedRange[1]));
- theCell.put(JSON_MERGEDOWN, (mergedRange[2] - mergedRange[0]));
- if (isMergeParent()) {
- theCell.put(JSON_MERGEPARENT, true);
- } else {
- theCell.put(JSON_MERGECHILD, true);
- }
- }
-
- // handle hidden setting
- try {
- if (getCol().isHidden())
- theCell.put(JSON_HIDDEN, true);
- } catch (Exception e) {
- ;
- }
-
- // handle the locked/formula hidden setting
- // only active if sheet is protected
- try {
- if (isFormulaHidden())
- theCell.put(JSON_FORMULA_HIDDEN, true);
-
- theCell.put(JSON_LOCKED, isLocked());
- } catch (Exception e) {
- ;
- }
-
- try {
- ValidationHandle vh = getValidationHandle();
- if (vh != null)
- theCell.put(JSON_VALIDATION_MESSAGE, vh.getPromptBoxTitle() + ":" + vh.getPromptBoxText());
- } catch (Exception e) {
- ;
- }
-
- // hyperlinks
- if (!(getURL() == null))
- theCell.put(JSON_HREF, getURL());
-
- if (getWrapText())
- theCell.put(JSON_WORD_WRAP, true);
-
- // store alignment for container issues
- int alignment = getFormatHandle().getHorizontalAlignment();
- if (alignment == FormatHandle.ALIGN_RIGHT) {
- theCell.put(JSON_TEXT_ALIGN, "right");
- } else if (alignment == FormatHandle.ALIGN_CENTER) {
- theCell.put(JSON_TEXT_ALIGN, "center");
- } else if (alignment == FormatHandle.ALIGN_LEFT) {
- theCell.put(JSON_TEXT_ALIGN, "left");
- }
-
- // dates
- if (typename.equals(JSON_DATETIME) && !(val == null) && !val.equals("")) {
- dataval.put(JSON_CELL_VALUE, getFormattedStringVal());
- // dataval.put(JSON_DATEVALUE, ch.getFloatVal());
- dataval.put("time", DateConverter.getCalendarFromCell(this).getTimeInMillis());
- } else if (getCellType() == CellHandle.TYPE_STRING) {
- // FORCES CALC
- if (((String) val).indexOf("\n") > -1) {
- val = ((String) val).replaceAll("\n", " ");
- }
- if (!val.equals(""))
- dataval.put(JSON_CELL_VALUE, val.toString());
- } else { // other
- dataval.put(JSON_CELL_VALUE, val.toString());
- try { // formatted pattern
- String s = getFormatPattern();
- if (!(s.equals(""))) {
- String fmtd = getFormattedStringVal(); // TRIGGERS CALC!
- if (!(val.equals(fmtd)))
- dataval.put(JSON_CELL_FORMATTED_VALUE, fmtd);
- if (s.indexOf("Red") > -1) {
- Double d = new Double(val.toString());
- if (d.doubleValue() < 0) {
- theCell.put(JSON_RED_FORMAT, "1");
- if (fmtd.indexOf("-") == 0)
- fmtd = fmtd.substring(1, fmtd.length());
- dataval.put(JSON_CELL_FORMATTED_VALUE, fmtd);
- }
- }
- }
- } catch (Exception x) {
- }
- ;
- }
- theCell.put(JSON_DATA, dataval);
- } catch (JSONException e) {
- Logger.logErr("error getting JSON for the cell: " + e);
- }
- return theCell;
- }
-
- /**
- * Returns the validation handle for the cell.
- *
- * @return ValidationHandle for this Cell, or null if none
- */
- public ValidationHandle getValidationHandle() {
- ValidationHandle ret = null;
- try {
- ret = this.getWorkSheetHandle().getValidationHandle(this.getCellAddress());
- } catch (Exception e) {
- ; // somewhat normal?
- }
- return ret;
- }
-
- /**
- * Copies all formatting - xf and non-xf (such as column width, hidden state)
- * plus merged cell range from a sourcecell to a new cell (usually in a new
- * workbook)
- *
- * @param sourcecell
- * the cell to copy
- * @param newcell
- * the cell to copy to
- * @return
- */
- protected static final CellHandle copyCellHelper(CellHandle sourcecell, CellHandle newcell) {
- // copy row height & attributes
- int rz = sourcecell.getRow().getHeight();
- newcell.getRow().setHeight(rz);
- if (sourcecell.getRow().isHidden()) {
- newcell.getRow().setHidden(true);
- }
- // copy col width & attributes
- int rzx = sourcecell.getCol().getWidth();
- newcell.getCol().setWidth(rzx);
- if (sourcecell.getCol().isHidden()) {
- newcell.getCol().setHidden(true);
- // Logger.logInfo("column " + rzx + " is hidden");
- }
-
- try {
- // copy merged ranges
- CellRange rng = sourcecell.getMergedCellRange();
- if (rng != null) {
- rng = new CellRange(rng.getRange(), newcell.getWorkBook());
- rng.addCellToRange(newcell);
- rng.mergeCells(false);
- }
- // Handle formats:
- Xf origxf = sourcecell.getWorkBook().getWorkBook().getXf(sourcecell.getFormatId());
- newcell.getFormatHandle().addXf(origxf);
- return newcell;
- } catch (Exception ex) {
- Logger.logErr("CellHandle.copyCellHelper failed.", ex);
- }
- return newcell;
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/CellHandle.kt b/src/main/java/io/starter/OpenXLS/CellHandle.kt
new file mode 100644
index 0000000..0e5a217
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/CellHandle.kt
@@ -0,0 +1,2867 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.Font
+import io.starter.formats.XLS.*
+import io.starter.formats.XLS.charts.Ai
+import io.starter.formats.XLS.formulas.Ptg
+import io.starter.formats.XLS.formulas.PtgRef
+import io.starter.formats.cellformat.CellFormatFactory
+import io.starter.toolkit.Logger
+import io.starter.toolkit.StringTool
+import org.json.JSONException
+import org.json.JSONObject
+
+import java.awt.Color
+import java.awt.font.TextAttribute
+import java.io.Serializable
+import java.util.*
+
+import io.starter.OpenXLS.JSONConstants.*
+
+/**
+ * The CellHandle provides a handle to an XLS Cell and its values.
+ * Use the CellHandle to work with individual Cells in an XLS file.
+ * To instantiate a CellHandle, you must first have a valid WorkSheetHandle,
+ * which in turn requires a valid WorkBookHandle.
+ *
+ * for example:
+ *
+ * WorkBookHandle book = newWorkBookHandle("testxls.xls");
+ * WorkSheetHandle sheet1 = book.getWorkSheet("Sheet1");
+ * CellHandlecell = sheet1.getCell("B22");
+ *
+ *
+ * With a CellHandle you can:
+ *
+ * - get the value of a Cell
+ * - set the value of a Cell
+ * - change the color, font, and background formatting of a Cell
+ * - change the formatting pattern of a Cell
+ * - change the value of a Cell
+ * - get a handle to any Formula for this Cell
+ *
+ *
+ * [Starter Inc.](http://starter.io)
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see FormulaHandle
+ *
+ * @see CellNotFoundException
+ *
+ * @see CellTypeMismatchException
+ */
+class CellHandle : Cell, Serializable, Handle, Comparable {
+
+ /**
+ * returns the WorkBookHandle for this Cell
+ *
+ * @return WorkBook the book
+ */
+ @Transient
+ val workBook: WorkBook? = null
+ /**
+ * get the WorkSheetHandle for this Cell
+ *
+ * @return the WorkSheetHandle for this Cell
+ */
+ /**
+ * set the WorkSheetHandle for this Cell
+ *
+ * @param WorkSheetHandle handle - the new worksheet for this Cell
+ * @see WorkSheetHandle
+ */
+ @Transient // This is redundant, already done in WSH.getCell().
+ // if (wsh!=null) //20080616 KSC
+ // wsh.cellhandles.put(this.getCellAddress(), this);
+ var workSheetHandle: WorkSheetHandle? = null
+ private var mycol: ColHandle? = null
+ private var myrow: RowHandle? = null
+ private var formatter: FormatHandle? = null
+ // reusing or creating new xfs is handled in FormatHandle/cloneXf and
+ // updateXf
+ // boolean useExistingXF = !false;
+ private val DEBUG = false
+ /**
+ * returns the underlying BIFF8 record for the Cell
+ * NOTE: the underlying record is not a part of the public API and may change at
+ * any time.
+ *
+ * @return Returns the underlying biff record.
+ */
+ /**
+ * sets the underlying BIFF8 record for the Cell
+ * NOTE: the underlying record is not a part of the public API and may change at
+ * any time.
+ *
+ * @param XLSRecord rec - The BIFF record to set.
+ */
+ var record: XLSRecord? = null
+
+ /**
+ * Get the default "empty" data value for this CellHandle
+ *
+ * @return Object a default empty value corresponding to the cell type
+ * such as 0.0 for TYPE_DOUBLE or an empty String for TYPE_BLANK
+ */
+ val defaultVal: Any?
+ get() = record!!.defaultVal
+
+ /**
+ * Gets the number format pattern for this cell, if set. For more information on
+ * number format patterns see
+ * [Microsoft KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @return the Excel number format pattern for this cell or `null` if
+ * none is applied
+ */
+ /**
+ * Sets the number format pattern for this cell. All Excel built-in number
+ * formats are supported. Custom formats will not be applied by OpenXLS (e.g.
+ * the [.getFormattedStringVal] method) but they will be written correctly
+ * to the output file. For more information on number format patterns see
+ * [Microsoft KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @param pat the Excel number format pattern to apply
+ * @see FormatConstantsImpl.getBuiltinFormats
+ */
+ var formatPattern: String?
+ get() = if (this.font == null) "" else record!!.formatPattern
+ set(pat) {
+ setFormatHandle()
+ formatter!!.formatPattern = pat
+ }
+
+ /**
+ * Returns whether this Cell has Date formatting applied.
+ * NOTE: This does not guarantee that the value is a valid date.
+ *
+ * @return boolean true if this Cell has a Date Format applied
+ */
+ override val isDate: Boolean
+ get() {
+ if (record!!.myxf == null)
+ return false
+ if (record!!.isString)
+ return false
+ if (record!!.isBoolean)
+ return false
+ return if (record!!.isBlank) false else record!!.myxf!!.isDatePattern
+ }
+
+ /**
+ * Returns whether this cell is a formula.
+ */
+ val isFormula: Boolean
+ get() = record!!.isFormula
+
+ /**
+ * Returns whether the formula for the Cell is hidden
+ *
+ * @return boolean true if formula is hidden
+ */
+ /**
+ * Hides or shows the formula for this Cell, if present
+ *
+ * @param boolean hidden - setting whether to hide or show formulas for this Cell
+ */
+ // create a new xf for this
+ // this causes formats to be lost this.useExistingXF = false;
+ var isFormulaHidden: Boolean
+ get() = this.formatHandle!!.isFormulaHidden
+ set(hidden) {
+ formatHandle!!.isFormulaHidden = hidden
+ }
+
+ /**
+ * returns whether this Cell is locked for editing
+ *
+ * @return boolean true if the cell is locked
+ */
+ /**
+ * locks or unlocks this Cell for editing
+ *
+ * @param boolean locked - true if Cell should be locked, false otherwise
+ */
+ // create a new xf for this
+ // this causes formats to be lost this.useExistingXF = false;
+ var isLocked: Boolean
+ get() = this.formatHandle!!.isLocked
+ set(locked) {
+ formatHandle!!.isLocked = locked
+ }
+
+ /**
+ * Returns whether this is a blank cell.
+ *
+ * @return true if this cell is blank
+ */
+ val isBlank: Boolean
+ get() = this.record!!.isBlank
+
+ /**
+ * Returns whether this Cell has a Currency format applied.
+ *
+ * @return boolean true if this Cell has a Currency format applied
+ */
+ val isCurrency: Boolean
+ get() = if (record!!.myxf == null) false else record!!.myxf!!.isCurrencyPattern
+
+ /**
+ * Returns whether this Cell has a numeric value
+ *
+ * @return boolean true if this Cell contains a numeric value
+ */
+ val isNumber: Boolean
+ get() = this.record!!.isNumber
+
+ /**
+ * get the weight (boldness) of the Font used by this Cell.
+ *
+ * @return int Font weight range between 100-1000
+ */
+ /**
+ * change the weight (boldness) of the Font used by this Cell.
+ * Some examples:
+ * a weight of 200 is normal
+ * a weight of 700 is bold
+ *
+ * @param int wt - Font weight range between 100-1000
+ */
+ var fontWeight: Int
+ get() = if (this.font == null) FormatHandle.DEFAULT_FONT_WEIGHT else record!!.font!!.fontWeight
+ set(wt) {
+ setFormatHandle()
+ formatter!!.fontWeight = wt
+ }
+
+ /**
+ * get the size in points of the Font used by this Cell
+ *
+ * @return int Font size in Points.
+ */
+ /**
+ * change the size (in points) of the Font used by this Cell and all other Cells
+ * sharing this FormatId.
+ * NOTE: To add an entirely new Font use the setFont(String fn, int typ, int sz)
+ * method instead.
+ *
+ * @param int sz - Font size in Points.
+ */
+ // excel size is 1/20 pt.
+ var fontSize: Int
+ get() = if (this.font == null) FormatHandle.DEFAULT_FONT_SIZE else record!!.font!!.fontHeight / 20
+ set(sz) {
+ var sz = sz
+ setFormatHandle()
+ sz *= 20
+ formatter!!.fontHeight = sz
+ }
+
+ /**
+ * get the Color of the Font used by this Cell.
+ *
+ * @return int Excel color constant for Font color
+ * @see FormatHandle.COLOR constants
+ */
+ /**
+ * Set the color of the Font used by this Cell.
+ *
+ * @param java .Awt.Color col - color of the font
+ */
+ // handle white on white text issue
+ // return black
+ // black on black
+ var fontColor: Color
+ get() {
+ if (this.font == null)
+ return FormatHandle.Black
+ val clidx = this.font!!.color
+ val x = record!!.xfRec
+ val clidb = x!!.backgroundColor.toInt()
+ if (clidx == 64 && clidb == 64) {
+ return FormatHandle.Black
+ }
+ return if (clidx < this.workBook!!.colorTable.size) {
+ workBook.colorTable[clidx]
+ } else Color.black
+ }
+ set(col) {
+ setFormatHandle()
+ formatter!!.fontColor = col
+ }
+
+ /**
+ * get the Color of the Cell Foreground of this Cell and all other cells sharing
+ * this FormatId.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @return java.awt.Color of the Font
+ */
+ val foregroundColor: Color
+ get() {
+ if (this.record!!.xfRec != null) {
+ val clidx = record!!.xfRec!!.foregroundColor.toInt()
+ if (clidx < this.workBook!!.colorTable.size) {
+ return workBook.colorTable[clidx]
+ }
+ }
+ return Color.black
+ }
+
+ /**
+ * get the Color of the Cell Background by this Cell and all other cells sharing
+ * this FormatId.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @return java.awt.Color for the Font
+ */
+ val backgroundColor: Color
+ get() {
+ if (this.record!!.xfRec != null) {
+ val x = record!!.xfRec
+ val clidx = x!!.backgroundColor.toInt()
+ if (clidx < this.workBook!!.colorTable.size) {
+ return workBook.colorTable[clidx]
+ }
+ }
+ return Color.white
+ }
+
+ /**
+ * Return the cell background color i.e. the color if a pattern is set, or white
+ * if none
+ *
+ * @return java.awt.Color cell background color
+ */
+ val cellBackgroundColor: Color
+ get() {
+ setFormatHandle()
+ val clidx = formatter!!.cellBackgroundColor
+ return if (clidx < this.workBook!!.workBook.colorTable.size) {
+ workBook.colorTable[clidx]
+ } else Color.white
+ }
+
+ /**
+ * get the Background Pattern for this cell
+ *
+ * @return int Excel pattern constant
+ * @see FormatHandle.PATTERN constants
+ */
+ /**
+ * set the Background Pattern for this Cell.
+ *
+ * @param int t - Excel pattern constant
+ * @see FormatHandle.PATTERN constants
+ */
+ var backgroundPattern: Int
+ get() = this.record!!.xfRec!!.fillPattern
+ set(t) {
+ setFormatHandle()
+ formatter!!.setPattern(t)
+ }
+
+ /**
+ * get the fill pattern for this cell
+ * Same as getBackgroundPattern
+ *
+ * @return int Excel fill pattern constant
+ * @see FormatHandle.PATTERN constants
+ */
+ val fillPattern: Int
+ get() {
+ setFormatHandle()
+ return formatter!!.fillPattern
+ }
+
+ /**
+ * get the Font face used by this Cell.
+ *
+ * @return String the system name of the font for this Cell
+ */
+ /**
+ * set the Font face used by this Cell.
+ *
+ * @param String fn - system name of the font
+ */
+ var fontFace: String?
+ get() = if (this.font == null) FormatHandle.DEFAULT_FONT_FACE else record!!.font!!.fontName
+ set(fn) {
+ setFormatHandle()
+ formatter!!.fontName = fn
+ }
+
+ /**
+ * Get the OpenXLS Font for this Cell, which roughly matches the functionality
+ * of the java.awt.Font class.
+ * Due to awt problems on console systems, converting the OpenXLS font to a GUI
+ * font is up to you.
+ *
+ * @return OpenXLS font for Cell
+ */
+ val font: Font?
+ get() = record!!.font
+
+ /**
+ * convert the OpenXLS font used by this Cell to java.awt.Font
+ *
+ * @return java.awt.Font for this cell
+ */
+ // back to default
+ // Excel seems to display 1 point larger than Java
+ // Logger.logInfo("Displaying font:" + fface);
+ // implement underlines
+ // Ahhh, much cooler fonts here!
+ // TODO: Interpret other weights- LIGHT, DEMI_LIGHT, DEMI_BOLD, etc.
+ val awtFont: java.awt.Font
+ get() {
+ var fface: String? = "Arial"
+ try {
+ fface = this.fontFace
+ } catch (e: Exception) {
+ }
+
+ var sz = 12
+ try {
+ sz = this.fontSize
+ } catch (e: Exception) {
+ sz = 12
+ }
+
+ sz += 4
+ val ftmap = HashMap()
+ try {
+ if (this.isUnderlined) {
+ ftmap[java.awt.font.TextAttribute.UNDERLINE] = java.awt.font.TextAttribute.UNDERLINE
+ }
+ } catch (e: Exception) {
+ }
+
+ ftmap[java.awt.font.TextAttribute.FAMILY] = fface
+ val fx = this.fontWeight.toFloat()
+ ftmap[java.awt.font.TextAttribute.SIZE] = sz
+ if (fx == FormatHandle.BOLD.toFloat())
+ ftmap[java.awt.font.TextAttribute.WEIGHT] = java.awt.font.TextAttribute.WEIGHT_BOLD
+ else
+ ftmap[java.awt.font.TextAttribute.WEIGHT] = java.awt.font.TextAttribute.WEIGHT_REGULAR
+ return java.awt.Font(ftmap)
+ }
+
+ /**
+ * Get a CommentHandle to the note attached to this cell
+ */
+ // this needs significant cleanup. We should not have to iterate notes
+ val comment: CommentHandle
+ @Throws(DocumentObjectNotFoundException::class)
+ get() {
+ val notes = record!!.sheet!!.notes
+ for (i in notes.indices) {
+ val n = notes[i] as Note
+ if (n.cellAddressWithSheet == this.cellAddressWithSheet) {
+ return CommentHandle(n)
+ }
+ }
+ throw DocumentObjectNotFoundException("Note record not found at " + this.cellAddressWithSheet)
+ }
+
+ /**
+ * returns whether the Font for this Cell is underlined
+ *
+ * @return boolean true if Font is underlined
+ */
+ /**
+ * Set whether the Font for this Cell is underlined
+ *
+ * @param boolean b - true if the Font for this Cell should be underlined (single
+ * underline only)
+ */
+ var isUnderlined: Boolean
+ get() = if (this.font == null) false else this.font!!.underlineStyle != 0x0
+ set(isUnderlined) {
+ setFormatHandle()
+ if (isUnderlined)
+ this.font!!.setUnderlineStyle(Font.STYLE_UNDERLINE_SINGLE)
+ else
+ this.font!!.setUnderlineStyle(Font.STYLE_UNDERLINE_NONE)
+ }
+
+ /**
+ * Returns any other Cells merged with this one, or null if this Cell is not a
+ * part of a merged range.
+ * Adding and/or removing Cells from this CellRange will merge or unmerge the
+ * Cells.
+ *
+ * @return CellRange object containing all Cells in this Cell's merged range.
+ */
+ val mergedCellRange: CellRange?
+ get() = record!!.mergeRange
+
+ /**
+ * Returns if the Cell is the parent (cell containing display value) of a merged
+ * cell range.
+ *
+ * @return boolean true if this cell is a merge parent cell
+ */
+ val isMergeParent: Boolean
+ get() {
+ try {
+ val cr = record!!.mergeRange ?: return false
+ val i = cr.rangeCoords
+ if (this.rowNum + 1 == i[0] && this.colNum == i[1])
+ return true
+ } catch (e: Exception) {
+ return false
+ }
+
+ return false
+
+ }
+
+ /**
+ * Returns the ColHandle for the Cell.
+ *
+ * @return ColHandle for the Cell
+ */
+ // can't happen, the column has to exist because we're in it
+ val col: ColHandle
+ get() {
+ try {
+ if (mycol == null)
+ mycol = workSheetHandle!!.getCol(this.colNum)
+ } catch (ex: ColumnNotFoundException) {
+ throw RuntimeException(ex)
+ }
+
+ return this.mycol
+ }
+
+ /**
+ * Returns the RowHandle for the Cell.
+ *
+ * @return RowHandle representing the Row for the Cell
+ */
+ val row: RowHandle
+ get() {
+ if (myrow == null)
+ myrow = RowHandle(record!!.row, this.workSheetHandle!!)
+ return this.myrow
+ }
+
+ /**
+ * Returns the value of this Cell in the native underlying data type.
+ *
+ *
+ * Formula cells will return the calculated value of the formula in the
+ * calculated data type.
+ *
+ *
+ * Use 'getStringVal()' to return a String regardless of underlying value type.
+ *
+ * @return Object value for this Cell
+ */
+ /**
+ * Set the val of this Cell to an object
+ *
+ * The object may be one of type:
+ * String, Float, Integer, Double, Long, Boolean, java.sql.Date, or null
+ *
+ * To set a Cell to a formula, obj should be a string begining with "="
+ *
+ * To set a Cell to an array formula, obj should be a string begining with "{="
+ *
+ * If you wish to put a line break in a string value, use the newline "\n"
+ * character. Note this will not function unless you also apply a format handle
+ * to the cell with WrapText=true
+ *
+ * @param Object obj - the object to set the value of the Cell to
+ * @throws CellTypeMismatchException
+ */
+
+ override// blow out cache
+ // Formula or array string
+ /* 20070212 KSC: FunctionNotSupported */// suppress these -- cell has been changed
+ // NOT a CTMME always
+ var `val`: Any?
+ get() = FormulaHandle.sanitizeValue(record!!.internalVal)
+ @Throws(CellTypeMismatchException::class)
+ set(obj) {
+ if (this.workBook!!.formulaCalculationMode != WorkBook.CALCULATE_EXPLICIT)
+ this.clearAffectedCells()
+
+ if (obj is java.sql.Date) {
+ this.setVal(obj as java.sql.Date?, null)
+ return
+ }
+ if (obj is String) {
+ val formstr = obj as String?
+ if (formstr!!.indexOf("=") == 0 || formstr.startsWith("{=")) {
+ try {
+ this.setFormula(formstr)
+ return
+ } catch (a: Exception) {
+ Logger.logWarn(
+ "CellHandle.setVal() failed. Setting Formula to $obj failed: $a")
+ }
+
+ }
+ }
+ try {
+ setBiffRecValue(obj)
+ } catch (fnse: FunctionNotSupportedException) {
+ } catch (e: Exception) {
+
+ throw CellTypeMismatchException(e.toString())
+ }
+
+ }
+
+ /**/
+
+ /**
+ * returns the java Type string of the Cell
+ * One of:
+ * * "String"
+ * * "Float"
+ * * "Integer"
+ * * "Formula"
+ * * "Double"
+ *
+ * @return String java data type
+ */
+ val cellTypeName: String
+ get() {
+ var typename = "Object"
+ val tp = cellType
+ when (tp) {
+ XLSConstants.TYPE_BLANK -> typename = "String"
+ XLSConstants.TYPE_STRING -> typename = "String"
+ XLSConstants.TYPE_FP -> typename = "Float"
+ XLSConstants.TYPE_INT -> typename = "Integer"
+ XLSConstants.TYPE_FORMULA -> typename = "Formula"
+ XLSConstants.TYPE_DOUBLE -> typename = "Double"
+ }
+ return typename
+ }
+
+ /**
+ * Returns the type of the Cell as an int
+ * * TYPE_STRING = 0,
+ * * TYPE_FP = 1,
+ * * TYPE_INT = 2,
+ * * TYPE_FORMULA = 3,
+ * * TYPE_BOOLEAN = 4,
+ * * TYPE_DOUBLE = 5;
+ *
+ * @return int type for this Cell
+ */
+ override val cellType: Int
+ get() = record!!.cellType
+
+ /**
+ * return the underlying cell record
+ * for internal API use only
+ *
+ * @return XLS cell record
+ */
+ val cell: BiffRec?
+ get() = record
+
+ /**
+ * returns Border Colors of Cell in: top, left, bottom, right order
+ * returns null or a java.awt.Color object for each of 4 sides
+ *
+ * @return java.awt.Color array representing the 4 borders of the cell
+ */
+ val borderColors: Array
+ get() {
+ formatHandle
+ return this.formatter!!.borderColors
+ }
+
+ /**
+ * returns the low-level bytes for the underlying BIFF8 record.
+ * For Internal API use only
+ *
+ * @return bytes for the underlying record
+ */
+ val bytes: ByteArray?
+ get() = record!!.data
+
+ /**
+ * Returns the column number of this Cell.
+ *
+ * @return int the Column Number of the Cell
+ */
+ override val colNum: Int
+ get() {
+ setMulblank()
+ return record!!.colNumber.toInt()
+ }
+
+ /**
+ * Returns the row number of this Cell.
+ *
+ *
+ * NOTE: This is the 1-based row number such as you will see in a spreadsheet
+ * UI.
+ *
+ *
+ * ie: A1 = row 1
+ *
+ * @return 1-based int the Row Number of the Cell
+ */
+ override val rowNum: Int
+ get() = record!!.rowNumber
+
+ /**
+ * Returns the Address of this Cell as a String.
+ *
+ * @return String the address of this Cell in the WorkSheet
+ */
+ override val cellAddress: String
+ get() {
+ setMulblank()
+ return record!!.cellAddress
+
+ }
+
+ val intLocation: IntArray
+ get() {
+ setMulblank()
+ return record!!.intLocation
+ }
+
+ /**
+ * Returns the Address of this Cell as a String. Includes the sheet name in the
+ * address.
+ *
+ * @return String the address of this Cell in the WorkSheet
+ */
+ val cellAddressWithSheet: String
+ get() {
+ setMulblank()
+ return record!!.cellAddressWithSheet
+
+ }
+
+ /**
+ * sets the column number referenced in the set of multiple blanks
+ * for multiple blank cells only
+ * for Internal Use. Not intended for the End User.
+ */
+ internal var mulblankcolnum: Short = -1
+
+ /**
+ * Returns the name of this Cell's WorkSheet as a String.
+ *
+ * @return String the name this Cell's WorkSheet
+ */
+ override val workSheetName: String
+ get() {
+ if (workSheetHandle == null) {
+ try {
+ return record!!.sheet!!.sheetName
+ } catch (e: Exception) {
+ return ""
+ }
+
+ }
+ return workSheetHandle!!.sheetName
+ }
+
+ /**
+ * Returns the value of the Cell as a String.
+ * boolean Cell types will return "true" or "false"
+ *
+ * @return String the value of the Cell
+ */
+ /**
+ * set the value of this cell to String s
+ * NOTE: this method will not check for formula references or do any data
+ * conversions
+ * This method is useful when a string may start with = but you do not want to
+ * convert to a Formula value
+ *
+ *
+ * If you wish to put a line break in the string use the newline "\n" character.
+ * Note this will not function unless you also apply a format handle to the cell
+ * with WrapText=true
+ *
+ * @param String s - the String value to set the Cell to
+ * @throws CellTypeMismatchException
+ * @see setVal
+ */
+ // avoid potential issues with string
+ // values beginning with "="
+ var stringVal: String?
+ get() = record!!.stringVal
+ set(s) = try {
+ if ((s == null || s == "") && record !is Blank)
+ changeCellType(s)
+ else if (s != null && s != "") {
+ if (record !is Labelsst)
+ changeCellType(" ")
+ record!!.stringVal = s
+ }
+ } catch (e: Exception) {
+ throw CellTypeMismatchException(e.toString())
+ }
+
+ /**
+ * Gets the value of the cell as a String with the number format applied.
+ * Boolean cell types will return "true" or "false". Custom number formats are
+ * not currently supported, although they will be written correctly to the
+ * output file. Patterns that display negative numbers in red are not currently
+ * supported; the number will be prefixed with a minus sign instead. For more
+ * information on number format patterns see
+ * [Microsoft KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @return the value of the cell as a string formatted according to the cell
+ * type and, if present, the number format pattern
+ */
+ override val formattedStringVal: String
+ get() {
+ val myfmt = this.formatHandle
+ return CellFormatFactory.fromPatternString(myfmt!!.formatPattern).format(this)
+ }
+
+ /**
+ * Returns the Formatting record ID (FormatId) for this Cell
+ * This can be used with 'setFormatId(int i)' to copy the formatting from one
+ * Cell to another (e.g. a template cell to a new cell)
+ *
+ * @return int the FormatId for this Cell
+ */
+ /**
+ * Sets the Formatting record ID (FormatId) for this Cell
+ *
+ *
+ * This can be used with 'getFormatId()' to copy the formatting from one Cell to
+ * another (ie: a template cell to a new cell)
+ *
+ * @param int i - the new index to the Format for this Cell
+ */
+ override var formatId: Int
+ get() {
+ setMulblank()
+ return record!!.ixfe
+ }
+ set(i) = record!!.setXFRecord(i)
+
+ /**
+ * get the conditional formatting record ID (FormatId)
+ * returns the normal FormatId if the condition(s) in the conditional format
+ * have not been met
+ *
+ * @return int the conditional format id
+ */
+ // TODO: only supporting first cfmat handle again
+ // create a ptgref for this Cell
+ // TODO: evaluate and combine multiple rules...
+ // currently returns on first true format
+ val conditionalFormatId: Int
+ get() {
+ val cfhandles = this.conditionalFormatHandles
+ if (cfhandles == null || cfhandles.size == 0) {
+ return this.formatId
+ }
+ val cfmt = cfhandles[0].cndfmt
+
+ val x = cfmt!!.rules.iterator()
+ while (x.hasNext()) {
+ val cx1 = x.next() as Cf
+ val pref = PtgRef(this.cellAddress, this.record, false)
+
+ if (cx1.evaluate(pref)) {
+ return cfmt.cfxe
+ }
+ }
+ return this.formatId
+ }
+
+ /**
+ * returns an array of FormatHandles for the Cell that have the current
+ * conditional format applied to them.
+ *
+ *
+ * This behavior is still in testing, and may change
+ *
+ * @return an array of FormatHandles, one for each of the Conditional Formatting
+ * rules
+ */
+ // TODO, should these be read-only?
+ // TODO, this is bad, only handles first cf record for the cell
+ val conditionallyFormattedHandles: Array?
+ get() {
+ val cfhandles = this.conditionalFormatHandles
+ if (cfhandles != null) {
+ val fmx = arrayOfNulls(cfhandles[0].cndfmt!!.rules.size)
+ var t = 0
+ while (t < fmx.size) {
+ fmx[t++] = FormatHandle(cfhandles[0].cndfmt!!, workBook!!, t, this)
+ t++
+ }
+ return fmx
+ }
+ return null
+ }
+
+ /**
+ * return all the ConditionalFormatHandles for this Cell, if any
+ *
+ * @return
+ */
+ val conditionalFormatHandles: Array?
+ get() {
+ val sh = this.workSheetHandle ?: return null
+ val cfs = sh.conditionalFormatHandles
+ val cfhandles = ArrayList()
+ for (i in cfs.indices) {
+ if (cfs[i].contains(this))
+ cfhandles.add(cfs[i])
+ }
+ val c = arrayOfNulls(cfhandles.size)
+ return cfhandles.toTypedArray()
+ }
+
+ /**
+ * Gets the FormatHandle (a Format Object describing the formats for this Cell)
+ * for this Cell.
+ *
+ * @return FormatHandle for this Cell
+ */
+ /**
+ * Sets the FormatHandle (a Format Object describing the formats for this Cell)
+ * for this Cell
+ *
+ * @param FormatHandle to apply to this Cell
+ * @see FormatHandle
+ */
+ var formatHandle: FormatHandle?
+ get() {
+ if (this.formatter == null)
+ this.setFormatHandle()
+
+ return this.formatter
+ }
+ set(f) {
+ f.addCell(this.record)
+ this.formatter = f
+ }
+
+ /**
+ * Returns the Formula Handle (an Object describing a Formula) for this Cell, if
+ * it contains a formula
+ *
+ * @return FormulaHandle the Formula of the Cell
+ * @throws FormulaNotFoundException
+ * @see FormulaHandle
+ */
+ val formulaHandle: FormulaHandle
+ @Throws(FormulaNotFoundException::class)
+ get() {
+ val f = record!!.formulaRec ?: throw FormulaNotFoundException("No Formula for: $cellAddress")
+ return FormulaHandle(f, workBook)
+ }
+
+ /**
+ * Returns the Hyperlink URL String for this Cell, if any
+ *
+ * @return String URL if this Cell contains a hyperlink
+ */
+ /**
+ * Creates a new Hyperlink for this Cell from a URL String. Can be any valid
+ * URL. This URL String must include the protocol.
+ * For Example, "http://www.extentech.com/"
+ * To remove a hyperlink, pass in null for the URL String
+ *
+ * @param String urlstr - the URL String for this Cell
+ */
+ // TODO: remove existing Hlink from stream
+ // mycell.hyperlink.remove(true);
+ var url: String?
+ get() = if (record!!.hyperlink != null) record!!.hyperlink!!.url else null
+ set(urlstr) {
+ if (urlstr == null) {
+ record!!.hyperlink = null
+ return
+ }
+ setURL(urlstr, "", "")
+ }
+
+ /**
+ * Returns the URL Description String for this Cell, if any
+ *
+ * @return String URL Description, if this Cell contains a hyperlink
+ */
+ val urlDescription: String
+ get() = if (record!!.hyperlink != null) record!!.hyperlink!!.description else ""
+
+ /**
+ * returns the value of this Cell as a double, if possible, or NaN if Cell value
+ * cannot be converted to double
+ *
+ * @return double value or NaN if the Cell value cannot be converted to a double
+ */
+ val doubleVal: Double
+ get() = record!!.dblVal
+
+ /**
+ * returns the value of this Cell as a int, if possible, or NaN if Cell value
+ * cannot be converted to int
+ *
+ * @return int value or NaN if the Cell value cannot be converted to an int
+ */
+ val intVal: Int
+ get() = record!!.intVal
+
+ /**
+ * returns the value of this Cell as a float, if possible, or NaN if Cell value
+ * cannot be converted to float
+ *
+ * @return float value or NaN if the Cell value cannot be converted to an float
+ */
+ val floatVal: Float
+ get() = record!!.floatVal
+
+ /**
+ * returns the value of this Cell as a boolean
+ * If the Cell is not of type Boolean, returns false
+ *
+ * @return boolean value of cell
+ */
+ val booleanVal: Boolean
+ get() = record!!.booleanVal
+
+ /**
+ * get the index of the WorkSheet containing this Cell in the list of sheets
+ *
+ * @return int the WorkSheetHandle index for this Cell
+ */
+ val sheetNum: Int
+ get() = this.record!!.sheet!!.sheetNum
+
+ /**
+ * Determines if the cellHandle represents a completely blank/null cell, and can
+ * thus be ignored for many operations.
+ *
+ *
+ * Criteria for returning true is a cell type of BLANK, that has a default
+ * format id (0), is not part of a merge range, does not contain a URL, and is
+ * not a part of a validation
+ *
+ * @return true if cell is truly blank
+ */
+ val isDefaultCell: Boolean
+ get() = (this.cellType == CellHandle.TYPE_BLANK
+ && (this.formatId == 15 && !this.workBook!!.workBook.isExcel2007 || this.formatId == 0)
+ && this.mergedCellRange == null && this.url == null
+ && this.validationHandle == null)
+
+ /**
+ * Returns an XML representation of the cell and it's component data
+ *
+ * @return String of XML
+ */
+ val xml: String
+ get() = getXML(null)
+
+ /**
+ * Returns an int representing the current horizontal alignment in this Cell.
+ *
+ * @return int representing horizontal alignment
+ * @see FormatHandle.ALIGN* constants
+ */
+ /**
+ * Set the horizontal alignment for this Cell
+ *
+ * @param int align - constant value representing the horizontal alignment.
+ * @see FormatHandle.ALIGN* constants
+ */
+ // 0 is default alignment
+ var horizontalAlignment: Int
+ get() = if (this.record!!.xfRec != null) {
+ this.record!!.xfRec!!.horizontalAlignment
+ } else 0
+ set(align) {
+ setFormatHandle()
+ formatter!!.horizontalAlignment = align
+ }
+
+ /**
+ * Returns an int representing the current vertical alignment in this Cell.
+ *
+ * @return int representing vertical alignment
+ * @see FormatHandle.ALIGN* constants
+ */
+ /**
+ * Set the Vertical alignment for this Cell
+ *
+ * @param int align - constant value representing the vertical alignment.
+ * @see FormatHandle.ALIGN* constants
+ */
+ // 1 is default alignment
+ var verticalAlignment: Int
+ get() = if (this.record!!.xfRec != null) {
+ this.record!!.xfRec!!.verticalAlignment
+ } else 1
+ set(align) {
+ setFormatHandle()
+ formatter!!.verticalAlignment = align
+ }
+
+ /**
+ * Get the cell wrapping behavior for this cell.
+ *
+ * @return true if cell text is wrapped
+ */
+ /**
+ * Sets the cell wrapping behavior for this cell
+ *
+ * @param boolean wrapit - true if cell text should be wrapped (default is false)
+ */
+ // false is default alignment
+ // when wrap text it automatically wraps if row height has
+ // NOT been set yet
+ // has row height been altered??
+ /* ignore */ var wrapText: Boolean
+ get() = if (this.record!!.xfRec != null) {
+ this.record!!.xfRec!!.wrapText
+ } else false
+ set(wrapit) {
+ setFormatHandle()
+ formatter!!.wrapText = wrapit
+ if (wrapit) {
+ try {
+ if (!this.row.isAlteredHeight)
+ this.row.setRowHeightAutoFit()
+ } catch (e: Exception) {
+ }
+
+ }
+ }
+
+ /**
+ * Get the rotation of this Cell in degrees.
+ * Values 0-90 represent rotation up, 0-90degrees.
+ * Values 91-180 represent rotation down, 0-90 degrees.
+ * Value 255 is vertical
+ *
+ * @return int representing the degrees of cell rotation
+ */
+ /**
+ * Set the rotation of the cell in degrees.
+ * Values 0-90 represent rotation up, 0-90degrees.
+ * Values 91-180 represent rotation down, 0-90 degrees.
+ * Value 255 is vertical
+ *
+ * @param int align - an int representing the rotation.
+ */
+ // false is default alignment
+ var cellRotation: Int
+ get() = if (this.record!!.xfRec != null) {
+ this.record!!.xfRec!!.rotation
+ } else 0
+ set(align) {
+ setFormatHandle()
+ formatter!!.cellRotation = align
+ }
+
+ /**
+ * retrieves or creates a new xf for this cell
+ *
+ * @return
+ */
+ private// reusing or creating new xfs is handled in FormatHandle/cloneXf and
+ // updateXf
+ // this.useExistingXF = true; // flag to re-use this XF
+ // get the recidx of the last Xf
+ // perform default add rec actions
+ // update the pointer
+ val newXf: Xf?
+ get() {
+ if (record!!.myxf != null)
+ return record!!.myxf
+ try {
+ record!!.myxf = Xf(this.font!!.idx)
+ val insertIdx = record!!.workBook!!.getXf(record!!.workBook!!.numXfs - 1)!!.recordIndex
+
+ record!!.myxf!!.setSheet(null)
+ record!!.workBook!!.streamer.addRecordAt(record!!.myxf!!, insertIdx + 1)
+ record!!.workBook!!.addRecord(record!!.myxf!!, false)
+ val xfe = record!!.myxf!!.idx
+ record!!.ixfe = xfe
+ return record!!.myxf
+ } catch (e: Exception) {
+ return null
+ }
+
+ }
+
+ /**
+ * Get the JSON object for this cell.
+ *
+ * @return String representing the JSON for this Cell
+ */
+ val json: String
+ get() = jsonObject.toString()
+
+ /**
+ * Get the JSON object for this cell.
+ */
+ val jsonObject: JSONObject
+ get() {
+ val cr = mergedCellRange
+ var mergedCellRange: IntArray? = null
+ if (cr != null) {
+ try {
+ mergedCellRange = cr.rangeCoords
+ if (record!!.opcode == XLSRecord.MULBLANK) {
+ val m = record as Mulblank?
+ if (!cr.contains(m!!.intLocation)) {
+ mergedCellRange = null
+ }
+ }
+ } catch (e: CellNotFoundException) {
+ }
+
+ }
+
+ return getJSONObject(mergedCellRange)
+ }
+
+ /**
+ * Returns the validation handle for the cell.
+ *
+ * @return ValidationHandle for this Cell, or null if none
+ */
+ // somewhat normal?
+ val validationHandle: ValidationHandle?
+ get() {
+ var ret: ValidationHandle? = null
+ try {
+ ret = this.workSheetHandle!!.getValidationHandle(this.cellAddress)
+ } catch (e: Exception) {
+ }
+
+ return ret
+ }
+
+ /**
+ * Public Constructor added for use in Bean-context ONLY.
+ *
+ *
+ * Do NOT create CellHandles manually.
+ */
+ constructor(c: BiffRec) {
+ record = c as XLSRecord
+ }
+
+ /**
+ * if this cellhandle refers to a mulblank, ensure internal mulblank properties
+ * are set to appropriate cell in the mulblank range
+ */
+ private fun setMulblank() {
+ if (record!!.opcode == XLSConstants.MULBLANK) {
+ if (mulblankcolnum.toInt() == -1) { // init
+ mulblankcolnum = record!!.colNumber
+ (record as Mulblank).setCurrentCell(mulblankcolnum)
+ record!!.ixfe // ensure myxf is set to correct
+ // xf for the given cell in the
+ // set of mulblanks
+ } else if (mulblankcolnum != record!!.colNumber) {
+ (record as Mulblank).setCurrentCell(mulblankcolnum)
+ record!!.ixfe // ensure myxf is set to correct
+ // xf for the given cell in the
+ // set of mulblanks
+ }
+ this.formatter = null
+ }
+ }
+
+ /**
+ * Public Constructor added for use in Bean-context ONLY.
+ *
+ *
+ * Do NOT create CellHandles manually.
+ */
+ constructor(c: BiffRec, myb: WorkBook) {
+ record = c as XLSRecord
+ setMulblank()
+ this.workBook = myb
+ }
+
+ /**
+ * Get a FormatHandle (a Format Object describing the formats for this Cell)
+ * referenced by this CellHandle.
+ *
+ * @return FormatHandle
+ * @see FormatHandle
+ */
+ internal fun setFormatHandle() {
+ setMulblank()
+ if (formatter != null && formatter!!.formatId == this.record!!.ixfe) {
+ return
+ }
+ // reusing or creating new xfs is handled in FormatHandle/cloneXf and
+ // updateXf
+ if (this.record!!.xfRec != null) {
+ formatter = FormatHandle(this.workBook, this.record!!.myxf)
+ } else {// should ever happen now?
+ // useExistingXF = false;
+ if (workBook == null && this.record!!.workBook != null)
+ formatter = FormatHandle(this.record!!.workBook, -1)
+ else
+ formatter = FormatHandle(this.workBook!!, -1)
+ }
+ formatter!!.addCell(record)
+ }
+
+ /**
+ * Sets a default "empty" value appropriate for the cell type of this CellHandle
+ *
+ * For example, will set the value to 0.0 for TYPE_DOUBLE, an empty String for
+ * TYPE_BLANK
+ */
+ fun setToDefault() {
+ `val` = this.defaultVal
+ }
+
+ /**
+ * Convenience method for toggling the bold state of the Font used by this Cell.
+ *
+ * @param boolean bold - true if bold
+ */
+ fun setBold(bold: Boolean) {
+ setFormatHandle()
+ formatter!!.bold = bold
+ }
+
+ /**
+ * set the Foreground Color for this Cell.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param int t - Excel color constant
+ * @see FormatHandle.COLOR constants
+ */
+ fun setForegroundColor(t: Int) {
+ setFormatHandle()
+ formatter!!.foregroundColor = t
+ }
+
+ /**
+ * set the Foreground Color for this Cell
+ * NOTE: this is the PATTERN Color
+ *
+ * @param int Excel color constant
+ * @see FormatHandle.COLOR constants
+ */
+ // TODO: is this doc correct?
+ fun setForeColor(i: Int) {
+ if (record!!.myxf == null)
+ this.newXf
+ record!!.myxf!!.setForeColor(i, null)
+ }
+
+ /**
+ * set the Background Color for this Cell.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param int t - Excel color constant
+ * @see FormatHandle.COLOR constants
+ */
+ fun setBackgroundColor(t: Int) {
+ setFormatHandle()
+ formatter!!.backgroundColor = t
+ }
+
+ /**
+ * sets the Color of the Cell Foreground pattern for this Cell.
+ *
+ *
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param java .awt.Color col - color for the foreground
+ */
+ fun setForegroundColor(col: Color) {
+ setFormatHandle()
+ formatter!!.setForegroundColor(col)
+ }
+
+ /**
+ * set the Color of the Cell Background pattern for this Cell.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param java .awt.Color col - background color
+ */
+ fun setBackgroundColor(col: Color) {
+ setFormatHandle()
+ formatter!!.setBackgroundColor(col)
+ }
+
+ /**
+ * set the Color of the Cell Background for this Cell.
+ *
+ * see FormatHandle.COLOR constants for valid values
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param int t - Excel color constant for Cell Background color
+ */
+ fun setCellBackgroundColor(t: Int) {
+ setFormatHandle()
+ formatter!!.cellBackgroundColor = t
+ }
+
+ /**
+ * set the Color of the Cell Background for this Cell.
+ *
+ * NOTE: Foreground color is the CELL BACKGROUND color for all patterns and
+ * Background color is the PATTERN color for all patterns not equal to
+ * PATTERN_SOLID
+ * For PATTERN_SOLID, the Foreground color is the CELL BACKGROUND color and
+ * Background Color is 64 (white).
+ *
+ * @param java .awt.Color col - color of the cell background
+ */
+ fun setCellBackgroundColor(col: Color) {
+ setFormatHandle()
+ formatter!!.setCellBackgroundColor(col)
+ }
+
+ /**
+ * set the Color of the Cell Background Pattern for this Cell.
+ *
+ * @param java .awt.Color col - color of the pattern background
+ */
+ fun setPatternBackgroundColor(col: Color) {
+ setFormatHandle()
+ formatter!!.setBackgroundColor(col)
+ }
+
+ /**
+ * set the Color of the Border for this Cell.
+ *
+ * @param java .awt.Color col - border color
+ */
+ fun setBorderColor(col: Color) {
+ setFormatHandle()
+ formatter!!.setBorderColor(col)
+ }
+
+ /**
+ * set the Color of the right Border line for this Cell.
+ *
+ * @param java .awt.Color col - right border color
+ */
+ fun setBorderRightColor(col: Color) {
+ setFormatHandle()
+ formatter!!.borderRightColor = col
+ }
+
+ /**
+ * set the Color of the left Border line for this Cell.
+ *
+ * @param java .awt.Color col - left border color
+ */
+ fun setBorderLeftColor(col: Color) {
+ setFormatHandle()
+ formatter!!.borderLeftColor = col
+ }
+
+ /**
+ * set the Color of the top Border line for this Cell.
+ *
+ * @param java .awt.Color col - top border color
+ */
+ fun setBorderTopColor(col: Color) {
+ setFormatHandle()
+ formatter!!.borderTopColor = col
+ }
+
+ /**
+ * set the Color of the bottom Border line for this Cell.
+ *
+ * @param java .awt.Color col - bottom border color
+ */
+ fun setBorderBottomColor(col: Color) {
+ setFormatHandle()
+ formatter!!.borderBottomColor = col
+ }
+
+ /**
+ * set the Border line style for this Cell.
+ *
+ * @param short s - border constant
+ * @see FormatHandle.BORDER line style constants
+ */
+ fun setBorderLineStyle(s: Short) {
+ setFormatHandle()
+ formatter!!.setBorderLineStyle(s)
+ }
+
+ /**
+ * set the Right Border line style for this Cell.
+ *
+ * @param short s - border constant
+ * @see FormatHandle.BORDER line style constants
+ */
+ fun setRightBorderLineStyle(s: Short) {
+ setFormatHandle()
+ formatter!!.rightBorderLineStyle = s
+ }
+
+ /**
+ * set the Left Border line style for this Cell.
+ *
+ * @param short s - border constant
+ * @see FormatHandle.BORDER line style constants
+ */
+ fun setLeftBorderLineStyle(s: Short) {
+ setFormatHandle()
+ formatter!!.leftBorderLineStyle = s
+ }
+
+ /**
+ * set the Top Border line style for this Cell.
+ *
+ * @param short s - border constant
+ * @see FormatHandle.BORDER line style constants
+ */
+ fun setTopBorderLineStyle(s: Short) {
+ setFormatHandle()
+ formatter!!.topBorderLineStyle = s
+ }
+
+ /**
+ * set the Bottom Border line style for this Cell.
+ *
+ * @param short s - border constant
+ * @see FormatHandle.BORDER line style constants
+ */
+ fun setBottomBorderLineStyle(s: Short) {
+ setFormatHandle()
+ formatter!!.bottomBorderLineStyle = s
+ }
+
+ /**
+ * removes the borders for this cell
+ */
+ fun removeBorder() {
+ setFormatHandle()
+ formatter!!.removeBorders()
+ }
+
+ /**
+ * Set the Font for this Cell via font name, font style and font size
+ * This method adds a new Font to the WorkBook.
+ * Roughly matches the functionality of the java.awt.Font class.
+ *
+ * @param String fn - system name of the font e.g. "Arial"
+ * @param int stl - font style (either Font.BOLD or Font.PLAIN)
+ * @param int sz - font size in points
+ */
+ fun setFont(fn: String, stl: Int, sz: Int) {
+ setFormatHandle()
+ formatter!!.setFont(fn, stl, sz.toDouble())
+ }
+
+ /**
+ * Removes any note/comment records attached to this cell
+ */
+ fun removeComment() {
+ try {
+ val note = this.comment
+ note.remove()
+ } catch (e: DocumentObjectNotFoundException) {
+ }
+
+ }
+
+ /**
+ * Creates a new annotation (Note or Comment) to the cell
+ *
+ * @param comment -- text of note
+ * @param author -- name of author
+ * @return CommentHandle - handle which allows access to the Note object
+ * @see CommentHandle
+ */
+ fun createComment(comment: String, author: String): CommentHandle {
+ val n = record!!.sheet!!.createNote(this.cellAddress, comment, author)
+ return CommentHandle(n)
+ }
+
+ /**
+ * set the Font Color for this Cell
+ *
+ * see FormatHandle.COLOR constants for valid values
+ *
+ * @param int t - Excel color constant
+ */
+ fun setFontColor(t: Int) {
+ setFormatHandle()
+ formatter!!.setFontColor(t)
+ }
+
+ fun setBlankRef(c: Int) {
+ mulblankcolnum = c.toShort()
+ }
+
+ /**
+ * Gets the value of the cell as a String with the number format applied.
+ * Boolean cell types will return "true" or "false". Custom number formats are
+ * not currently supported, although they will be written correctly to the
+ * output file. Patterns that display negative numbers in red are not currently
+ * supported; the number will be prefixed with a minus sign instead. For more
+ * information on number format patterns see
+ * [Microsoft KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @param formatForXML if true non-compliant characters will be properly qualified
+ * @return the value of the cell as a string formatted according to the cell
+ * type and, if present, the number format pattern
+ */
+ fun getFormattedStringVal(formatForXML: Boolean): String {
+ val myfmt = this.formatHandle
+ var `val` = this.`val`!!.toString()
+ if (formatForXML)
+ `val` = io.starter.formats.XLS.OOXMLAdapter.stripNonAscii(`val`).toString()
+ return CellFormatFactory.fromPatternString(myfmt!!.formatPattern).format(`val`)
+ }
+
+ /**
+ * Returns the value of the Cell as a String.
+ * For numeric cell values, including cells containing a formula which return a
+ * numeric value, the notation to be used in representing the value as a String
+ * must be specified.
+ * The Notation choices are:
+ * * CellHandle.NOTATION_STANDARD e.g. "8002974342"
+ * * CellHandle.NOTATION_SCIENTIFIC e.g. "8.002974342E9"
+ * * CellHandle.NOTATION_SCIENTIFIC_EXCEL e.g. "8.002974342+E9"
+ *
+ * For non-numeric values, the value of the cell as a string is returned
+ * boolean Cell types will return "true" or "false"
+ *
+ * @param int notation one of the CellHandle.NOTATION constants for numeric cell
+ * types; ignored for other cell types
+ * @param int notation - notation constant
+ * @return String the value of the Cell
+ */
+ fun getStringVal(notation: Int): String? {
+ val numval = record!!.stringVal
+ val i = this.cellType
+ return if (i == TYPE_FP || i == TYPE_INT || i == TYPE_FORMULA || i == TYPE_DOUBLE) {
+ ExcelTools.formatNumericNotation(numval!!, notation)
+ } else numval
+ }
+
+ /**
+ * Returns the value of the Cell as a String with the specified encoding.
+ * boolean Cell types will return "true" or "false"
+ *
+ * @param String encoding
+ * @return String the value of the Cell
+ */
+ fun getStringVal(encoding: String): String? {
+ return record!!.getStringVal(encoding)
+ }
+
+ /**
+ * move this cell to another row
+ * throws CellPositionConflictException if there is a cell in that position
+ * already
+ *
+ * @param int newrow - new row number
+ * @throws CellPositionConflictException
+ */
+ @Throws(CellPositionConflictException::class)
+ fun moveToRow(newrow: Int) {
+ var newaddr = ExcelTools.getAlphaVal(record!!.colNumber.toInt())
+ newaddr += newrow.toString()
+ this.moveTo(newaddr)
+ }
+
+ /**
+ * move this cell to another row
+ * overwrite any cells in the destination
+ *
+ * @param int newrow - new row number
+ */
+ fun moveAndOverwriteToRow(newrow: Int) {
+ var newaddr = ExcelTools.getAlphaVal(record!!.colNumber.toInt())
+ newaddr += newrow.toString()
+ this.moveAndOverwriteTo(newaddr)
+ }
+
+ /**
+ * move this cell to another column
+ * throws CellPositionConflictException if there is a cell in that position
+ * already
+ *
+ * @param String newcol - the new column in alpha format e.g. "A", "B" ...
+ * @throws CellPositionConflictException
+ */
+ @Throws(CellPositionConflictException::class)
+ fun moveToCol(newcol: String) {
+ var newaddr = newcol
+ newaddr += (record!!.rowNumber + 1).toString()
+ this.moveTo(newaddr)
+ }
+
+ /**
+ * Copy all formats from a source Cell to this Cell
+ *
+ * @param CellHandle source - source cell
+ */
+ fun copyFormat(source: CellHandle) {
+ this.cell!!.copyFormat(source.cell)
+ }
+
+ /**
+ * copy this Cell to another location.
+ *
+ * @param String newaddr - address for copy of this Cell in Excel-style e.g. "A1"
+ * @return returns the newly copied CellHandle
+ * @throws CellPositionConflictException if there is a cell in the new address already
+ */
+ @Throws(CellPositionConflictException::class)
+ fun copyTo(newaddr: String): CellHandle {
+
+ // check for existing
+ val bs = this.record!!.sheet
+
+ val rec = this.record
+ val nucell = (rec as XLSRecord).clone() as XLSRecord
+ val rc = ExcelTools.getRowColFromString(newaddr)
+ nucell.rowNumber = rc[0]
+ nucell.setCol(rc[1].toShort())
+ nucell.setXFRecord(this.record!!.ixfe)
+ bs!!.addRecord(nucell, rc)
+
+ val ret = CellHandle(nucell, workBook)
+ if (record!!.hyperlink != null) {
+ // set the bounds of the mycell.hyperlink
+ ret.url = this.url
+ }
+ ret.workSheetHandle = this.workSheetHandle
+ // this.getWorkSheetHandle().cellhandles.put(this.getCellAddress(),
+ // this);
+ return ret
+ }
+
+ /**
+ * Removes this Cell from the WorkSheet
+ *
+ * @param boolean nullme - true if this CellHandle should be nullified after removal
+ */
+ fun remove(nullme: Boolean) {
+ record!!.sheet!!.removeCell(record!!)
+ if (nullme) {
+ try {
+ this.finalize()
+ } catch (t: Throwable) {
+ }
+
+ }
+ }
+
+ /**
+ * move this cell to another location.
+ *
+ * @param String newaddr - the new address for Cell in Excel-style notation e.g.
+ * "A1"
+ * @throws CellPositionConflictException if there is a cell in the new address already
+ */
+ @Throws(CellPositionConflictException::class)
+ fun moveTo(newaddr: String) {
+
+ // check for existing
+ val bs = record!!.sheet
+ val oldhand = bs!!.getCell(newaddr)
+ if (oldhand != null)
+ throw CellPositionConflictException(newaddr)
+ bs.moveCell(this.cellAddress, newaddr)
+
+ if (record!!.hyperlink != null) {
+ // set the bounds of the mycell.hyperlink
+ // int[] bnds =
+ // ExcelTools.getRowColFromString(this.getCellAddress());
+
+ val bnds = ExcelTools.getRowColFromString(this.cellAddress)
+
+ val hl = record!!.hyperlink
+ hl!!.rowFirst = bnds[0]
+ hl.rowLast = bnds[0]
+ hl.colFirst = bnds[1]
+ hl.colLast = bnds[1]
+ hl.init()
+ }
+ }
+
+ /**
+ * move this cell to another location, overwriting any cells that are in the way
+ *
+ * @param String newaddr - the new address for Cell in Excel-style notation e.g.
+ * "A1"
+ */
+ fun moveAndOverwriteTo(newaddr: String) {
+
+ // check for existing
+ val bs = record!!.sheet
+ val oldhand = bs!!.getCell(newaddr)
+ bs.moveCell(this.cellAddress, newaddr)
+
+ if (record!!.hyperlink != null) {
+ val bnds = ExcelTools.getRowColFromString(this.cellAddress)
+
+ val hl = record!!.hyperlink
+ hl!!.rowFirst = bnds[0]
+ hl.rowLast = bnds[0]
+ hl.colFirst = bnds[1]
+ hl.colLast = bnds[1]
+ hl.init()
+ }
+ }
+
+ /**
+ * Set a conditional format upon this cell.
+ *
+ *
+ * Note that conditional format handles are bound to a specific worksheet,
+ *
+ * @param format A ConditionalFormatHandle in the same worksheet
+ */
+ fun addConditionalFormat(format: ConditionalFormatHandle) {
+ format.addCell(this)
+ }
+
+ /**
+ * Resets this cell's format to the default.
+ */
+ fun clearFormats() {
+ this.formatId = this.workBook!!.workBook.defaultIxfe
+ }
+
+ /**
+ * Resets this cells contents to blank.
+ */
+ fun clearContents() {
+ this.`val` = null
+ }
+
+ /**
+ * Resets this cell to the default, as if it had just been added.
+ */
+ fun clear() {
+ this.clearFormats()
+ this.clearContents()
+ }
+
+ /**
+ * returns true if this Cell contains a hyperlink
+ *
+ * @return boolean true if this Cell contains a hyperlink
+ */
+ fun hasHyperlink(): Boolean {
+ return record!!.hyperlink != null
+ }
+
+ /**
+ * Creates a new Hyperlink for this Cell from a URL String, a descrpiton and
+ * textMark text.
+ *
+ * The URL String Can be any valid URL. This URL String must include the
+ * protocol. For Example, "http://www.extentech.com/"
+ * The textMark text is the porition of the URL that follows #
+ *
+ * NOTE: URL text and textMark text must not be null or ""
+ *
+ * @param String urlstr - the URL String
+ * @param String desc - the description text
+ * @param String textMark - the text that follows #
+ */
+ fun setURL(urlstr: String, desc: String, textMark: String) {
+ if (record!!.hyperlink != null) {
+ record!!.hyperlink!!.setURL(urlstr, desc, textMark)
+ } else {
+ // create new URL
+ record!!.hyperlink = Hlink.prototype as Hlink?
+ record!!.hyperlink!!.setURL(urlstr, desc, textMark)
+
+ // why would we want to set the val during this operation?
+ // if (!desc.equals("")) setVal(desc);
+
+ // set the bounds of the mycell.hyperlink
+ val bnds = ExcelTools.getRowColFromString(this.cellAddress)
+ record!!.hyperlink!!.rowFirst = bnds[0]
+ record!!.hyperlink!!.colFirst = bnds[1]
+ record!!.hyperlink!!.rowLast = bnds[0]
+ record!!.hyperlink!!.colLast = bnds[1]
+ }
+ }
+
+ /**
+ * Sets a hyperlink to a location within the current template
+ * The URL String should be prefixed with "file://"
+ *
+ * @param String fileURLStr - the file URL String
+ */
+ // TODO: document this: NOTE: Excel File URL in actuality does not match
+ // documentation
+ fun setFileURL(fileURLStr: String) {
+ setFileURL(fileURLStr, "", "")
+ }
+
+ /**
+ * Sets a hyperlink to a location within the current template, and includes
+ * additional optional information: description + textMark text
+ *
+ * The URL String should be prefixed with "file://"
+ *
+ * The textMark text is the porition of the URL that follows #
+ *
+ * @param String fileURLstr - the file URL String
+ * @param String desc - the description text
+ * @param String textMark - text that follows #
+ */
+ // TODO: this documentation is contradictory
+ fun setFileURL(fileURLstr: String, desc: String, textMark: String) {
+ if (record!!.hyperlink != null) {
+ record!!.hyperlink!!.setFileURL(fileURLstr, desc, textMark)
+ } else {
+ record!!.hyperlink = Hlink.prototype as Hlink?
+
+ record!!.hyperlink!!.setFileURL(fileURLstr, desc, textMark)
+ if (desc != "")
+ `val` = desc
+
+ // set the bounds of the mycell.hyperlink
+ val bnds = ExcelTools.getRowColFromString(this.cellAddress)
+ record!!.hyperlink!!.rowFirst = bnds[0]
+ record!!.hyperlink!!.colFirst = bnds[1]
+ record!!.hyperlink!!.rowLast = bnds[0]
+ record!!.hyperlink!!.colLast = bnds[1]
+ }
+ }
+
+ /**
+ * set the value of this cell to Unicodestring us
+ * NOTE: This method will not check for formula references or do any data
+ * conversions
+ * Useful when strings may start with = but you do not want to convert to a
+ * formula value
+ *
+ * @param Unicodestring us - Unicode String
+ * @throws CellTypeMismatchException
+ */
+ fun setStringVal(us: Unicodestring?) {
+ try {
+ if ((us == null || us.toString() == "") && record !is Blank)
+ changeCellType(null) // set to blank
+ else if (us != null && us.toString() != "") {
+ if (record !is Labelsst)
+ changeCellType(" ") // avoid potential issues with string
+ // values beginning with "="
+ (record as Labelsst).setStringVal(us)
+ }
+ } catch (e: Exception) {
+ throw CellTypeMismatchException(e.toString())
+ }
+
+ }
+
+ /**
+ * this method will be fired as each record is parsed from an input Spreadsheet
+ *
+ *
+ * Dec 15, 2010
+ */
+ fun fireParserEvent() {
+
+ }
+
+ /**
+ * Returns a String representation of this CellHandle
+ *
+ * @see java.lang.Object.toString
+ */
+ override fun toString(): String {
+ var ret = this.cellAddress + ":" + this.stringVal
+ if (this.url != null)
+ ret += this.url
+ return ret
+ }
+
+ /**
+ * Set the Value of the Cell to a double
+ *
+ * @param double d- double value to set this Cell to
+ * @throws CellTypeMismatchException
+ */
+ @Throws(CellTypeMismatchException::class)
+ fun setVal(d: Double) {
+ this.`val` = d
+ }
+
+ /**
+ * Set value of this Cell to a Float
+ *
+ * @param float f - float value to set this Cell to
+ * @throws CellTypeMismatchException
+ */
+ @Throws(CellTypeMismatchException::class)
+ fun setVal(f: Float) {
+ this.`val` = f
+ }
+
+ /**
+ * Sets the value of this Cell to a java.sql.Date.
+ * You must also specify a formatting pattern for the new date, or null for the
+ * default date format ("m/d/yy h:mm".)
+ *
+ * valid date format patterns:
+ * "m/d/y"
+ * "d-mmm-yy"
+ * "d-mmm"
+ * "mmm-yy"
+ * "h:mm AM/PM"
+ * "h:mm:ss AM/PM"
+ * "h:mm"
+ * "h:mm:ss"
+ * "m/d/yy h:mm"
+ * "mm:ss"
+ * "[h]:mm:ss"
+ * "mm:ss.0"
+ *
+ * @param java .sql.Date dt - the value of the new Cell
+ * @param String fmt - date formatting pattern
+ */
+ fun setVal(dt: java.sql.Date, fmt: String?) {
+ var fmt = fmt
+
+ if (this.workBook!!.formulaCalculationMode != WorkBook.CALCULATE_EXPLICIT)
+ this.clearAffectedCells() // blow out cache
+ if (fmt == null)
+ fmt = "m/d/yyyy"
+ this.`val` = DateConverter.getXLSDateVal(dt)
+ this.formatPattern = fmt
+ }
+
+ /**
+ * Sets the value of this Cell to a boolean value
+ *
+ * @param boolean b - boolean value to set this Cell to
+ * @throws CellTypeMismatchException
+ */
+ @Throws(CellTypeMismatchException::class)
+ fun setVal(b: Boolean) {
+ `val` = java.lang.Boolean.valueOf(b)
+ }
+
+ /**
+ * Set the value of this Cell to an int value
+ * NOTE: setting a Boolean Cell type to a zero or a negative number will set the
+ * Cell to 'false'; setting it to an int value 1 or greater will set it to true.
+ *
+ * @param int i - int value to set this Cell to
+ * @throws CellTypeMismatchException
+ */
+ @Throws(CellTypeMismatchException::class)
+ fun setVal(i: Int) {
+ if (record!!.cellType == XLSConstants.TYPE_BOOLEAN) {
+ if (i > 0)
+ `val` = java.lang.Boolean.valueOf(true)
+ else
+ `val` = java.lang.Boolean.valueOf(false)
+ } else {
+ `val` = Integer.valueOf(i)
+ }
+ }
+
+ /**
+ * Set a cell to Excel-compatible formula passed in as String.
+ *
+ * @param String formStr - the Formula String
+ * @throws FunctionNotSupportedException if unable to parse string correctly
+ */
+ @Throws(FunctionNotSupportedException::class)
+ fun setFormula(formStr: String) {
+ val ixfe = this.record!!.ixfe
+ this.remove(true)
+ this.record = workSheetHandle!!.add(formStr, this.cellAddress)!!.record
+ this.record!!.setXFRecord(ixfe)
+ }
+
+ /**
+ * Set a cell to formula passed in as String. Sets the cachedValue as well, so
+ * no calculating is necessary.
+ *
+ *
+ * Parses the string to convert into a Excel formula.
+ * IMPORTANT NOTE: if cell is ALREADY a formula String this method will NOT
+ * reset it
+ *
+ * @param String formulaStr - The excel-compatible formula string to pass in
+ * @param Object value - The calculated value of the formula
+ * @throws Exception if unable to parse string correctly
+ */
+ @Throws(Exception::class)
+ fun setFormula(formStr: String, value: Any) {
+ if (this.record !is Formula) {
+ val ixfe = this.record!!.ixfe
+ val cr = this.record!!.mergeRange
+ val r = this.rowNum
+ val c = this.colNum
+ this.remove(true)
+ this.record = workSheetHandle!!.add(formStr, r, c, ixfe)!!.record
+ this.record!!.mergeRange = cr
+ }
+ val f = this.record as Formula?
+ f!!.setCachedValue(value)
+ }
+
+ /**
+ * sets the formula for this cellhandle using a stack of Ptgs appropriate for
+ * formula records. This method also sets the cachedValue of the formula as
+ * well, so no new calculating is necessary.
+ *
+ * @param Stack newExp - Stack of Ptgs
+ * @param Object value - calculated value of formula
+ */
+ fun setFormula(newExp: Stack<*>, value: Any) {
+ if (this.record !is Formula) {
+ val ixfe = this.record!!.ixfe
+ val mccr = this.record!!.mergeRange
+ val r = this.rowNum
+ val c = this.colNum
+ this.remove(true)
+ this.record = workSheetHandle!!.add("=0", r, c, ixfe)!!.record // add the most
+ // basic formula so
+ // can modify below
+ // ((:
+ this.record!!.mergeRange = mccr
+ }
+ try {
+ val f = this.record as Formula?
+ f!!.expression = newExp
+ f.setCachedValue(value)
+ } catch (e: Exception) {
+ // do what??
+ }
+
+ }
+
+ /**
+ * Returns the size of the merged cell area, if one exists.
+ *
+ * @param row this parameter is ignored
+ * @param column this parameter is ignored
+ * @return a 2 position int array with number of rows and number of cols
+ */
+ @Deprecated("since October 2012. This method duplicates the functionality of\n" +
+ " {@link #getMergedCellRange()}, which it calls internally. That\n" +
+ " method should be used instead.")
+ fun getSpan(row: Int, column: Int): IntArray? {
+ val mergerange = mergedCellRange
+ if (mergerange != null) {
+ if (DEBUG)
+ Logger.logInfo("CellHandle $this getSpan() for range: $mergerange")
+ val ret = intArrayOf(0, 0)
+ // if(check.toString().equals(this.toString())){ //it's the first in
+ // the range -- show it!
+ try {
+ ret[0] = mergerange.rows.size
+ ret[1] = mergerange.cols.size // TODO: test!
+ } catch (e: Exception) {
+ Logger.logWarn("CellHandle getting CellSpan failed: $e")
+ }
+
+ // }
+ return ret
+ }
+ return null
+ }
+
+ /**
+ * Returns an XML representation of the cell and it's component data
+ *
+ * @param int[] mergedRange - include merged ranges in the XML representation if
+ * not null
+ * @return String of XML
+ */
+ fun getXML(mergedRange: IntArray?): String {
+ val vl = ""
+ var fvl = ""
+ var sv = ""
+ var hd = ""
+ var csp = ""
+ var hlink = ""
+ var `val`: Any? = null
+ val retval = StringBuffer()
+ var typename = this.cellTypeName
+ // put the formula string in
+ if (typename == "Formula") {
+ try {
+ val fmh = formulaHandle
+ val fms = fmh.formulaString
+ // use single quotes around formula value to avoid errors in
+ // xslt transform
+ if (fms.indexOf("\"") > 0) {
+ fvl = " Formula='" + StringTool.convertXMLChars(fms) + "'"
+ } else {
+ fvl = " Formula=\"" + StringTool.convertXMLChars(fms) + "\""
+ }
+ try {
+ if (this.workBook!!.workBook.calcMode != WorkBook.CALCULATE_EXPLICIT) {
+ `val` = fmh.calculate()
+ } else {
+ try {
+ // changed from getVal() now that getVal returns a
+ // null
+ `val` = fmh.stringVal
+ } catch (e: Exception) {
+ Logger.logWarn("CellHandle.getXML formula calc failed: $e")
+ }
+
+ }
+ if (`val` is Float)
+ typename = "Float"
+ else if (`val` is Double)
+ typename = "Double"
+ else if (`val` is Int)
+ typename = "Integer"
+ else if (`val` is java.util.Date || `val` is java.sql.Date
+ || `val` is java.sql.Timestamp)
+ typename = "DateTime"
+ else
+ typename = "String"
+ } catch (e: Exception) {
+ typename = "String" // default
+ }
+
+ } catch (e: Exception) {
+ Logger.logErr("OpenXLS.getXML() failed getting type of Formula for: $this", e)
+ }
+
+ }
+ if (this.isDate)
+ typename = "DateTime" // 20060428 KSC: Moved after Formula parsing
+
+ // TODO: when RowHandle.getCells actually contains ALL cells, keep this
+ if (this.record!!.opcode != XLSConstants.MULBLANK) {
+ // Put the style ID in
+ sv = " StyleID=\"s$formatId\""
+ if (mergedRange != null) { // TODO: fix!
+ csp += " MergeAcross=\"" + (mergedRange[3] - mergedRange[1] + 1) + "\""
+ csp += " MergeDown=\"" + (mergedRange[2] - mergedRange[0]) + "\""
+ }
+ if (this.col.isHidden) {
+ hd = " Hidden=\"true\""
+ }
+ // TODO: HRefScreenTip ????
+ if (this.url != null) {
+ hlink = " HRef=\"" + StringTool.convertXMLChars(this.url) + "\""
+ }
+
+ // put the date formattingin
+ // Assemble the string
+ retval.append("")
+ if (typename == "DateTime") {
+ retval.append(DateConverter.getFormattedDateVal(this))
+ } else if (this.cellType == CellHandle.TYPE_STRING) {
+ `val` = this.stringVal // (String)getVal();
+ if (`val` == "") { // 20070216 KSC: John, had the same edits,
+ // seems to work well in cursory tests ...
+ // retval.append(" "); does this screw up formulas expecting
+ // empty strings? -jm
+ } else {
+ retval.append(StringTool.convertXMLChars(`val`!!.toString()))
+ }
+ } else {
+ try {
+ // if(val == null)
+ `val` = this.`val`
+ retval.append(StringTool.convertXMLChars(`val`!!.toString()) + vl)
+ } catch (e: Exception) {
+ Logger.logErr("CellHandle.getXML failed for: " + this.cellAddress + " in: "
+ + this.workBook!!.toString(), e)
+ retval.append("XML ERROR!")
+ }
+
+ }
+ retval.append(" ")
+ retval.append(end_cell_xml)
+ } else {
+ var c = (this.record as Mulblank).colFirst
+ val lastcol = (this.record as Mulblank).colLast
+ while (c <= lastcol) {
+ mulblankcolnum = c.toShort()
+ // Put the style ID in
+ sv = " StyleID=\"s$formatId\""
+ if (this.col.isHidden) {
+ hd = " Hidden=\"true\""
+ }
+ // TODO: HRefScreenTip ????
+ if (this.url != null) {
+ hlink = " HRef=\"" + StringTool.convertXMLChars(this.url) + "\""
+ }
+
+ // put the date formattingin
+ // Assemble the string
+ retval.append(" ")
+ retval.append(end_cell_xml)
+ c++
+ }
+ }
+ return retval.toString()
+ }
+
+ override fun compareTo(that: CellHandle): Int {
+ val comp = this.rowNum - that.rowNum
+ return if (comp != 0) comp else this.colNum - that.colNum
+ }
+
+ override fun equals(that: Any?): Boolean {
+ return if (that !is CellHandle) false else this.record == that.record
+ }
+
+ override fun hashCode(): Int {
+ return this.record!!.hashCode()
+ }
+
+ /**
+ * Set the super/sub script for the Font
+ *
+ * @param int ss - super/sub script constant (0 = none, 1 = super, 2 = sub)
+ */
+ fun setScript(ss: Int) {
+ if (record!!.myxf == null)
+ this.newXf
+ record!!.myxf!!.font!!.script = ss
+ }
+
+ /**
+ * Set the val of the biffrec with an Object
+ *
+ * @param Object to set the value of the Cell to
+ */
+ @Throws(CellTypeMismatchException::class)
+ private fun setBiffRecValue(obj: Any?) {
+ if (record!!.opcode == XLSConstants.BLANK || record!!.opcode == XLSConstants.MULBLANK) {
+ // no reason for this Blank blank = (Blank)mycell;
+ // String addr = mycell.getCellAddress();
+
+ // trim the Mulblank
+ /*
+ * KSC: mulblanks are NOT expanded now if (blank.getMyMul() != null){ Mulblank
+ * mblank = (Mulblank)blank.getMyMul(); mblank.trim(blank); }
+ */
+ changeCellType(obj) // 20080206 KSC: Basically replaces all above
+ // code
+ } else {
+ if (obj == null) {
+ // should never be false ??? if (!(mycell instanceof Blank))
+ changeCellType(obj) // will set to blank
+ } else if (obj is Float || obj is Double || obj is Int || obj is Long) {
+ if (record is NumberRec || record is Rk) {
+ if (obj is Float) {
+ val f = obj as Float?
+ record!!.floatVal = f!!.toFloat()
+ } else if (obj is Int) {
+ val i = obj as Int?
+ record!!.intVal = i!!.toInt()
+ } else if (obj is Double) {
+ val d = obj as Double?
+ record!!.setDoubleVal(d!!.toDouble())
+ } else if (obj is Long) {
+ val d = obj as Long?
+ record!!.setDoubleVal(d!!.toLong().toDouble())
+ }
+ } else
+ changeCellType(obj)
+ } else if (obj is Boolean) {
+ if (record is Boolerr)
+ record!!.booleanVal = obj.booleanValue()
+ else
+ changeCellType(obj)
+ } else if (obj is String) {
+ if (obj.startsWith("="))
+ changeCellType(obj) // easier to just redo a formula...
+ else if (!obj.toString().equals("", ignoreCase = true)) {
+ if (record is Labelsst)
+ record!!.stringVal = obj.toString()
+ else
+ changeCellType(obj)
+ } else if (record !is Blank)
+ changeCellType(obj)
+ }
+ }
+ }
+
+ /**
+ * if object type doesn't match current mycell record, remove and add
+ * appropriate record type
+ *
+ * @param obj
+ */
+ private fun changeCellType(obj: Any?) {
+ val rc = intArrayOf(record!!.rowNumber, record!!.colNumber.toInt())
+ val bs = record!!.sheet
+ val oldXf = record!!.ixfe
+ bs!!.removeCell(record!!)
+ val addedrec = bs.addValue(obj, rc, true)
+ record = addedrec as XLSRecord
+ record!!.setXFRecord(oldXf)
+ }
+
+ /**
+ * Calculates and returns all formulas that reference this CellHandle.
+ * Please note that these cells may have already been calculated, so in order to
+ * get their values without re-calculating them Extentech suggests setting the
+ * book level non-calculation flag, ie
+ * book.setFormulaCalculationMode(WorkBookHandle.CALCULATE_EXPLICIT); or
+ * FormulaHandle.getCachedVal()
+ *
+ * @return List of of calculated cells (CellHandles)
+ */
+ fun calculateAffectedCells(): List {
+ val rt = this.workBook!!.workBook.refTracker
+ val its = rt!!.clearAffectedFormulaCells(this).values.iterator()
+
+ val ret = ArrayList()
+ while (its.hasNext()) {
+ val cx = CellHandle(its.next() as BiffRec, this.workBook)
+ ret.add(cx)
+ }
+ return ret
+ }
+
+ /**
+ * Internal method for clearing affected cells, does the same thing as
+ * calculateAffectedCells, but does not create a list
+ */
+ fun clearAffectedCells() {
+ val rt = this.workBook!!.workBook.refTracker
+ rt!!.clearAffectedFormulaCells(this)
+ }
+
+ /**
+ * Calculates and returns all formulas on the same sheet that reference this
+ * CellHandle.
+ * Please note that these cells may have already been calculated, so in order to
+ * get their values without re-calculating them Extentech suggests setting the
+ * book level non-calculation flag, ie
+ * book.setFormulaCalculationMode(WorkBookHandle.CALCULATE_EXPLICIT); or
+ * FormulaHandle.getCachedVal()
+ *
+ * @return List of of calculated cells (CellHandles)
+ */
+ fun calculateAffectedCellsOnSheet(): List {
+ val its = this.workBook!!.workBook.refTracker!!
+ .clearAffectedFormulaCellsOnSheet(this, this.workSheetName).values.iterator()
+ val ret = ArrayList()
+ while (its.hasNext()) {
+ val cx = CellHandle(its.next() as BiffRec, this.workBook)
+ ret.add(cx)
+ }
+ return ret
+ }
+
+ /**
+ * flags chart references to the particular cell as dirty/ needing caches
+ * rebuilt
+ */
+ fun clearChartReferences() {
+ val ret = ArrayList()
+ val ii = this.workBook!!.workBook.refTracker!!.getChartReferences(this.cell!!).iterator()
+ while (ii.hasNext()) {
+ val ai = ii.next() as Ai
+ if (ai.parentChart != null)
+ ai.parentChart!!.setMetricsDirty()
+ }
+ }
+
+ /**
+ * Get a JSON Object representation of a cell utilizing a merged range
+ * identifier.
+ *
+ */
+ @Deprecated("The {@code mergedRange} parameter is unnecessary. This method\n" +
+ " will be removed in a future version. Use {@link #getJSONObject()}\n" +
+ " instead.")
+ fun getJSONObject(mergedRange: IntArray?): JSONObject {
+ val theCell = JSONObject()
+ try {
+ theCell.put(JSON_LOCATION, cellAddress)
+
+ var `val`: Any?
+ try {
+ `val` = `val`
+ if (`val` == null)
+ `val` = ""
+ } catch (ex: Exception) {
+ Logger.logWarn("OpenXLS.getJSONObject failed: $ex")
+ `val` = "#ERR!"
+ }
+
+ var typename = cellTypeName
+ val dataval = JSONObject()
+
+ if (typename == "Formula") {
+ try {
+ val fmh = formulaHandle
+ val fms = fmh.formulaString
+
+ theCell.put(JSON_CELL_FORMULA, fms)
+
+ try {
+ if (java.lang.Float.parseFloat(`val`!!.toString()) == java.lang.Float.NaN) {
+ typename = JSON_FLOAT
+ } else if (`val` is Float)
+ typename = JSON_FLOAT
+ else if (`val` is Double)
+ typename = JSON_DOUBLE
+ else if (`val` is Int)
+ typename = JSON_INTEGER
+ else if (`val` is java.util.Date || `val` is java.sql.Date
+ || `val` is java.sql.Timestamp) {
+ typename = JSON_DATETIME
+ } else
+ typename = JSON_STRING
+ } catch (e: Exception) {
+ typename = JSON_STRING // default
+ }
+
+ } catch (e: Exception) {
+ Logger.logErr("OpenXLS.getJSON() failed getting type of Formula for: " + toString(), e)
+ }
+
+ }
+
+ if (isDate)
+ typename = JSON_DATETIME
+
+ dataval.put(JSON_TYPE, typename)
+
+ // TODO: Handle Conditional Format
+ // cell should return the style id for its condition
+ // this is an ID that begins incrementing after the last Xf
+ // and should be contained in the CSS for the output
+
+ // if the conditional format evaluates to TRUE
+ // then we use *that* style ID not the default
+
+ // We can have multiple CF styles per cell, one per each rule... we'll need that
+ // from CSS standpoint so...
+
+ // style
+ theCell.put(JSON_STYLEID, conditionalFormatId)
+
+ // merges
+ if (mergedRange != null) {
+ theCell.put(JSON_MERGEACROSS, mergedRange[3] - mergedRange[1])
+ theCell.put(JSON_MERGEDOWN, mergedRange[2] - mergedRange[0])
+ if (isMergeParent) {
+ theCell.put(JSON_MERGEPARENT, true)
+ } else {
+ theCell.put(JSON_MERGECHILD, true)
+ }
+ }
+
+ // handle hidden setting
+ try {
+ if (col.isHidden)
+ theCell.put(JSON_HIDDEN, true)
+ } catch (e: Exception) {
+ }
+
+ // handle the locked/formula hidden setting
+ // only active if sheet is protected
+ try {
+ if (isFormulaHidden)
+ theCell.put(JSON_FORMULA_HIDDEN, true)
+
+ theCell.put(JSON_LOCKED, isLocked)
+ } catch (e: Exception) {
+ }
+
+ try {
+ val vh = validationHandle
+ if (vh != null)
+ theCell.put(JSON_VALIDATION_MESSAGE, vh.promptBoxTitle + ":" + vh.promptBoxText)
+ } catch (e: Exception) {
+ }
+
+ // hyperlinks
+ if (url != null)
+ theCell.put(JSON_HREF, url)
+
+ if (wrapText)
+ theCell.put(JSON_WORD_WRAP, true)
+
+ // store alignment for container issues
+ val alignment = formatHandle!!.horizontalAlignment
+ if (alignment == FormatHandle.ALIGN_RIGHT) {
+ theCell.put(JSON_TEXT_ALIGN, "right")
+ } else if (alignment == FormatHandle.ALIGN_CENTER) {
+ theCell.put(JSON_TEXT_ALIGN, "center")
+ } else if (alignment == FormatHandle.ALIGN_LEFT) {
+ theCell.put(JSON_TEXT_ALIGN, "left")
+ }
+
+ // dates
+ if (typename == JSON_DATETIME && `val` != null && `val` != "") {
+ dataval.put(JSON_CELL_VALUE, formattedStringVal)
+ // dataval.put(JSON_DATEVALUE, ch.getFloatVal());
+ dataval.put("time", DateConverter.getCalendarFromCell(this).timeInMillis)
+ } else if (cellType == CellHandle.TYPE_STRING) {
+ // FORCES CALC
+ if ((`val` as String).indexOf("\n") > -1) {
+ `val` = `val`.replace("\n".toRegex(), " ")
+ }
+ if (`val` != "")
+ dataval.put(JSON_CELL_VALUE, `val`.toString())
+ } else { // other
+ dataval.put(JSON_CELL_VALUE, `val`!!.toString())
+ try { // formatted pattern
+ val s = formatPattern
+ if (s != "") {
+ var fmtd = formattedStringVal // TRIGGERS CALC!
+ if (`val` != fmtd)
+ dataval.put(JSON_CELL_FORMATTED_VALUE, fmtd)
+ if (s!!.indexOf("Red") > -1) {
+ val d = Double(`val`.toString())
+ if (d < 0) {
+ theCell.put(JSON_RED_FORMAT, "1")
+ if (fmtd.indexOf("-") == 0)
+ fmtd = fmtd.substring(1)
+ dataval.put(JSON_CELL_FORMATTED_VALUE, fmtd)
+ }
+ }
+ }
+ } catch (x: Exception) {
+ }
+
+ }
+ theCell.put(JSON_DATA, dataval)
+ } catch (e: JSONException) {
+ Logger.logErr("error getting JSON for the cell: $e")
+ }
+
+ return theCell
+ }
+
+ companion object {
+
+ /**
+ *
+ */
+ private const val serialVersionUID = 4737120893891570607L
+ /**
+ * Cell types
+ */
+ val TYPE_BLANK = Cell.TYPE_BLANK
+ val TYPE_STRING = Cell.TYPE_STRING
+ val TYPE_FP = Cell.TYPE_FP
+ val TYPE_INT = Cell.TYPE_INT
+ val TYPE_FORMULA = Cell.TYPE_FORMULA
+ val TYPE_BOOLEAN = Cell.TYPE_BOOLEAN
+ val TYPE_DOUBLE = Cell.TYPE_DOUBLE
+ val NOTATION_STANDARD = 0
+ val NOTATION_SCIENTIFIC = 1
+ val NOTATION_SCIENTIFIC_EXCEL = 2
+
+ internal val begin_hidden_emptycell_xml = " | "
+
+ internal val begin_cell_xml = " | "
+ internal val end_cell_xml = " | "
+
+ /**
+ * Returns an xml representation of an empty cell
+ *
+ * @param loc - the cell address
+ * @param isVisible - if the cell is visible (not hidden)
+ * @return
+ */
+ protected fun getEmptyCellXML(loc: String, isVisible: Boolean): String {
+ return if (!isVisible) {
+ begin_hidden_emptycell_xml + loc + end_hidden_emptycell_xml
+ } else {
+ begin_cell_xml + loc + end_emptycell_xml
+ }
+ }
+
+ /**
+ * Creates a copy of this cell on the given worksheet at the given address.
+ *
+ * @param sourcecell the cell to copy
+ * @param newsheet the sheet to which the cell should be copied
+ * @param row the row in which the copied cell should be placed
+ * @param col the row in which the copied cell should be placed
+ * @param copyByValue whether to copy formulas' values instead of the formulas
+ * themselves
+ * @return CellHandle representing the new cell
+ */
+ @JvmOverloads
+ fun copyCellToWorkSheet(sourcecell: CellHandle, newsheet: WorkSheetHandle, row: Int, col: Int,
+ copyByValue: Boolean = false): CellHandle {
+ // copy cell values
+ var newcell: CellHandle? = null
+
+ val offsets = intArrayOf(row - sourcecell.rowNum, col - sourcecell.colNum)
+
+ if (sourcecell.isFormula && !copyByValue)
+ try {
+ val fmh = sourcecell.formulaHandle
+ newcell = newsheet.add(fmh.formulaString, row, col)
+ val fm2 = newcell!!.formulaHandle
+ FormulaHandle.moveCellRefs(fm2, offsets)
+ } catch (ex: FormulaNotFoundException) {
+ newcell = null
+ }
+
+ if (newcell == null)
+ newcell = newsheet.add(sourcecell.`val`, row, col)
+
+ return copyCellHelper(sourcecell, newcell!!)
+ }
+
+ /**
+ * Create a copy of this Cell in another WorkBook
+ *
+ * @param sourcecell the cell to copy
+ * @param target worksheet to copy this cell into
+ * @return
+ */
+ fun copyCellToWorkSheet(sourcecell: CellHandle, newsheet: WorkSheetHandle): CellHandle {
+ // copy cell values
+ var newcell: CellHandle? = null
+ try {
+ val fmh = sourcecell.formulaHandle
+ // Logger.logInfo("testFormats Formula encountered: "+
+ // fmh.getFormulaString());
+
+ newcell = newsheet.add(fmh.formulaString, sourcecell.cellAddress)
+ } catch (ex: FormulaNotFoundException) {
+ newcell = newsheet.add(sourcecell.`val`, sourcecell.cellAddress)
+ }
+
+ return copyCellHelper(sourcecell, newcell!!)
+ }
+
+ /**
+ * Copies all formatting - xf and non-xf (such as column width, hidden state)
+ * plus merged cell range from a sourcecell to a new cell (usually in a new
+ * workbook)
+ *
+ * @param sourcecell the cell to copy
+ * @param newcell the cell to copy to
+ * @return
+ */
+ protected fun copyCellHelper(sourcecell: CellHandle, newcell: CellHandle): CellHandle {
+ // copy row height & attributes
+ val rz = sourcecell.row.height
+ newcell.row.height = rz
+ if (sourcecell.row.isHidden) {
+ newcell.row.isHidden = true
+ }
+ // copy col width & attributes
+ val rzx = sourcecell.col.width
+ newcell.col.width = rzx
+ if (sourcecell.col.isHidden) {
+ newcell.col.isHidden = true
+ // Logger.logInfo("column " + rzx + " is hidden");
+ }
+
+ try {
+ // copy merged ranges
+ var rng = sourcecell.mergedCellRange
+ if (rng != null) {
+ rng = CellRange(rng.getRange(), newcell.workBook)
+ rng.addCellToRange(newcell)
+ rng.mergeCells(false)
+ }
+ // Handle formats:
+ val origxf = sourcecell.workBook!!.workBook.getXf(sourcecell.formatId)
+ newcell.formatHandle!!.addXf(origxf!!)
+ return newcell
+ } catch (ex: Exception) {
+ Logger.logErr("CellHandle.copyCellHelper failed.", ex)
+ }
+
+ return newcell
+ }
+ }
+
+}
+/**
+ * Creates a copy of this cell on the given worksheet at the given address.
+ *
+ * @param sourcecell the cell to copy
+ * @param newsheet the sheet to which the cell should be copied
+ * @param row the row in which the copied cell should be placed
+ * @param col the row in which the copied cell should be placed
+ * @return CellHandle representing the new Cell
+ */
diff --git a/src/main/java/io/starter/OpenXLS/CellRange.java b/src/main/java/io/starter/OpenXLS/CellRange.java
deleted file mode 100644
index 0c70226..0000000
--- a/src/main/java/io/starter/OpenXLS/CellRange.java
+++ /dev/null
@@ -1,2038 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import static io.starter.OpenXLS.JSONConstants.JSON_CELL;
-import static io.starter.OpenXLS.JSONConstants.JSON_CELLS;
-import static io.starter.OpenXLS.JSONConstants.JSON_CELL_VALUE;
-import static io.starter.OpenXLS.JSONConstants.JSON_LOCATION;
-import static io.starter.OpenXLS.JSONConstants.JSON_RANGE;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import io.starter.formats.XLS.BiffRec;
-import io.starter.formats.XLS.Blank;
-import io.starter.formats.XLS.Boundsheet;
-import io.starter.formats.XLS.CellNotFoundException;
-import io.starter.formats.XLS.CellRec;
-import io.starter.formats.XLS.ColumnNotFoundException;
-import io.starter.formats.XLS.Condfmt;
-import io.starter.formats.XLS.FormulaNotFoundException;
-import io.starter.formats.XLS.Mergedcells;
-import io.starter.formats.XLS.Name;
-import io.starter.formats.XLS.RowNotFoundException;
-import io.starter.formats.XLS.WorkSheetNotFoundException;
-import io.starter.formats.XLS.XLSConstants;
-import io.starter.formats.XLS.XLSRecord;
-import io.starter.formats.XLS.Xf;
-import io.starter.formats.XLS.formulas.FormulaParser;
-import io.starter.formats.XLS.formulas.GenericPtg;
-import io.starter.formats.XLS.formulas.Ptg;
-import io.starter.formats.XLS.formulas.PtgRef;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.StringTool;
-
-/**
- * Cell Range is a handle to a range of Workbook Cells
- *
- *
- * Contains useful methods for working with Collections of Cells.
- *
- * for example:
- *
- * CellRange cr = new CellRange("Sheet1!A1:B10", workbk);
- * cr.addCellToRange("C10");
- * CellHandle mycells = cr.getCells();
- * for(int x=0;x < mycells.length;x++)
- * Logger.logInfo(mycells[x].getCellAddress() + mycells[x].toString());
- * }
- *
- *
- *
- * Starter Inc.
- *
- * @see DataBoundCellRange
- * @see XLSRecord
- */
-public class CellRange implements Serializable {
-
- Condfmt cfx = null;
-
- /**
- * returns the conditional format object for this range, if any
- *
- * @return Condfmt object
- */
- protected Condfmt getConditionalFormat() {
- return cfx;
- }
-
- /**
- *
- *
- *
- */
- private static final long serialVersionUID = -3609881364824289079L;
- private boolean ismerged = false;
- private BiffRec parent = null; // if cell range is child of a named range, must ensure update correctly
- public static final boolean REMOVE_MERGED_CELLS = true;
- public static final boolean RETAIN_MERGED_CELLS = false;
- // private Ptg myptg = null;
- public boolean DEBUG = false;
- private boolean isDirty = false; // true if addCellsToRange without init
- int firstcellrow = -1;
- int firstcellcol = -1;
- int lastcellrow = -1;
- int lastcellcol = -1;
- private boolean createBlanks = false;
- private boolean initializeCells = true;
- public transient CellHandle[] cells;
- protected transient String range, sheetname;
- protected transient io.starter.OpenXLS.WorkBook mybook;
- private transient WorkSheetHandle sheet = null;
- private int[] myrowints;
- private int[] mycolints;
- private transient RowHandle[] myrows;
- private transient ColHandle[] mycols;
-
- // for OOXML External References
- protected int externalLink1 = 0;
- protected int externalLink2 = 0;
-
- FormatHandle fmtr = null;
- boolean wholeCol = false, wholeRow = false;
-
- /** Protected constructor for creating result ranges. */
- protected CellRange(WorkSheetHandle sheet, int row, int col, int width, int height) {
- this.sheet = sheet;
- sheetname = sheet.getSheetName();
- mybook = sheet.getWorkBook();
-
- firstcellrow = row;
- firstcellcol = col;
- lastcellrow = row + height - 1;
- lastcellcol = col + width - 1;
-
- range = sheetname + "!"
- + ExcelTools.formatRange(new int[] { firstcellcol, firstcellrow, lastcellcol, lastcellrow });
-
- cells = new CellHandle[width * height];
- }
-
- /**
- * Initializes a CellRange from a CellRangeRef. The
- * source CellRangeRef instance must be qualified with a single
- * resolved worksheet.
- *
- * @param source
- * the CellRangeRef from which to initialize
- * @param init
- * whether to populate the cell array
- * @param create
- * whether to fill gaps in the range with blank cells
- * @throws IllegalArgumentException
- * if the source range does not have a resolved sheet or has more
- * than one sheet
- */
- public CellRange(CellRangeRef source, boolean init, boolean create) {
- initializeCells = init;
- createBlanks = create;
-
- sheet = source.getFirstSheet();
- if (sheet == null || source.isMultiSheet())
- throw new IllegalArgumentException("the source range must have a single resolved sheet");
-
- mybook = this.sheet.getWorkBook();
- sheetname = this.sheet.getSheetName();
-
- // This is inefficient, but fixing it would require rewriting init.
- this.range = source.toString();
-
- try {
- this.init();
- } catch (CellNotFoundException e) {
- // this should be impossible
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Initializes a CellRange from a CellRangeRef. The
- * source CellRangeRef instance must be qualified with a single
- * resolved worksheet.
- *
- * @param source
- * the CellRangeRef from which to initialize
- * @throws IllegalArgumentException
- * if the source range does not have a resolved sheet or has more
- * than one sheet
- */
- public CellRange(CellRangeRef source) {
- this(source, false, true);
- }
-
- public void clearFormats() {
- for (int idx = 0; idx < cells.length; idx++)
- if (cells[idx] != null)
- cells[idx].clearFormats();
- }
-
- /**
- * @deprecated use clear()
- */
- @Deprecated
- public void clearContents() {
- for (int idx = 0; idx < cells.length; idx++)
- if (cells[idx] != null)
- cells[idx].clearContents();
- }
-
- /**
- * clears the contents and formats of the cells referenced by this range but
- * does not remove the cells from the workbook.
- *
- */
- public void clear() {
- for (int idx = 0; idx < cells.length; idx++)
- if (cells[idx] != null)
- cells[idx].clear();
- }
-
- /**
- * removes the cells referenced by this range from the sheet.
- *
- * NOTE: method does not shift rows or cols.
- *
- */
- public void removeCells() {
- for (int idx = 0; idx < cells.length; idx++)
- if (cells[idx] != null)
- cells[idx].remove(true);
- }
-
- /**
- * Un-Merge the Cells contained in this CellRange
- *
- * @throws Exception
- */
- public void unMergeCells() throws Exception {
- BiffRec[] mycells = this.getCellRecs();
- for (int t = 0; t < mycells.length; t++) {
- mycells[t].setMergeRange(null); // unset the range of merged cells
- mycells[t].getXfRec().setMerged(false);
- }
- Mergedcells mc = this.getSheet().getSheet().getMergedCellsRec();
- if (mc != null)
- mc.removeCellRange(this);
- this.ismerged = false;
- }
-
- /**
- * Set the format ID of all cells in this CellRange
- * FormatID can be obtained through any CellHandle with the getFormatID() call
- *
- * @param int
- * fmtID - the format ID to set the cells within the range to
- */
- public void setFormatID(int fmtID) throws Exception {
- BiffRec[] mycells = this.getCellRecs();
- for (int t = 0; t < mycells.length; t++) {
- mycells[t].setXFRecord(fmtID);
- }
- }
-
- /**
- * Set a hyperlink on all cells in this CellRange
- *
- * @param String
- * url - the URL String to set
- */
- public void setURL(String url) throws Exception {
- BiffRec[] mycells = this.getCellRecs();
- for (int t = 0; t < mycells.length; t++) {
- new CellHandle(mycells[t], this.mybook).setURL(url);
- }
- }
-
- /**
- * Merge the Cells contained in this CellRange
- *
- * @param boolean
- * remove - true to delete the Cells following the first in the range
- */
- public void mergeCells(boolean remove) {
- this.createBlanks();
- if (remove)
- this.mergeCellsClearFollowingCells();
- else
- this.mergeCellsKeepFollowingCells();
- }
-
- /**
- * Merge the Cells contained in this CellRange, clearing or removing the Cells
- * following the first in the range
- *
- */
- private void mergeCellsClearFollowingCells() {
- BiffRec[] mycells = this.getCellRecs();
-
- // mycells[0].setMergeRange(this); // set the range of merged cells
- Xf r = mycells[0].getXfRec();
- if (r == null) {
- fmtr = new FormatHandle(this.getWorkBook());
- fmtr.addCell(mycells[0]);
- r = mycells[0].getXfRec();
- }
- r.setMerged(true);
- for (int t = 0; t < mycells.length; t++) {
- if (mycells[t] != null)
- mycells[t].setSheet(this.getSheet().getMysheet());
- mycells[t].setMergeRange(this); // set the range of merged cells
- if (t > 0) {
- if (!(mycells[t] instanceof Blank)) {
- String cellname = mycells[t].getCellAddress();
- Boundsheet sheet = mycells[t].getSheet();
- mycells[t].remove(true); // blow it out!
- sheet.addValue(null, cellname);
- }
- }
- }
- Mergedcells mc = this.getSheet().getSheet().getMergedCellsRec();
- if (mc == null)
- mc = this.getSheet().getSheet().addMergedCellRec();
- mc.addCellRange(this);
- this.ismerged = true;
- }
-
- /**
- * Merge the Cells contained in this CellRange *
- */
- private void mergeCellsKeepFollowingCells() {
- BiffRec[] mycells = this.getCellRecs();
- for (int t = 0; t < mycells.length; t++) {
- mycells[t].setMergeRange(this); // set the range of merged cells
- Xf r = mycells[t].getXfRec();
- if (r == null) {
- fmtr = new FormatHandle(this.getWorkBook());
- fmtr.addCellRange(this);
- r = mycells[t].getXfRec();
- }
- r.setMerged(true);
- }
-
- Mergedcells mc = this.getSheet().getSheet().getMergedCellsRec();
- if (mc == null)
- mc = this.getSheet().getSheet().addMergedCellRec();
- mc.addCellRange(this);
- this.ismerged = true;
- }
-
- /**
- * Gets the number of columns in the range.
- */
- public int getWidth() {
- return lastcellcol - firstcellcol + 1;
- }
-
- /**
- * Gets the number of rows in the range.
- */
- public int getHeight() {
- return lastcellrow - firstcellrow + 1;
- }
-
- /**
- * Returns an array of the row numbers referenced by this CellRange
- *
- * @return int[] array of row ints
- */
- public int[] getRowInts() {
- if (myrowints != null)
- return myrowints;
- int numrows = (lastcellrow + 1) - firstcellrow;
- myrowints = new int[numrows];
- for (int t = 0; t < numrows; t++) {
- myrowints[t] = firstcellrow + t;
- }
- return myrowints;
- }
-
- /**
- * returns an array of column numbers referenced by this CellRange
- *
- * @return int[] array of col ints
- */
- public int[] getColInts() {
- if (mycolints != null)
- return mycolints;
- int numcols = (lastcellcol + 1) - firstcellcol;
- mycolints = new int[numcols];
- for (int t = 0; t < numcols; t++) {
- mycolints[t] = firstcellcol + t;
- }
- return mycolints;
- }
-
- /**
- * Returns an array of Rows (RowHandles) referenced by this CellRange
- *
- * @return RowHandle[] array of row handles
- */
- public RowHandle[] getRows() throws RowNotFoundException {
- if (myrows != null)
- return myrows;
- int numrows = (lastcellrow + 1) - firstcellrow;
- myrows = new RowHandle[numrows];
- for (int t = 0; t < numrows; t++) {
- RowHandle rx = null;
- try {
- rx = sheet.getRow((firstcellrow - 1) + t);
- } catch (Exception x) {
- ; // typically empty rows
- }
- myrows[t] = rx;
- }
- return myrows;
- }
-
- /**
- * Get the number of rows that this CellRange encompasses
- *
- * @return
- */
- public int getNumberOfRows() {
- int numRows = (lastcellrow + 1) - firstcellrow;
- return numRows;
- }
-
- /**
- * Returns an array of Columns (ColHandles) referenced by this CellRange
- *
- * @return ColHandle[] array of columns handles
- */
- public ColHandle[] getCols() throws ColumnNotFoundException {
- if (mycols != null)
- return mycols;
- int numcols = (lastcellcol + 1) - firstcellcol;
- mycols = new ColHandle[numcols];
- for (int t = 0; t < numcols; t++) {
- mycols[t] = sheet.getCol(firstcellcol + t);
- }
- return mycols;
- }
-
- /**
- * Get the number of columns that this CellRange encompasses
- *
- * @return
- */
- public int getNumberOfCols() {
- int numCols = (lastcellcol + 1) - firstcellcol;
- return numCols;
- }
-
- /**
- * returns edge status of the desired CellHandle within this CellRange ie: top,
- * left, bottom, right
- * returns 0 or 1 for 4 sides
- * 1,1,1,1 is a single cell in a range 1,1,0,0 is on the top left edge of the
- * range
- *
- * @param CellHandle
- * ch -
- * @param int
- * sz -
- * @return int[] array representing the edge positions
- */
- // TODO: documentation: Don't quite understand this!
- public int[] getEdgePositions(CellHandle ch, int sz) {
- int[] coords = { 0, 0, 0, 0 };
- // get the corners, check for 'edges'
- String adr = ch.getCellAddress();
- int[] rc = ExcelTools.getRowColFromString(adr);
- // increment to one-based
- rc[0]++;
- if (rc[0] == firstcellrow)
- coords[0] = sz;
- if (rc[0] == lastcellrow)
- coords[2] = sz;
- if (rc[1] == firstcellcol)
- coords[1] = sz;
- if (rc[1] == lastcellcol)
- coords[3] = sz;
- return coords;
- }
-
- /**
- * returns whether this CellRange intersects with another CellRange
- *
- * @param CellRange
- * cr - CellRange to test
- * @return boolean true if CellRange cr intersects with this CellRange
- */
- public boolean intersects(CellRange cr) {
- // get the corners, check for 'contains'
- try {
- int[] rc = cr.getRangeCoords();
- if ((rc[0] >= firstcellrow) && (rc[2] <= lastcellrow) && (rc[1] >= firstcellcol)
- && (rc[3] <= lastcellcol)) {
- return true;
- }
- } catch (CellNotFoundException e) {
- Logger.logWarn("CellRange unable to determine intersection of range: " + cr.toString());
- }
- return false;
- }
-
- /**
- * returns whether this CellRange contains a particular Cell
- *
- * @param CellHandle
- * ch - the Cell to check
- * @return true if CellHandle ch is contained within this CellRange
- */
- public boolean contains(Cell cxx) {
- String chsheet = cxx.getWorkSheetName();
- String mysheet = "";
- if (this.getSheet() != null)
- mysheet = this.getSheet().getSheetName();
- if (!chsheet.equalsIgnoreCase(mysheet))
- return false;
- String adr = cxx.getCellAddress();
- int[] rc = ExcelTools.getRowColFromString(adr);
- return contains(rc);
- }
-
- /**
- * returns whether this CellRange contains the specified Row/Col coordinates
- *
- * @param int[]
- * rc - row/col coordinates to test
- * @return true if the coordinates are contained with this CellRange
- */
- public boolean contains(int[] rc) {
- boolean ret = true;
- if (rc[0] + 1 < firstcellrow)
- ret = false;
- if (rc[0] + 1 > lastcellrow)
- ret = false;
- if (rc[1] < firstcellcol)
- ret = false;
- if (rc[1] > lastcellcol)
- ret = false;
- return ret;
- }
-
- /**
- * returns the String representation of this CellRange
- */
- @Override
- public String toString() {
- return range;
- }
-
- /**
- * Constructor to create a new CellRange from a WorkSheetHandle and a set of
- * range coordinates:
- * coords[0] = first row
- * coords[1] = first col
- * coords[2] = last row
- * coords[3] = last col
- *
- * @param WorkSheetHandle
- * sht - handle to the WorkSheet containing the Range's Cells
- * @param int[]
- * coords - the cell coordinates
- * @param boolean
- * cb - true if should create blank cells
- * @throws Exception
- **/
- public CellRange(WorkSheetHandle sht, int[] coords, boolean cb) throws Exception {
- this.createBlanks = cb;
- this.sheet = sht;
- this.mybook = sht.wbh;
- sheetname = sht.getSheetName();
- sheetname = GenericPtg.qualifySheetname(sheetname);
- String addr = sheetname + "!";
- String c1 = ExcelTools.getAlphaVal(coords[1]) + String.valueOf(coords[0] + 1);
- String c2 = ExcelTools.getAlphaVal(coords[3]) + String.valueOf(coords[2] + 1);
- addr += c1 + ":" + c2;
- this.range = addr;
- this.init();
- }
-
- /**
- * Set this CellRange to be the current Print Area
- *
- */
- public void setAsPrintArea() {
- if (this.sheet == null) {
- Logger.logErr("CellRange.setAsPrintArea() failed: " + this.toString()
- + " does not have a valid Sheet reference.");
- return;
- }
- sheet.setPrintArea(this);
- }
-
- /**
- * Constructor to create a new CellRange from a WorkSheetHandle and a set of
- * range coordinates:
- * coords[0] = first row
- * coords[1] = first col
- * coords[2] = last row
- * coords[3] = last col
- *
- * @param WorkSheetHandle
- * sht - handle to the WorkSheet containing the Range's Cells
- * @param int[]
- * coords - the cell coordinates
- */
- public CellRange(WorkSheetHandle sht, int[] coords) throws Exception {
- this(sht, coords, false);
- }
-
- /**
- * Constructor to Create a new CellRange from a String range
- * The String range must be in the format Sheet!CR:CR
- * For Example, "Sheet1!C9:I19"
- * NOTE: You MUST Set the WorkBookHandle explicitly on this CellRange or it will
- * generate NullPointerException when trying to access the Cells.
- *
- *
- * @param String
- * r - range String
- * @see CellRange.setWorkBook
- */
- public CellRange(String r) {
- this.range = r;
- }
-
- /**
- * Increase the bounds of the CellRange by including the CellHandle.
- * These are the limitations and side-effects of this method:
- * - the Cell must be contiguous with the existing Range, ie: you can add a Cell
- * which either increments the row or the column of the existing range by one.
- *
- * - the Cell must be on the same sheet as the existing range.
- * - as a Cell Range is a 2 dimensional rectangle, expanding a multiple column
- * range by adding a Cell to the end will include the logical Cells on the row
- * in the range.
- * Some Examples:
- *
- * // simple one dimensional range expansion:
- * existing Range = A1:A20
- * addCellToRange(A21) new Range = A1:A21
- *
- * existing Range = A1:B20
- * addCellToRange(A21)
- * new Range = A1:B21 // note B20 is included automatically
- *
- * existing Range = A1:A20
- * addCellToRange(B1)
- * new Range = A1:B20 //note entire B column of cells are included automatically
- *
- * @param CellHandle
- * ch - the Cell to add to the CellRange
- */
- public boolean addCellToRange(CellHandle ch) {
- // check worksheet
- String sheetname = ch.getWorkSheetName();
- if (sheetname == null) {
- Logger.logWarn("Cell " + ch.toString() + " NOT added to Range: " + this.toString());
- return false;
- }
- if (!sheetname.equalsIgnoreCase(this.getSheet().getSheetName())) {
- Logger.logWarn("Cell " + ch.toString() + " NOT added to Range: " + this.toString());
- return false;
- }
- int[] rc = { ch.getRowNum(), ch.getColNum() };
- // increment to one-based
- rc[0]++;
-
- // check that it's at the beginning
- if (firstcellrow == -1)
- firstcellrow = rc[0];
- if (firstcellcol == -1)
- firstcellcol = rc[1];
- if (lastcellrow == -1)
- lastcellrow = rc[0];
- if (lastcellcol == -1)
- lastcellcol = rc[1];
- if (rc[0] < firstcellrow)
- firstcellrow--;
- if (rc[1] < firstcellcol)
- firstcellcol--;
- // check that it's at the end
- if (rc[0] > lastcellrow)
- lastcellrow++;
- if (rc[1] > lastcellcol)
- lastcellcol++;
-
- // myptg is never set so myptg access never happens... taking out
- // boolean addPtgInfo = false;
- // if (myptg != null && myptg instanceof PtgRef)
- // addPtgInfo = true;
- // format the new range String
- String newrange = this.getSheet().getSheetName() + "!";
- String newcellrange = "";
- // if (addPtgInfo && !((PtgRef) myptg).isColRel())
- // newcellrange += "$";
- newcellrange += ExcelTools.getAlphaVal(firstcellcol);
- // if (addPtgInfo && !((PtgRef) myptg).isRowRel())
- // newcellrange += "$";
- newcellrange += String.valueOf(firstcellrow);
- newcellrange += ":";
- // if (addPtgInfo && !((PtgRef) myptg).isColRel())
- // newcellrange += "$";
- newcellrange += ExcelTools.getAlphaVal(lastcellcol);
- // if (addPtgInfo && !((PtgRef) myptg).isColRel())
- // newcellrange += "$";
- newcellrange += String.valueOf(lastcellrow);
- this.range = newrange + newcellrange;
- isDirty = true;
-
- /*
- * if (addPtgInfo) { ReferenceTracker.updateAddressPerPolicy(myptg,
- * newcellrange); return true; }
- */
-
- if (this.parent != null && this.parent.getOpcode() == XLSConstants.NAME) {
- ((Name) parent).setLocation(this.range); // ensure named range expression is updated, as well as any formula
- // references are cleared of cache
- }
-
- return false;
- }
-
- /**
- * get the Cells in this cell range
- *
- * @return CellHandle[] all the Cells in this range
- */
- public CellHandle[] getCells() {
- if (isDirty)
- try {
- init();
- } catch (CellNotFoundException e) {
- ;
- }
- return cells;
- }
-
- /**
- * Return a list of the cells in this cell range
- *
- * @return List of CellHandles
- */
- public List getCellList() {
- return Arrays.asList(cells);
- }
-
- /**
- * get the underlying Cell Records in this range
- * NOTE: Cell Records are not a part of the public API and are not intended for
- * use in client applications.
- *
- * @return BiffRec[] array of Cell Records
- *
- */
- public BiffRec[] getCellRecs() {
- CellHandle[] ch = this.getCells();
- BiffRec[] ret = new BiffRec[ch.length];
- for (int t = 0; t < ret.length; t++) {
- if (ch[t] != null)
- ret[t] = ch[t].getCell();
- }
- return ret;
- }
-
- /*
- * reset the underlying cell records in this range NOTE: Cell Records are
- * not a part of the public API and are not intended for use in client
- * applications.
- *
- * @return BiffRec[] array of Cell Records
- *
- * NOT USED AT THIS TIME public BiffRec[] resetCellRecs() { this.isDirty= true;
- * return getCellRecs(); }
- */
-
- /**
- * If the cells contain an incrementing value that can be transferred into an
- * int, then return that value, else throw a NPE. I'm sure there is a better
- * exception to be thrown, but not sure what that is, and it doesn't make sense
- * to return a value like -1 in these cases.
- */
- public int getIncrementAmount() throws Exception {
- CellHandle[] ch = this.getCells();
- if (ch.length == 1) {
- throw new Exception("Cannot have increment with non-range cell");
- }
- boolean initialized = false;
- int incAmount = 0;
- for (int i = 1; i < ch.length; i++) {
- int value1 = ch[i - 1].getIntVal();
- int value2 = ch[i].getIntVal();
- if (!initialized) {
- incAmount = (value2 - value1);
- initialized = true;
- } else {
- if (value2 - value1 != incAmount) {
- throw new Exception("Inconsistent values across increment");
- }
- }
- }
- if (!initialized) {
- throw new Exception("Error determining increment");
- }
- return incAmount;
- }
-
- /**
- * Constructor which creates a new CellRange from a String range
- * The String range must be in the format Sheet!CR:CR
- * For Example, "Sheet1!C9:I19"
- *
- * @param String
- * range - the range string
- * @param WorkBook
- * bk
- * @param boolean
- * createblanks - true if blank cells should be created if necessary
- * @param boolean
- * initcells - true if cells should (be initialized)
- */
- public CellRange(String range, io.starter.OpenXLS.WorkBook bk, boolean createblanks, boolean initcells) {
- createBlanks = createblanks;
- initializeCells = initcells;
- this.range = range;
- if (bk == null)
- return;
- this.setWorkBook(bk);
- try {
- this.init();
- } catch (CellNotFoundException e) {
- ;
- }
- }
-
- /**
- * Constructor which creates a new CellRange from a String range
- * The String range must be in the format Sheet!CR:CR
- * For Example, "Sheet1!C9:I19"
- *
- * @param String
- * range - the range string
- * @param WorkBook
- * bk
- * @param boolean
- * createblanks - true if blank cells should be created (if
- * necessary)
- */
- public CellRange(String range, io.starter.OpenXLS.WorkBook bk, boolean c) {
- createBlanks = c;
- this.range = range;
- if (bk == null)
- return;
- this.setWorkBook(bk);
- try {
- if (!"".equals(this.range))
- this.init();
- } catch (CellNotFoundException e) {
- ;
- } catch (NumberFormatException ne) {
- ; // happens upon !REF range
- }
- }
-
- /**
- * sets the parent of this Cell range
- * Used Internally. Not intended for the End User.
- *
- * @param b
- */
- public void setParent(BiffRec b) {
- parent = b;
- }
-
- /**
- * Re-sort all cells in this cell range according to the column.
- *
- * A custom comparator can be passed in, or the default one can be used with
- * sort(String, boolean).
- *
- * Comparators will be passed 2 CellHandle objects for comparison.
- *
- * Collections.reverse will be called on the results if ascending is set to
- * false;
- *
- * @param rowNumber
- * the 0 based (row 5 = 4) number of the row to be sorted upon
- * @param comparator
- * @throws RowNotFoundException
- * @throws ColumnNotFoundException
- */
- public void sort(int rownumber, Comparator comparator, boolean ascending) throws RowNotFoundException {
- this.createBlanks();
- ArrayList sortRow = this.getCellsByRow(rownumber);
- Collections.sort(sortRow, comparator);
- if (!ascending)
- Collections.reverse(sortRow);
- // now we have sorted the array list, come up with a map to resort the rows.
- int[] coords = null;
- try {
- coords = this.getRangeCoords();
- // fix stupid wrong offsets;
- coords[0] = coords[0]--;
- coords[2] = coords[2]--;
- } catch (CellNotFoundException e1) {
- }
- ArrayList outputCols = new ArrayList();
- for (int i = 0; i < sortRow.size(); i++) {
- CellHandle cell = sortRow.get(i);
- ArrayList> cells = null;
- try {
- cells = this.getCellsByCol(ExcelTools.getAlphaVal(cell.getColNum()));
- } catch (ColumnNotFoundException e) {
- // if there are no cells in this column ignore it
- }
- outputCols.add(cells);
- }
- this.removeCells();
- for (int i = coords[1]; i <= coords[3]; i++) {
- ArrayList> cells = outputCols.get(i - coords[1]);
- for (int x = 0; x < cells.size(); x++) {
- CellHandle cell = (CellHandle) cells.get(x);
- Boundsheet bs = this.getSheet().getBoundsheet();
- cell.getCell().setCol((short) i);
- bs.addCell((CellRec) cell.getCell());
- }
- }
-
- }
-
- /**
- * Changes the cellRange to a createBlanks cellrange and re-initializes the
- * range, creating the missing blanks.
- */
- private void createBlanks() {
- if (!this.createBlanks) {
- this.createBlanks = true;
- this.initializeCells = true;
- try {
- this.init();
- } catch (CellNotFoundException e) {
- }
- }
- }
-
- /**
- * Resort all cells in the range according to the rownumber passed in.
- *
- * @param rownumber
- * the 0 based row number
- * @param ascending
- * @throws RowNotFoundException
- * @throws ColumnNotFoundException
- */
- public void sort(int rownumber, boolean ascending) throws RowNotFoundException {
- Comparator cp = new CellComparator();
- this.sort(rownumber, cp, ascending);
- }
-
- /**
- * Re-sort all cells in this cell range according to the column.
- *
- * A custom comparator can be passed in, or the default one can be used with
- * sort(String, boolean).
- *
- * Comparators will be passed 2 CellHandle objects for comparison.
- *
- * * Collections.reverse will be called on the results if ascending is set to
- * false;
- *
- * @param columnName
- * @param comparator
- * @throws RowNotFoundException
- * @throws ColumnNotFoundException
- */
- public void sort(String columnName, Comparator comparator, boolean ascending) throws ColumnNotFoundException {
- if (!this.createBlanks) {
- // we cannot have empty cells in this operation
- this.createBlanks = true;
- try {
- this.init();
- } catch (CellNotFoundException e) {
- }
- }
- ArrayList sortCol = this.getCellsByCol(columnName);
- Collections.sort(sortCol, comparator);
- if (!ascending)
- Collections.reverse(sortCol);
- // now we have sorted the array list, come up with a map to resort the rows.
- int[] coords = null;
- try {
- coords = this.getRangeCoords();
- // fix stupid wrong offsets;
- coords[0] = coords[0]--;
- coords[2] = coords[2]--;
- } catch (CellNotFoundException e1) {
- e1.printStackTrace();
- }
- ArrayList> outputRows = new ArrayList>();
- for (int i = 0; i < sortCol.size(); i++) {
- CellHandle cell = (CellHandle) sortCol.get(i);
- ArrayList cells = null;
- try {
- cells = this.getCellsByRow(cell.getRowNum());
- } catch (RowNotFoundException e) {
- // ignore if no cells available
- }
- outputRows.add(cells);
- }
- this.removeCells();
- for (int i = coords[0]; i <= coords[2]; i++) {
- ArrayList> cells = outputRows.get(i - coords[0]);
- for (int x = 0; x < cells.size(); x++) {
- CellHandle cell = (CellHandle) cells.get(x);
- Boundsheet bs = this.getSheet().getBoundsheet();
- cell.getCell().setRowNumber(i - 1);
- bs.addCell((CellRec) cell.getCell());
- }
- }
- }
-
- /**
- * Resort all cells in the range according to the column passed in.
- *
- *
- * @param columnName
- * @param ascending
- * @throws ColumnNotFoundException
- * @throws RowNotFoundException
- */
- @SuppressWarnings("unchecked")
- public void sort(String columnName, boolean ascending) throws ColumnNotFoundException {
- Comparator> cp = new CellComparator();
- this.sort(columnName, cp, ascending);
- }
-
- public static String xmlResponsePre = "";
- public static String xmlResponsePost = " ";
-
- /**
- * Return the XML representation of this CellRange object
- *
- * @return String of XML
- */
- public String getXML() {
- StringBuffer sb = new StringBuffer("");
- // StringBuffer sb = new StringBuffer(xmlResponsePre);
- CellHandle[] cx = this.getCells();
- sb.append("\r\n");
- // append cellxml
- for (int t = 0; t < cx.length; t++) {
- sb.append(cx[t].getXML());
- sb.append("\r\n");
- }
- sb.append(xmlResponsePost);
- return sb.toString();
- }
-
- /**
- * gets the array of Cells in this Name
- *
- * NOTE: this method variation also returns the Sheetname for the name record if
- * not null.
- *
- * Thus this method is limited to use with 2D ranges.
- *
- *
- * @return Cell[] all Cells defined in this Name
- * @param fragment
- * whether to enclose result in NameHandle tag
- */
- public String getCellRangeXML(boolean fragment) {
- StringBuffer sbx = new StringBuffer();
- if (!fragment)
- sbx.append("");
- sbx.append("");
- sbx.append(getXML());
- sbx.append("");
- return sbx.toString();
- }
-
- /**
- * gets the array of Cells in this Name
- *
- * Thus this method is limited to use with 2D ranges.
- *
- * @return Cell[] all Cells defined in this Name
- * @param fragment
- * whether to enclose result in NameHandle tag
- */
- public String getCellRangeXML() {
- StringBuffer sbx = new StringBuffer();
- sbx.append("");
- sbx.append(getXML());
- return sbx.toString();
- }
-
- /**
- * Constructor which creates a new CellRange using an array of cells as it's
- * constructor.
- * NOTE that if the array of cells you are adding is not a rectangle of data (ie
- * [A1][B1][C1]) that you will have null cells in your cell range and operations
- * on it may cause errors.
- * If you wish to populate a cell range that is not contiguous, consider the
- * constructor CellRange(CellHandle[] newcells, boolean createblanks), which
- * will populate null cells with blank records, allowing normal operations such
- * as formatting, merging, etc.
- *
- * @param CellHandle[]
- * newcells - the array of cells from which to create the new
- * CellRange
- * @throws CellNotFoundException
- */
- public CellRange(CellHandle[] newcells) throws CellNotFoundException {
- this.setWorkBook(newcells[0].getWorkBook());
- this.sheet = newcells[0].getWorkSheetHandle();
- for (int x = 0; x < newcells.length; x++) {
- this.addCellToRange(newcells[x]);
- }
- this.init();
- }
-
- /**
- * create a new CellRange using an array of cells as it's constructor.
- * If you wish to populate a cell range that is not contiguous, set createblanks
- * to true, which will populate null cells with blank records, allowing normal
- * operations such as formatting, merging, etc.
- *
- * @param CellHandle[]
- * newcells - the array of cells from which to create the new
- * CellRange
- * @param boolean
- * createblanks - true if should create blank cells if necesary
- */
- public CellRange(CellHandle[] newcells, boolean createblanks) throws CellNotFoundException {
- this.createBlanks = createblanks;
- this.setWorkBook(newcells[0].getWorkBook());
- this.sheet = newcells[0].getWorkSheetHandle();
- for (int x = 0; x < newcells.length; x++) {
- this.addCellToRange(newcells[x]);
- }
- this.init();
- }
-
- /**
- * Constructor which creates a new CellRange from a String range
- * The String range must be in the format Sheet!CR:CR
- * For Example, "Sheet1!C9:I19"
- *
- * @param String
- * range - the range string
- * @param WorkBook
- * bk
- * @throws CellNotFoundException
- */
- public CellRange(String range, io.starter.OpenXLS.WorkBook bk) throws CellNotFoundException {
- this(range, bk, true);
- }
-
- /**
- * attach the workbook for this CellRange
- *
- * @param WorkBook
- * bk
- */
- public void setWorkBook(io.starter.OpenXLS.WorkBook bk) {
- this.mybook = bk;
- }
-
- /**
- * Gets the coordinates of this cell range,
- *
- * @return int[5]: [0] first row (zero based, ie row 1=0), [1] first column, [2]
- * last row (zero based, ie row 1=0), [3] last column, [4] number of
- * cells in range
- */
- public int[] getCoords() throws CellNotFoundException {
- int numrows = 0;
- int numcols = 0;
- int numcells = 0;
- int[] coords = new int[5];
- String temprange = range;
- String[] s = ExcelTools.stripSheetNameFromRange(temprange);
- temprange = s[1];
- // qualify sheet and reset range - necessary if sheetname with spaces is used in
- // formula parsing
- sheetname = GenericPtg.qualifySheetname(s[0]);
- if (sheetname != null && !sheetname.equals("")) {
- if (s[2] == null)
- this.range = sheetname + "!" + temprange;
- else {
- s[2] = GenericPtg.qualifySheetname(s[2]);
- this.range = sheetname + ":" + s[2] + "!" + temprange;
- }
- }
-
- /*
- * check for R1C1
- */
- if ((temprange.indexOf("R") == 0) && (temprange.indexOf("C") > 1)
- && (Character.isDigit(temprange.charAt(temprange.indexOf("C") - 1)))) {
-
- int[] b = ExcelTools.getRangeRowCol(temprange);
-
- numrows = (b[2] - b[0]);
- if (numrows <= 0)
- numrows = 1;
-
- numcols = (b[3] - b[2]);
- if (numcols <= 0)
- numcols = 1;
-
- numcells = numrows * numcols;
-
- int[] retr = new int[5];
- retr[0] = b[0];
- retr[1] = b[1];
- retr[2] = b[2];
- retr[3] = b[3];
- retr[4] = numcells;
- return retr;
- }
- String startcell = "", endcell = "";
- int lastcolon = temprange.lastIndexOf(":");
- endcell = temprange.substring(lastcolon + 1);
- if (lastcolon == -1) // no range
- startcell = endcell;
- else
- startcell = temprange.substring(0, lastcolon);
-
- startcell = StringTool.strip(startcell, "$");
- endcell = StringTool.strip(endcell, "$");
-
- // get the first cell's coordinates
- int charct = startcell.length();
- while (charct > 0) {
- if (!Character.isDigit(startcell.charAt(--charct))) {
- charct++;
- break;
- }
- }
- String firstcellrowstr = startcell.substring(charct);
- firstcellrow = Integer.parseInt(firstcellrowstr);
- String firstcellcolstr = startcell.substring(0, charct);
- firstcellcol = ExcelTools.getIntVal(firstcellcolstr);
- // get the last cell's coordinates
- charct = endcell.length();
- while (charct > 0) {
- if (!Character.isDigit(endcell.charAt(--charct))) {
- charct++;
- break;
- }
- }
- String lastcellrowstr = endcell.substring(charct);
- lastcellrow = Integer.parseInt(lastcellrowstr);
- String lastcellcolstr = endcell.substring(0, charct);
- lastcellcol = ExcelTools.getIntVal(lastcellcolstr);
- numrows = (lastcellrow - firstcellrow) + 1;
- numcols = (lastcellcol - firstcellcol) + 1;
-
- numcells = numrows * numcols;
- if (numcells < 0)
- numcells *= -1; // handle swapped cells ie: "B1:A1"
-
- coords[0] = firstcellrow - 1;
- coords[1] = firstcellcol;
- coords[2] = lastcellrow - 1;
- coords[3] = lastcellcol;
- coords[4] = numcells;
- if (firstcellrow < 0 && lastcellrow < 0 || firstcellcol < 0 || lastcellcol < 0) {
- // not an error if it is a whole column or whole row range
- if (firstcellcol == -1 && lastcellcol == -1) {
- // what should numcells be for wholerow?
- wholeRow = true;
- } else if (firstcellrow == -1 && lastcellrow == -1) {
- // what should numcells be for wholecol?
- wholeCol = true;
- } else
- Logger.logErr("CellRange.getRangeCoords: Error in Range " + range);
- }
-
- // trap OOXML external reference link, if any
- if (s[3] != null)
- externalLink1 = Integer.valueOf(s[3].substring(1, s[3].length() - 1)).intValue();
- if (s[4] != null)
- externalLink2 = Integer.valueOf(s[4].substring(1, s[4].length() - 1)).intValue();
-
- return coords;
-
- }
-
- /**
- * Gets the coordinates of this cell range.
- *
- * @return int[5]: [0] first row, [1] first column, [2] last row, [3] last
- * column, [4] number of cells in range
- *
- * @deprecated {@link #getCoords()} instead, which returns zero based values for
- * rows.
- */
- @Deprecated
- public int[] getRangeCoords() throws CellNotFoundException {
- int[] ordinalValues = this.getCoords();
- ordinalValues[0] += 1;
- ordinalValues[2] += 1;
- return ordinalValues;
- }
-
- /**
- * Returns the WorkSheet referenced in this CellRange.
- *
- * @return WorkSheetHandle sheet referenced in this CellRange.
- */
- public WorkSheetHandle getSheet() {
- return sheet;
- }
-
- /**
- * initializes this CellRange
- *
- * @throws CellNotFoundException
- */
- public void init() throws CellNotFoundException {
- if (!FormulaParser.isComplexRange(range)) {
- int[] coords = this.getRangeCoords();
- int rowctr = coords[0];
- int firstcellcol = coords[1];
- int lastcellcol = coords[3];
- int numcells = coords[4];
-
- int cellctr = firstcellcol - 1;
- try {
- if (sheetname != null) {
- if (sheetname.equals("")) // 20080214 KSC - is this a good idea?
- // default to work sheet 0
- sheetname = this.mybook.getWorkSheet(0).getSheetName();
- }
- if (sheetname == null) {
- if (this.sheet != null)
- sheetname = this.sheet.getSheetName();
- else
- throw new IllegalArgumentException("sheet name not specified: " + range);
- }
-
- String s = sheetname;
- if (s != null) {
- // handle enclosing apostrophes which are added to PtgRefs
- if (s.charAt(0) == '\'') {
- s = s.substring(1, s.length());
- if (s.charAt(s.length() - 1) == '\'') {
- s = s.substring(0, s.length() - 1);
- }
- }
- }
- sheet = mybook.getWorkSheet(s);
- // if wholerow or wholecol, don't gather cells
- if (this.wholeCol || this.wholeRow)
- return;
- cells = new CellHandle[numcells];
- boolean resetFastAdds = false;
- if (sheet.getFastCellAdds() && this.createBlanks) {
- resetFastAdds = true;
- sheet.setFastCellAdds(false);
- }
- for (int i = 0; i < numcells; i++) {
- if (cellctr == lastcellcol) {// if its the end of the row,
- // increment row.
- cellctr = firstcellcol - 1;
- rowctr++;
- }
- ++cellctr;
- try {
- // use caching 20080917 KSC: PROBLEM HERE [Claritas
- // BugTracker 1862]
- if (this.initializeCells)
- cells[i] = sheet.getCell(rowctr - 1, cellctr, sheet.getUseCache()); // 20080917 KSC: use
- // cache
- // setting instead of
- // defaulting to true);
- } catch (CellNotFoundException e) {
- if (this.createBlanks) {
- cells[i] = sheet.add(null, rowctr - 1, cellctr);
- }
-
- }
- }
- if (resetFastAdds) {
- sheet.setFastCellAdds(true);
- }
- } catch (WorkSheetNotFoundException e) {
- throw new IllegalArgumentException(e.toString());
- }
- } else { // gather cells for a complex range ...
- io.starter.formats.XLS.formulas.PtgMemFunc pm = new io.starter.formats.XLS.formulas.PtgMemFunc();
- XLSRecord b = new XLSRecord();
- b.setWorkBook(this.mybook.getWorkBook());
- pm.setParentRec(b);
- try {
- pm.setLocation(range);
- Ptg[] p = pm.getComponents();
- java.util.ArrayList cellsfromcomplexrange = new java.util.ArrayList();
- for (int i = 0; i < p.length; i++) {
- try {
- cellsfromcomplexrange.add(mybook.getCell(((PtgRef) p[i]).getLocation()));
- } catch (CellNotFoundException e) {
- if (this.createBlanks) {
- cells[i] = sheet.add(null, p[i].getLocation());
- }
- }
- }
- cells = new CellHandle[cellsfromcomplexrange.size()];
- cells = cellsfromcomplexrange.toArray(cells);
- } catch (Exception e) {
- throw new IllegalArgumentException(e.toString());
- }
-
- }
- isDirty = false;
- }
-
- /**
- * Initializes this CellRange's cell list if necessary. This method
- * is useful if this CellRange was created with
- * initCells set to false and it is later necessary to
- * retrieve the cell list.
- *
- * @param createBlanks
- * whether missing cells should be created as blanks. If this is
- * false they will appear in the cell list as
- * nulls.
- */
- public void initCells(boolean createBlanks) {
- // If we don't need to do anything, return
- if (initializeCells == true && (createBlanks ? this.createBlanks : true))
- return;
-
- this.initializeCells = true;
- this.createBlanks = createBlanks;
-
- try {
- this.init();
- } catch (CellNotFoundException e) {
- // This will never actually happen but we have to catch it anyway
- throw new Error();
- }
- }
-
- /**
- * @return the workbook object attached to this CellRange
- */
- public WorkBook getWorkBook() {
- return mybook;
- }
-
- /**
- * gets whether this CellRange will add blank records to the WorkBook for any
- * missing Cells contained within the range.
- *
- * @return true if should create blank records for missing Cells
- */
- public boolean getCreateBlanks() {
- return createBlanks;
- }
-
- /**
- * set whether this CellRange will add blank records to the WorkBook for any
- * missing Cells contained within the range.
- *
- * @param boolean
- * b - true if should create blank records for missing Cells
- */
- public void setCreateBlanks(boolean b) {
- createBlanks = b;
- }
-
- /**
- * Return the String representation of this range
- *
- * @return the String range
- */
- public String getRange() {
- return range;
- }
-
- /**
- * Return the String cell address of this range in R1C1 format
- *
- * @return String range in R1C1 format
- */
- public String getR1C1Range() {
- String rc1x = "R";
- try {
- int[] rc1 = this.getRangeCoords();
- rc1x += rc1[0] + 1; // rangecoords are already 1-based
- rc1x += "C" + rc1[1];
- rc1x += ":R" + (rc1[2] + 1);
- rc1x += "C" + rc1[3];
-
- } catch (CellNotFoundException e) {
- Logger.logErr("CellRange.getR1C1Range failed", e);
- }
- return rc1x;
- }
-
- /**
- * Sets the range of cells for this CellRange to a string range
- *
- * @param String
- * rng - Range string
- */
- public void setRange(String rng) {
- range = rng;
- try {
- this.init();
- } catch (CellNotFoundException e) {
- ; // don't have to report anything
- }
- }
-
- /**
- * sets a border around the range of cells
- *
- * @param int
- * width - line width
- * @param int
- * linestyle - line style
- * @param java.awt.Color
- * colr - color of border line
- */
- public void setBorder(int width, int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- int[] coords = getEdgePositions(ch[t], width);
- // create Excel border -- top, left, bottom, right
- if (coords[0] > 0) {
- ch[t].setTopBorderLineStyle((short) linestyle);
- ch[t].setBorderTopColor(colr);
- }
- if (coords[1] > 0) {
- ch[t].setLeftBorderLineStyle((short) linestyle);
- ch[t].setBorderLeftColor(colr);
- }
- if (coords[2] > 0) {
- ch[t].setBottomBorderLineStyle((short) linestyle);
- ch[t].setBorderBottomColor(colr);
- }
- if (coords[3] > 0) {
- ch[t].setRightBorderLineStyle((short) linestyle);
- ch[t].setBorderRightColor(colr);
- }
- }
- }
-
- /**
- * update the CellRange when the underlying Cells change their location
- *
- * @return boolean true if the CellRange could be updated, false if there are no
- * cells represented by this range
- *
- *
- */
- public boolean update() {
- if (cells == null)
- return false; // this is an invalid range -- see Mergedcells prob.
- // jm
-
- // arbitrarily set the initial vals...
- if (cells[0] != null) { // 20100106 KSC: if didn't create blanks it's possible that cells are null
- firstcellrow = cells[0].getRowNum() + 1;
- firstcellcol = cells[0].getColNum();
- lastcellrow = cells[0].getRowNum() + 1;
- lastcellcol = cells[0].getColNum();
- for (int t = 0; t < cells.length; t++) {
- CellHandle cx = cells[t];
- // 20090901 KSC: apparently can be null
- if (cx != null)
- this.addCellToRange(cx);
- }
- this.myrowints = null;
- this.mycolints = null;
- return true;
- } else if (this.range != null) {// 20100106 KSC: handle ranges containing null cell[0] (i.e. ranges referencing
- // cells not present and createBlanks==false)
- if (this.DEBUG)
- Logger.logWarn("CellRange.update: trying to access blank cells in range " + this.range);
- try {
- this.getRangeCoords();
- return true;
- } catch (CellNotFoundException e) { // shouldn't
- return false;
- }
- }
- return false; // return false if it doesn't have it's cells defined
- }
-
- /**
- * returns the merged state of the CellRange
- *
- * @return true if this CellRange is merged
- */
- public boolean isMerged() {
- return ismerged;
- }
-
- /**
- * Sets the sheet reference for this CellRange.
- *
- * @param WorkSheetHandle
- * aSheet
- */
- public void setSheet(WorkSheetHandle aSheet) {
- this.sheet = aSheet;
- this.sheetname = aSheet.getSheetName();
- }
-
- /**
- * Whether to copy the cell contents.
- *
- */
- public static final int COPY_CONTENTS = 0x01;
-
- /**
- * Whether formulas should be copied. If this bit is not set the formula result
- * will be copied instead.
- */
- public static final int COPY_FORMULAS = 0x02;
-
- public static final int COPY_FORMATS = 0x0100;
-
- /**
- * Copies this range to another location. At present only contents and complete
- * formats may be copied.
- *
- * @param row
- * the topmost row of the target area
- * @param col
- * the leftmost column of the target area
- * @param what
- * a set of flags determining what will be copied
- * @return the destination range
- */
- public CellRange copy(WorkSheetHandle sheet, int row, int col, int what) {
- CellRange result = new CellRange(sheet, row, col, this.getWidth(), this.getHeight());
-
- int first_col = col;
-
- // note these are not currently used, see setting below
- boolean copy_contents = (what & COPY_CONTENTS) != 0;
- boolean copy_formulas = (what & COPY_FORMULAS) != 0;
- boolean copy_formats = (what & COPY_FORMATS) != 0;
-
- // set to true until this thing is fully implemented
- copy_formats = true;
- copy_formulas = true;
-
- int cur_row = cells[0].getRowNum();
- for (int idx = 0; idx < cells.length; idx++) {
- CellHandle source = cells[idx];
-
- if (source.getRowNum() != cur_row) {
- cur_row = source.getRowNum();
- row++;
- col = first_col;
- }
-
- CellHandle target = null;
- try {
- target = sheet.getCell(row, col);
- } catch (CellNotFoundException e) {
- }
-
- int formatID;
- if (copy_formats)
- formatID = source.getFormatId();
- else if (target != null)
- formatID = target.getFormatId();
- else
- formatID = sheet.getWorkBook().getWorkBook().getDefaultIxfe();
-
- if (copy_contents) {
- Object value;
-
- if (copy_formulas && source.isFormula()) {
- try {
- value = source.getFormulaHandle().getFormulaString();
- } catch (FormulaNotFoundException e) {
- // This shouldn't happen; we known the formula exists.
- // If it does happen it indicates a bug in OpenXLS,
- // thus we throw an Error.
- throw new Error("formula cell has no Formula record", e);
- }
- } else {
- value = source.getVal();
- }
-
- target = sheet.add(value, row, col, formatID);
-
- if (target.isFormula())
- try {
- FormulaHandle.moveCellRefs(target.getFormulaHandle(),
- new int[] { row - source.getRowNum(), col - source.getColNum() });
- } catch (FormulaNotFoundException e) {
- }
- }
-
- else if (target == null) {
- target = sheet.add(null, row, col, formatID);
- }
-
- if (copy_formats) {
- target.setFormatId(formatID);
- }
-
- result.cells[idx] = target;
- col++;
- }
-
- return result;
- }
-
- /**
- * Fills this range from the given cell.
- *
- * @param source
- * the cell whose attributes should be copied or null to
- * copy from the first cell in the range
- * @param what
- * a set of flags determining what will be copied
- * @param increment
- * the amount by which to increment numeric values or
- * NaN for no increment
- */
- public void fill(CellHandle source, int what, double increment) {
- if (null == source)
- source = cells[0];
-
- boolean copy_contents = (what & COPY_CONTENTS) != 0;
- boolean copy_formulas = (what & COPY_FORMULAS) != 0;
- boolean copy_formats = (what & COPY_FORMATS) != 0;
-
- int sourceRow = source.getRowNum();
- int sourceCol = source.getColNum();
-
- Object value = null;
- if (copy_contents) {
- if (copy_formulas && source.isFormula()) {
- try {
- value = source.getFormulaHandle().getFormulaString();
- } catch (FormulaNotFoundException e) {
- throw new Error("formula cell has no Formula record", e);
- }
- } else {
- value = source.getVal();
- }
- }
-
- // if increment is set, ensure the value can be incremented
- if (!Double.isNaN(increment) && !(copy_contents && value instanceof Number))
- throw new IllegalArgumentException("cannot increment unless filling with a numeric value");
-
- for (int idx = 0; idx < cells.length; idx++) {
- CellHandle target = cells[idx];
-
- // don't overwrite the source cell
- if (source.equals(target))
- continue;
-
- if (!Double.isNaN(increment))
- value = ((Number) value).doubleValue() + increment;
-
- int formatID = (copy_formats ? source : target).getFormatId();
-
- if (copy_contents) {
- cells[idx] = target = sheet.add(value, target.getRowNum(), target.getColNum(), formatID);
-
- if (target.isFormula())
- try {
- FormulaHandle.moveCellRefs(target.getFormulaHandle(),
- new int[] { target.getRowNum() - sourceRow, target.getColNum() - sourceCol });
- } catch (FormulaNotFoundException e) {
- }
- }
-
- // when adding Date values passing the format ID to sheet.add
- // doesn't set the format so we always set it here
- if (copy_formats) {
- target.setFormatId(formatID);
- }
-
- }
- }
-
- public Collection calculateAffectedCellsOnSheet() {
- Set affected = new HashSet();
- for (CellHandle cell : cells) {
- if (cell != null) {
- affected.add(cell);
- affected.addAll(cell.calculateAffectedCellsOnSheet());
- }
- }
- return affected;
- }
-
- /**
- * return a JSON array of cell values for the given range
- * static version
- *
- * @param String
- * range - a string representation of the desired range of cells
- * @param WorkBook
- * wbh - the source WorkBook for the cell range
- * @return JSONArray - a JSON representation of the desired cell range
- */
- public static JSONArray getValuesAsJSON(String range, WorkBook wbh) {
- JSONArray rangeArray = new JSONArray();
- try {
- CellRange cr = new CellRange(range, wbh, true);
- for (int j = 0; j < cr.getCells().length; j++)
- rangeArray.put(cr.getCells()[j].getVal());
- } catch (Exception e) {
- Logger.logErr("Error obtaining CellRange " + range + " JSON: " + e);
- }
- return rangeArray;
- }
-
- /**
- * Return a json object representing this cell range, entries contain only
- * address and values for more compact space
- *
- * @param range
- * @param wbh
- * @return
- */
- public JSONObject getBasicJSON() {
- try {
- JSONObject crObj = new JSONObject();
- crObj.put(JSON_RANGE, this.getRange());
- JSONArray rangeArray = new JSONArray();
- // should this possibly be full
- CellHandle[] cells = this.getCells();
- for (int j = 0; j < cells.length; j++) {
- JSONObject result = new JSONObject();
- String addy = cells[j].getCellAddress();
- String val = cells[j].getVal().toString();
- result.put(JSON_LOCATION, addy);
- result.put(JSON_CELL_VALUE, val);
- rangeArray.put(result);
- }
- crObj.put(JSON_CELLS, rangeArray);
- return crObj;
- } catch (Exception e) {
- Logger.logErr("Error obtaining CellRange " + range + " JSON: " + e);
- }
- return new JSONObject();
- }
-
- /**
- * Return a json object representing this cell range with full cell information
- * embedded.
- */
- public JSONObject getJSON() {
- JSONObject theRange = new JSONObject();
- JSONArray cells = new JSONArray();
- try {
- theRange.put(JSON_RANGE, getRange());
- CellHandle[] chandles = getCells();
- for (int i = 0; i < chandles.length; i++) {
- CellHandle thisCell = chandles[i];
- JSONObject result = new JSONObject();
-
- result.put(JSON_CELL, thisCell.getJSONObject());
- cells.put(result);
- }
- theRange.put(JSON_CELLS, cells);
- } catch (JSONException e) {
- Logger.logErr("Error getting cellRange JSON: " + e);
- }
- return theRange;
- }
-
- /**
- * Get the cells from a particular rownumber, constrained by the boundaries of
- * the cellRange
- *
- * @param rownumber
- */
- public ArrayList getCellsByRow(int rownumber) throws RowNotFoundException {
- ArrayList al = new ArrayList();
- RowHandle r = this.getSheet().getRow(rownumber);
- CellHandle[] cells = r.getCells();
- int[] coords = null;
- try {
- coords = this.getRangeCoords();
- } catch (CellNotFoundException e) {
- throw new RowNotFoundException("Error getting internal coordinates for CellRange" + e);
- }
- for (int i = 0; i < cells.length; i++) {
- if (cells[i].getColNum() >= coords[1] && cells[i].getColNum() <= coords[3]) {
- al.add(cells[i]);
- }
- }
- return al;
- }
-
- /**
- * Get the cells from a particular column, constrained by the boundaries of the
- * cellRange
- *
- * @param rownumber
- * @throws ColumnNotFoundException
- */
- public ArrayList getCellsByCol(String col) throws ColumnNotFoundException {
- ArrayList al = new ArrayList();
- ColHandle r = this.getSheet().getCol(col);
- CellHandle[] cells = r.getCells();
- int[] coords = null;
- try {
- coords = this.getRangeCoords();
- coords[0] = coords[0] - 1;
- coords[2] = coords[2] - 1;
- } catch (CellNotFoundException e) {
- throw new ColumnNotFoundException("Error getting internal coordinates for CellRange" + e);
- }
- for (int i = 0; i < cells.length; i++) {
- if (cells[i].getRowNum() >= coords[0] && cells[i].getRowNum() <= coords[2]) {
- al.add(cells[i]);
- }
- }
- return al;
- }
-
- /**
- * returns the cells for a given range
- * static version
- *
- * @param String
- * range - a string representation of the desired range of cells
- * @param WorkBook
- * wbh - the source WorkBook for the cell range
- * @return CellHandle[] array of cells represented by the desired cell range
- */
- public static CellHandle[] getCells(String range, WorkBookHandle wbh) {
- CellRange cr = new CellRange(range, wbh, true);
- return cr.getCells();
- }
-
- /**
- * removes the border from all of the cells in this range
- *
- */
- public void removeBorder() {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].removeBorder();
- }
- }
-
- /**
- * Sets a bottom border on all cells in the cellrange
- *
- * Linestyle should be set through the FormatHandle constants
- */
- public void setInnerBorderBottom(int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].setBottomBorderLineStyle((short) linestyle);
- ch[t].setBorderBottomColor(colr);
- }
- }
-
- /**
- * Sets a right border on all cells in the cellrange
- *
- * Linestyle should be set through the FormatHandle constants
- */
- public void setInnerBorderRight(int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].setRightBorderLineStyle((short) linestyle);
- ch[t].setBorderRightColor(colr);
- }
- }
-
- /**
- * Sets a left border on all cells in the cellrange
- *
- * Linestyle should be set through the FormatHandle constants
- */
- public void setInnerBorderLeft(int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].setLeftBorderLineStyle((short) linestyle);
- ch[t].setBorderLeftColor(colr);
- }
- }
-
- /**
- * Sets a top border on all cells in the cellrange
- *
- * Linestyle should be set through the FormatHandle constants
- */
- public void setInnerBorderTop(int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].setTopBorderLineStyle((short) linestyle);
- ch[t].setBorderTopColor(colr);
- }
- }
-
- /**
- * Sets a surround border on all cells in the cellrange
- *
- * Linestyle should be set through the FormatHandle constants
- */
- public void setInnerBorderSurround(int linestyle, java.awt.Color colr) {
- CellHandle[] ch = getCells();
- for (int t = 0; t < ch.length; t++) {
- ch[t].setBorderColor(colr);
- ch[t].setBorderLineStyle((short) linestyle);
- }
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/CellRange.kt b/src/main/java/io/starter/OpenXLS/CellRange.kt
new file mode 100644
index 0000000..9c99899
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/CellRange.kt
@@ -0,0 +1,1986 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.*
+import io.starter.formats.XLS.formulas.FormulaParser
+import io.starter.formats.XLS.formulas.GenericPtg
+import io.starter.formats.XLS.formulas.Ptg
+import io.starter.formats.XLS.formulas.PtgRef
+import io.starter.toolkit.Logger
+import io.starter.toolkit.StringTool
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+
+import java.io.Serializable
+import java.util.*
+
+import io.starter.OpenXLS.JSONConstants.*
+
+/**
+ * Cell Range is a handle to a range of Workbook Cells
+ *
+ *
+ * Contains useful methods for working with Collections of Cells.
+ *
+ * for example:
+ *
+ * CellRange cr = new CellRange("Sheet1!A1:B10", workbk);
+ * cr.addCellToRange("C10");
+ * CellHandle mycells = cr.getCells();
+ * for(int x=0;x < mycells.length;x++)
+ * Logger.logInfo(mycells[x].getCellAddress() + mycells[x].toString());
+ * }
+ *
+ *
+ *
+ * [Starter Inc.](http://starter.io)
+ *
+ * @see DataBoundCellRange
+ *
+ * @see XLSRecord
+ */
+class CellRange : Serializable {
+
+ /**
+ * returns the conditional format object for this range, if any
+ *
+ * @return Condfmt object
+ */
+ protected var conditionalFormat: Condfmt? = null
+ internal set
+ /**
+ * returns the merged state of the CellRange
+ *
+ * @return true if this CellRange is merged
+ */
+ var isMerged = false
+ private set
+ private var parent: BiffRec? = null // if cell range is child of a named range, must ensure update correctly
+ // private Ptg myptg = null;
+ var DEBUG = false
+ private var isDirty = false // true if addCellsToRange without init
+ internal var firstcellrow = -1
+ internal var firstcellcol = -1
+ internal var lastcellrow = -1
+ internal var lastcellcol = -1
+ /**
+ * gets whether this CellRange will add blank records to the WorkBook for any
+ * missing Cells contained within the range.
+ *
+ * @return true if should create blank records for missing Cells
+ */
+ /**
+ * set whether this CellRange will add blank records to the WorkBook for any
+ * missing Cells contained within the range.
+ *
+ * @param boolean b - true if should create blank records for missing Cells
+ */
+ var createBlanks = false
+ private var initializeCells = true
+ @Transient
+ var cells: Array? = null
+ @Transient
+ protected var range: String? = null
+ @Transient
+ protected var sheetname: String? = null
+ /**
+ * @return the workbook object attached to this CellRange
+ */
+ /**
+ * attach the workbook for this CellRange
+ *
+ * @param WorkBook bk
+ */
+ @Transient
+ var workBook: WorkBook? = null
+ @Transient
+ private var sheet: WorkSheetHandle? = null
+ private var myrowints: IntArray? = null
+ private var mycolints: IntArray? = null
+ @Transient
+ private var myrows: Array? = null
+ @Transient
+ private var mycols: Array? = null
+
+ // for OOXML External References
+ protected var externalLink1 = 0
+ protected var externalLink2 = 0
+
+ internal var fmtr: FormatHandle? = null
+ internal var wholeCol = false
+ internal var wholeRow = false
+
+ /**
+ * Gets the number of columns in the range.
+ */
+ val width: Int
+ get() = lastcellcol - firstcellcol + 1
+
+ /**
+ * Gets the number of rows in the range.
+ */
+ val height: Int
+ get() = lastcellrow - firstcellrow + 1
+
+ /**
+ * Returns an array of the row numbers referenced by this CellRange
+ *
+ * @return int[] array of row ints
+ */
+ val rowInts: IntArray
+ get() {
+ if (myrowints != null)
+ return myrowints
+ val numrows = lastcellrow + 1 - firstcellrow
+ myrowints = IntArray(numrows)
+ for (t in 0 until numrows) {
+ myrowints[t] = firstcellrow + t
+ }
+ return myrowints
+ }
+
+ /**
+ * returns an array of column numbers referenced by this CellRange
+ *
+ * @return int[] array of col ints
+ */
+ val colInts: IntArray
+ get() {
+ if (mycolints != null)
+ return mycolints
+ val numcols = lastcellcol + 1 - firstcellcol
+ mycolints = IntArray(numcols)
+ for (t in 0 until numcols) {
+ mycolints[t] = firstcellcol + t
+ }
+ return mycolints
+ }
+
+ /**
+ * Returns an array of Rows (RowHandles) referenced by this CellRange
+ *
+ * @return RowHandle[] array of row handles
+ */
+ // typically empty rows
+ val rows: Array
+ @Throws(RowNotFoundException::class)
+ get() {
+ if (myrows != null)
+ return myrows
+ val numrows = lastcellrow + 1 - firstcellrow
+ myrows = arrayOfNulls(numrows)
+ for (t in 0 until numrows) {
+ var rx: RowHandle? = null
+ try {
+ rx = sheet!!.getRow(firstcellrow - 1 + t)
+ } catch (x: Exception) {
+ }
+
+ myrows[t] = rx
+ }
+ return myrows
+ }
+
+ /**
+ * Get the number of rows that this CellRange encompasses
+ *
+ * @return
+ */
+ val numberOfRows: Int
+ get() = lastcellrow + 1 - firstcellrow
+
+ /**
+ * Returns an array of Columns (ColHandles) referenced by this CellRange
+ *
+ * @return ColHandle[] array of columns handles
+ */
+ val cols: Array
+ @Throws(ColumnNotFoundException::class)
+ get() {
+ if (mycols != null)
+ return mycols
+ val numcols = lastcellcol + 1 - firstcellcol
+ mycols = arrayOfNulls(numcols)
+ for (t in 0 until numcols) {
+ mycols[t] = sheet!!.getCol(firstcellcol + t)
+ }
+ return mycols
+ }
+
+ /**
+ * Get the number of columns that this CellRange encompasses
+ *
+ * @return
+ */
+ val numberOfCols: Int
+ get() = lastcellcol + 1 - firstcellcol
+
+ /**
+ * Return a list of the cells in this cell range
+ *
+ * @return List of CellHandles
+ */
+ val cellList: List
+ get() = Arrays.asList(*cells!!)
+
+ /**
+ * get the underlying Cell Records in this range
+ * NOTE: Cell Records are not a part of the public API and are not intended for
+ * use in client applications.
+ *
+ * @return BiffRec[] array of Cell Records
+ */
+ val cellRecs: Array
+ get() {
+ val ch = this.getCells()
+ val ret = arrayOfNulls(ch!!.size)
+ for (t in ret.indices) {
+ if (ch[t] != null)
+ ret[t] = ch[t].cell
+ }
+ return ret
+ }
+
+ /*
+ * reset the underlying cell records in this range NOTE: Cell Records are
+ * not a part of the public API and are not intended for use in client
+ * applications.
+ *
+ * @return BiffRec[] array of Cell Records
+ *
+ * NOT USED AT THIS TIME public BiffRec[] resetCellRecs() { this.isDirty= true;
+ * return getCellRecs(); }
+ */
+
+ /**
+ * If the cells contain an incrementing value that can be transferred into an
+ * int, then return that value, else throw a NPE. I'm sure there is a better
+ * exception to be thrown, but not sure what that is, and it doesn't make sense
+ * to return a value like -1 in these cases.
+ */
+ val incrementAmount: Int
+ @Throws(Exception::class)
+ get() {
+ val ch = this.getCells()
+ if (ch!!.size == 1) {
+ throw Exception("Cannot have increment with non-range cell")
+ }
+ var initialized = false
+ var incAmount = 0
+ for (i in 1 until ch.size) {
+ val value1 = ch[i - 1].intVal
+ val value2 = ch[i].intVal
+ if (!initialized) {
+ incAmount = value2 - value1
+ initialized = true
+ } else {
+ if (value2 - value1 != incAmount) {
+ throw Exception("Inconsistent values across increment")
+ }
+ }
+ }
+ if (!initialized) {
+ throw Exception("Error determining increment")
+ }
+ return incAmount
+ }
+
+ /**
+ * Return the XML representation of this CellRange object
+ *
+ * @return String of XML
+ */
+ // StringBuffer sb = new StringBuffer(xmlResponsePre);
+ // append cellxml
+ val xml: String
+ get() {
+ val sb = StringBuffer("")
+ val cx = this.getCells()
+ sb.append("\r\n")
+ for (t in cx!!.indices) {
+ sb.append(cx[t].xml)
+ sb.append("\r\n")
+ }
+ sb.append(xmlResponsePost)
+ return sb.toString()
+ }
+
+ /**
+ * gets the array of Cells in this Name
+ *
+ *
+ * Thus this method is limited to use with 2D ranges.
+ *
+ * @param fragment whether to enclose result in NameHandle tag
+ * @return Cell[] all Cells defined in this Name
+ */
+ val cellRangeXML: String
+ get() {
+ val sbx = StringBuffer()
+ sbx.append("")
+ sbx.append(xml)
+ return sbx.toString()
+ }
+
+ /**
+ * Gets the coordinates of this cell range,
+ *
+ * @return int[5]: [0] first row (zero based, ie row 1=0), [1] first column, [2]
+ * last row (zero based, ie row 1=0), [3] last column, [4] number of
+ * cells in range
+ */
+ // qualify sheet and reset range - necessary if sheetname with spaces is used in
+ // formula parsing
+ /*
+ * check for R1C1
+ */// no range
+ // get the first cell's coordinates
+ // get the last cell's coordinates
+ // handle swapped cells ie: "B1:A1"
+ // not an error if it is a whole column or whole row range
+ // what should numcells be for wholerow?
+ // what should numcells be for wholecol?
+ // trap OOXML external reference link, if any
+ val coords: IntArray
+ @Throws(CellNotFoundException::class)
+ get() {
+ var numrows = 0
+ var numcols = 0
+ var numcells = 0
+ val coords = IntArray(5)
+ var temprange = range
+ val s = ExcelTools.stripSheetNameFromRange(temprange!!)
+ temprange = s[1]
+ sheetname = GenericPtg.qualifySheetname(s[0])
+ if (sheetname != null && sheetname != "") {
+ if (s[2] == null)
+ this.range = "$sheetname!$temprange"
+ else {
+ s[2] = GenericPtg.qualifySheetname(s[2])
+ this.range = sheetname + ":" + s[2] + "!" + temprange
+ }
+ }
+ if (temprange!!.indexOf("R") == 0 && temprange.indexOf("C") > 1
+ && Character.isDigit(temprange[temprange.indexOf("C") - 1])) {
+
+ val b = ExcelTools.getRangeRowCol(temprange)
+
+ numrows = b[2] - b[0]
+ if (numrows <= 0)
+ numrows = 1
+
+ numcols = b[3] - b[2]
+ if (numcols <= 0)
+ numcols = 1
+
+ numcells = numrows * numcols
+
+ val retr = IntArray(5)
+ retr[0] = b[0]
+ retr[1] = b[1]
+ retr[2] = b[2]
+ retr[3] = b[3]
+ retr[4] = numcells
+ return retr
+ }
+ var startcell = ""
+ var endcell = ""
+ val lastcolon = temprange.lastIndexOf(":")
+ endcell = temprange.substring(lastcolon + 1)
+ if (lastcolon == -1)
+ startcell = endcell
+ else
+ startcell = temprange.substring(0, lastcolon)
+
+ startcell = StringTool.strip(startcell, "$")
+ endcell = StringTool.strip(endcell, "$")
+ var charct = startcell.length
+ while (charct > 0) {
+ if (!Character.isDigit(startcell[--charct])) {
+ charct++
+ break
+ }
+ }
+ val firstcellrowstr = startcell.substring(charct)
+ firstcellrow = Integer.parseInt(firstcellrowstr)
+ val firstcellcolstr = startcell.substring(0, charct)
+ firstcellcol = ExcelTools.getIntVal(firstcellcolstr)
+ charct = endcell.length
+ while (charct > 0) {
+ if (!Character.isDigit(endcell[--charct])) {
+ charct++
+ break
+ }
+ }
+ val lastcellrowstr = endcell.substring(charct)
+ lastcellrow = Integer.parseInt(lastcellrowstr)
+ val lastcellcolstr = endcell.substring(0, charct)
+ lastcellcol = ExcelTools.getIntVal(lastcellcolstr)
+ numrows = lastcellrow - firstcellrow + 1
+ numcols = lastcellcol - firstcellcol + 1
+
+ numcells = numrows * numcols
+ if (numcells < 0)
+ numcells *= -1
+
+ coords[0] = firstcellrow - 1
+ coords[1] = firstcellcol
+ coords[2] = lastcellrow - 1
+ coords[3] = lastcellcol
+ coords[4] = numcells
+ if (firstcellrow < 0 && lastcellrow < 0 || firstcellcol < 0 || lastcellcol < 0) {
+ if (firstcellcol == -1 && lastcellcol == -1) {
+ wholeRow = true
+ } else if (firstcellrow == -1 && lastcellrow == -1) {
+ wholeCol = true
+ } else
+ Logger.logErr("CellRange.getRangeCoords: Error in Range " + range!!)
+ }
+ if (s[3] != null)
+ externalLink1 = Integer.valueOf(s[3].substring(1, s[3].length - 1)).toInt()
+ if (s[4] != null)
+ externalLink2 = Integer.valueOf(s[4].substring(1, s[4].length - 1)).toInt()
+
+ return coords
+
+ }
+
+ /**
+ * Gets the coordinates of this cell range.
+ *
+ * @return int[5]: [0] first row, [1] first column, [2] last row, [3] last
+ * column, [4] number of cells in range
+ */
+ val rangeCoords: IntArray
+ @Deprecated("{@link #getCoords()} instead, which returns zero based values for\n" +
+ " rows.")
+ @Throws(CellNotFoundException::class)
+ get() {
+ val ordinalValues = this.coords
+ ordinalValues[0] += 1
+ ordinalValues[2] += 1
+ return ordinalValues
+ }
+
+ /**
+ * Return the String cell address of this range in R1C1 format
+ *
+ * @return String range in R1C1 format
+ */
+ // rangecoords are already 1-based
+ val r1C1Range: String
+ get() {
+ var rc1x = "R"
+ try {
+ val rc1 = this.rangeCoords
+ rc1x += rc1[0] + 1
+ rc1x += "C" + rc1[1]
+ rc1x += ":R" + (rc1[2] + 1)
+ rc1x += "C" + rc1[3]
+
+ } catch (e: CellNotFoundException) {
+ Logger.logErr("CellRange.getR1C1Range failed", e)
+ }
+
+ return rc1x
+ }
+
+ /**
+ * Return a json object representing this cell range, entries contain only
+ * address and values for more compact space
+ *
+ * @param range
+ * @param wbh
+ * @return
+ */
+ // should this possibly be full
+ val basicJSON: JSONObject
+ get() {
+ try {
+ val crObj = JSONObject()
+ crObj.put(JSON_RANGE, this.getRange())
+ val rangeArray = JSONArray()
+ val cells = this.getCells()
+ for (j in cells!!.indices) {
+ val result = JSONObject()
+ val addy = cells[j].cellAddress
+ val `val` = cells[j].`val`!!.toString()
+ result.put(JSON_LOCATION, addy)
+ result.put(JSON_CELL_VALUE, `val`)
+ rangeArray.put(result)
+ }
+ crObj.put(JSON_CELLS, rangeArray)
+ return crObj
+ } catch (e: Exception) {
+ Logger.logErr("Error obtaining CellRange $range JSON: $e")
+ }
+
+ return JSONObject()
+ }
+
+ /**
+ * Return a json object representing this cell range with full cell information
+ * embedded.
+ */
+ val json: JSONObject
+ get() {
+ val theRange = JSONObject()
+ val cells = JSONArray()
+ try {
+ theRange.put(JSON_RANGE, getRange())
+ val chandles = getCells()
+ for (i in chandles!!.indices) {
+ val thisCell = chandles[i]
+ val result = JSONObject()
+
+ result.put(JSON_CELL, thisCell.jsonObject)
+ cells.put(result)
+ }
+ theRange.put(JSON_CELLS, cells)
+ } catch (e: JSONException) {
+ Logger.logErr("Error getting cellRange JSON: $e")
+ }
+
+ return theRange
+ }
+
+ /**
+ * Protected constructor for creating result ranges.
+ */
+ protected constructor(sheet: WorkSheetHandle, row: Int, col: Int, width: Int, height: Int) {
+ this.sheet = sheet
+ sheetname = sheet.sheetName
+ workBook = sheet.workBook
+
+ firstcellrow = row
+ firstcellcol = col
+ lastcellrow = row + height - 1
+ lastcellcol = col + width - 1
+
+ range = (sheetname + "!"
+ + ExcelTools.formatRange(intArrayOf(firstcellcol, firstcellrow, lastcellcol, lastcellrow)))
+
+ cells = arrayOfNulls(width * height)
+ }
+
+ /**
+ * Initializes a `CellRange` from a `CellRangeRef`. The
+ * source `CellRangeRef` instance must be qualified with a single
+ * resolved worksheet.
+ *
+ * @param source the `CellRangeRef` from which to initialize
+ * @param init whether to populate the cell array
+ * @param create whether to fill gaps in the range with blank cells
+ * @throws IllegalArgumentException if the source range does not have a resolved sheet or has more
+ * than one sheet
+ `` */
+ @JvmOverloads
+ constructor(source: CellRangeRef, init: Boolean = false, create: Boolean = true) {
+ initializeCells = init
+ createBlanks = create
+
+ sheet = source.firstSheet
+ if (sheet == null || source.isMultiSheet)
+ throw IllegalArgumentException("the source range must have a single resolved sheet")
+
+ workBook = this.sheet!!.workBook
+ sheetname = this.sheet!!.sheetName
+
+ // This is inefficient, but fixing it would require rewriting init.
+ this.range = source.toString()
+
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ // this should be impossible
+ throw RuntimeException(e)
+ }
+
+ }
+
+ fun clearFormats() {
+ for (idx in cells!!.indices)
+ if (cells!![idx] != null)
+ cells!![idx].clearFormats()
+ }
+
+
+ @Deprecated("use clear()")
+ fun clearContents() {
+ for (idx in cells!!.indices)
+ if (cells!![idx] != null)
+ cells!![idx].clearContents()
+ }
+
+ /**
+ * clears the contents and formats of the cells referenced by this range but
+ * does not remove the cells from the workbook.
+ */
+ fun clear() {
+ for (idx in cells!!.indices)
+ if (cells!![idx] != null)
+ cells!![idx].clear()
+ }
+
+ /**
+ * removes the cells referenced by this range from the sheet.
+ *
+ *
+ * NOTE: method does not shift rows or cols.
+ */
+ fun removeCells() {
+ for (idx in cells!!.indices)
+ if (cells!![idx] != null)
+ cells!![idx].remove(true)
+ }
+
+ /**
+ * Un-Merge the Cells contained in this CellRange
+ *
+ * @throws Exception
+ */
+ @Throws(Exception::class)
+ fun unMergeCells() {
+ val mycells = this.cellRecs
+ for (t in mycells.indices) {
+ mycells[t].mergeRange = null // unset the range of merged cells
+ mycells[t].xfRec.merged = false
+ }
+ val mc = this.getSheet()!!.sheet!!.mergedCellsRec
+ mc?.removeCellRange(this)
+ this.isMerged = false
+ }
+
+ /**
+ * Set the format ID of all cells in this CellRange
+ * FormatID can be obtained through any CellHandle with the getFormatID() call
+ *
+ * @param int fmtID - the format ID to set the cells within the range to
+ */
+ @Throws(Exception::class)
+ fun setFormatID(fmtID: Int) {
+ val mycells = this.cellRecs
+ for (t in mycells.indices) {
+ mycells[t].setXFRecord(fmtID)
+ }
+ }
+
+ /**
+ * Set a hyperlink on all cells in this CellRange
+ *
+ * @param String url - the URL String to set
+ */
+ @Throws(Exception::class)
+ fun setURL(url: String) {
+ val mycells = this.cellRecs
+ for (t in mycells.indices) {
+ CellHandle(mycells[t], this.workBook).url = url
+ }
+ }
+
+ /**
+ * Merge the Cells contained in this CellRange
+ *
+ * @param boolean remove - true to delete the Cells following the first in the range
+ */
+ fun mergeCells(remove: Boolean) {
+ this.createBlanks()
+ if (remove)
+ this.mergeCellsClearFollowingCells()
+ else
+ this.mergeCellsKeepFollowingCells()
+ }
+
+ /**
+ * Merge the Cells contained in this CellRange, clearing or removing the Cells
+ * following the first in the range
+ */
+ private fun mergeCellsClearFollowingCells() {
+ val mycells = this.cellRecs
+
+ // mycells[0].setMergeRange(this); // set the range of merged cells
+ var r: Xf? = mycells[0].xfRec
+ if (r == null) {
+ fmtr = FormatHandle(this.workBook)
+ fmtr!!.addCell(mycells[0])
+ r = mycells[0].xfRec
+ }
+ r!!.merged = true
+ for (t in mycells.indices) {
+ if (mycells[t] != null)
+ mycells[t].setSheet(this.getSheet()!!.mysheet)
+ mycells[t].mergeRange = this // set the range of merged cells
+ if (t > 0) {
+ if (mycells[t] !is Blank) {
+ val cellname = mycells[t].cellAddress
+ val sheet = mycells[t].sheet
+ mycells[t].remove(true) // blow it out!
+ sheet.addValue(null, cellname)
+ }
+ }
+ }
+ var mc = this.getSheet()!!.sheet!!.mergedCellsRec
+ if (mc == null)
+ mc = this.getSheet()!!.sheet!!.addMergedCellRec()
+ mc!!.addCellRange(this)
+ this.isMerged = true
+ }
+
+ /**
+ * Merge the Cells contained in this CellRange *
+ */
+ private fun mergeCellsKeepFollowingCells() {
+ val mycells = this.cellRecs
+ for (t in mycells.indices) {
+ mycells[t].mergeRange = this // set the range of merged cells
+ var r: Xf? = mycells[t].xfRec
+ if (r == null) {
+ fmtr = FormatHandle(this.workBook)
+ fmtr!!.addCellRange(this)
+ r = mycells[t].xfRec
+ }
+ r!!.merged = true
+ }
+
+ var mc = this.getSheet()!!.sheet!!.mergedCellsRec
+ if (mc == null)
+ mc = this.getSheet()!!.sheet!!.addMergedCellRec()
+ mc!!.addCellRange(this)
+ this.isMerged = true
+ }
+
+ /**
+ * returns edge status of the desired CellHandle within this CellRange ie: top,
+ * left, bottom, right
+ * returns 0 or 1 for 4 sides
+ * 1,1,1,1 is a single cell in a range 1,1,0,0 is on the top left edge of the
+ * range
+ *
+ * @param CellHandle ch -
+ * @param int sz -
+ * @return int[] array representing the edge positions
+ */
+ // TODO: documentation: Don't quite understand this!
+ fun getEdgePositions(ch: CellHandle, sz: Int): IntArray {
+ val coords = intArrayOf(0, 0, 0, 0)
+ // get the corners, check for 'edges'
+ val adr = ch.cellAddress
+ val rc = ExcelTools.getRowColFromString(adr)
+ // increment to one-based
+ rc[0]++
+ if (rc[0] == firstcellrow)
+ coords[0] = sz
+ if (rc[0] == lastcellrow)
+ coords[2] = sz
+ if (rc[1] == firstcellcol)
+ coords[1] = sz
+ if (rc[1] == lastcellcol)
+ coords[3] = sz
+ return coords
+ }
+
+ /**
+ * returns whether this CellRange intersects with another CellRange
+ *
+ * @param CellRange cr - CellRange to test
+ * @return boolean true if CellRange cr intersects with this CellRange
+ */
+ fun intersects(cr: CellRange): Boolean {
+ // get the corners, check for 'contains'
+ try {
+ val rc = cr.rangeCoords
+ if (rc[0] >= firstcellrow && rc[2] <= lastcellrow && rc[1] >= firstcellcol
+ && rc[3] <= lastcellcol) {
+ return true
+ }
+ } catch (e: CellNotFoundException) {
+ Logger.logWarn("CellRange unable to determine intersection of range: " + cr.toString()!!)
+ }
+
+ return false
+ }
+
+ /**
+ * returns whether this CellRange contains a particular Cell
+ *
+ * @param CellHandle ch - the Cell to check
+ * @return true if CellHandle ch is contained within this CellRange
+ */
+ operator fun contains(cxx: Cell): Boolean {
+ val chsheet = cxx.workSheetName
+ var mysheet = ""
+ if (this.getSheet() != null)
+ mysheet = this.getSheet()!!.sheetName
+ if (!chsheet.equals(mysheet, ignoreCase = true))
+ return false
+ val adr = cxx.cellAddress
+ val rc = ExcelTools.getRowColFromString(adr)
+ return contains(rc)
+ }
+
+ /**
+ * returns whether this CellRange contains the specified Row/Col coordinates
+ *
+ * @param int[] rc - row/col coordinates to test
+ * @return true if the coordinates are contained with this CellRange
+ */
+ operator fun contains(rc: IntArray): Boolean {
+ var ret = true
+ if (rc[0] + 1 < firstcellrow)
+ ret = false
+ if (rc[0] + 1 > lastcellrow)
+ ret = false
+ if (rc[1] < firstcellcol)
+ ret = false
+ if (rc[1] > lastcellcol)
+ ret = false
+ return ret
+ }
+
+ /**
+ * returns the String representation of this CellRange
+ */
+ override fun toString(): String? {
+ return range
+ }
+
+ /**
+ * Constructor to create a new CellRange from a WorkSheetHandle and a set of
+ * range coordinates:
+ * coords[0] = first row
+ * coords[1] = first col
+ * coords[2] = last row
+ * coords[3] = last col
+ *
+ * @param WorkSheetHandle sht - handle to the WorkSheet containing the Range's Cells
+ * @param int[] coords - the cell coordinates
+ * @param boolean cb - true if should create blank cells
+ * @throws Exception
+ */
+ @Throws(Exception::class)
+ @JvmOverloads
+ constructor(sht: WorkSheetHandle, coords: IntArray, cb: Boolean = false) {
+ this.createBlanks = cb
+ this.sheet = sht
+ this.workBook = sht.workBook
+ sheetname = sht.sheetName
+ sheetname = GenericPtg.qualifySheetname(sheetname)
+ var addr = sheetname!! + "!"
+ val c1 = ExcelTools.getAlphaVal(coords[1]) + (coords[0] + 1)
+ val c2 = ExcelTools.getAlphaVal(coords[3]) + (coords[2] + 1)
+ addr += "$c1:$c2"
+ this.range = addr
+ this.init()
+ }
+
+ /**
+ * Set this CellRange to be the current Print Area
+ */
+ fun setAsPrintArea() {
+ if (this.sheet == null) {
+ Logger.logErr("CellRange.setAsPrintArea() failed: " + this.toString()
+ + " does not have a valid Sheet reference.")
+ return
+ }
+ sheet!!.setPrintArea(this)
+ }
+
+ /**
+ * Constructor to Create a new CellRange from a String range
+ * The String range must be in the format Sheet!CR:CR
+ * For Example, "Sheet1!C9:I19"
+ * NOTE: You MUST Set the WorkBookHandle explicitly on this CellRange or it will
+ * generate NullPointerException when trying to access the Cells.
+ *
+ * @param String r - range String
+ * @see CellRange.setWorkBook
+ */
+ constructor(r: String) {
+ this.range = r
+ }
+
+ /**
+ * Increase the bounds of the CellRange by including the CellHandle.
+ * These are the limitations and side-effects of this method:
+ * - the Cell must be contiguous with the existing Range, ie: you can add a Cell
+ * which either increments the row or the column of the existing range by one.
+ *
+ * - the Cell must be on the same sheet as the existing range.
+ * - as a Cell Range is a 2 dimensional rectangle, expanding a multiple column
+ * range by adding a Cell to the end will include the logical Cells on the row
+ * in the range.
+ * Some Examples:
+ *
+ * // simple one dimensional range expansion:
+ * existing Range = A1:A20
+ * addCellToRange(A21) new Range = A1:A21
+ *
+ * existing Range = A1:B20
+ * addCellToRange(A21)
+ * new Range = A1:B21 // note B20 is included automatically
+ *
+ * existing Range = A1:A20
+ * addCellToRange(B1)
+ * new Range = A1:B20 //note entire B column of cells are included automatically
+ *
+ * @param CellHandle ch - the Cell to add to the CellRange
+ */
+ fun addCellToRange(ch: CellHandle): Boolean {
+ // check worksheet
+ val sheetname = ch.workSheetName
+ if (sheetname == null) {
+ Logger.logWarn("Cell $ch NOT added to Range: $this")
+ return false
+ }
+ if (!sheetname.equals(this.getSheet()!!.sheetName, ignoreCase = true)) {
+ Logger.logWarn("Cell $ch NOT added to Range: $this")
+ return false
+ }
+ val rc = intArrayOf(ch.rowNum, ch.colNum)
+ // increment to one-based
+ rc[0]++
+
+ // check that it's at the beginning
+ if (firstcellrow == -1)
+ firstcellrow = rc[0]
+ if (firstcellcol == -1)
+ firstcellcol = rc[1]
+ if (lastcellrow == -1)
+ lastcellrow = rc[0]
+ if (lastcellcol == -1)
+ lastcellcol = rc[1]
+ if (rc[0] < firstcellrow)
+ firstcellrow--
+ if (rc[1] < firstcellcol)
+ firstcellcol--
+ // check that it's at the end
+ if (rc[0] > lastcellrow)
+ lastcellrow++
+ if (rc[1] > lastcellcol)
+ lastcellcol++
+
+ // myptg is never set so myptg access never happens... taking out
+ // boolean addPtgInfo = false;
+ // if (myptg != null && myptg instanceof PtgRef)
+ // addPtgInfo = true;
+ // format the new range String
+ val newrange = this.getSheet()!!.sheetName + "!"
+ var newcellrange = ""
+ // if (addPtgInfo && !((PtgRef) myptg).isColRel())
+ // newcellrange += "$";
+ newcellrange += ExcelTools.getAlphaVal(firstcellcol)
+ // if (addPtgInfo && !((PtgRef) myptg).isRowRel())
+ // newcellrange += "$";
+ newcellrange += firstcellrow.toString()
+ newcellrange += ":"
+ // if (addPtgInfo && !((PtgRef) myptg).isColRel())
+ // newcellrange += "$";
+ newcellrange += ExcelTools.getAlphaVal(lastcellcol)
+ // if (addPtgInfo && !((PtgRef) myptg).isColRel())
+ // newcellrange += "$";
+ newcellrange += lastcellrow.toString()
+ this.range = newrange + newcellrange
+ isDirty = true
+
+ /*
+ * if (addPtgInfo) { ReferenceTracker.updateAddressPerPolicy(myptg,
+ * newcellrange); return true; }
+ */
+
+ if (this.parent != null && this.parent!!.opcode == XLSConstants.NAME) {
+ (parent as Name).location = this.range // ensure named range expression is updated, as well as any formula
+ // references are cleared of cache
+ }
+
+ return false
+ }
+
+ /**
+ * get the Cells in this cell range
+ *
+ * @return CellHandle[] all the Cells in this range
+ */
+ fun getCells(): Array? {
+ if (isDirty)
+ try {
+ init()
+ } catch (e: CellNotFoundException) {
+ }
+
+ return cells
+ }
+
+ /**
+ * Constructor which creates a new CellRange from a String range
+ * The String range must be in the format Sheet!CR:CR
+ * For Example, "Sheet1!C9:I19"
+ *
+ * @param String range - the range string
+ * @param WorkBook bk
+ * @param boolean createblanks - true if blank cells should be created if necessary
+ * @param boolean initcells - true if cells should (be initialized)
+ */
+ constructor(range: String, bk: io.starter.OpenXLS.WorkBook?, createblanks: Boolean, initcells: Boolean) {
+ createBlanks = createblanks
+ initializeCells = initcells
+ this.range = range
+ if (bk == null)
+ return
+ this.workBook = bk
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ }
+
+ }
+
+ /**
+ * Constructor which creates a new CellRange from a String range
+ * The String range must be in the format Sheet!CR:CR
+ * For Example, "Sheet1!C9:I19"
+ *
+ * @param String range - the range string
+ * @param WorkBook bk
+ * @param boolean createblanks - true if blank cells should be created (if
+ * necessary)
+ */
+ @JvmOverloads
+ constructor(range: String, bk: io.starter.OpenXLS.WorkBook?, c: Boolean = true) {
+ createBlanks = c
+ this.range = range
+ if (bk == null)
+ return
+ this.workBook = bk
+ try {
+ if ("" != this.range)
+ this.init()
+ } catch (e: CellNotFoundException) {
+ } catch (ne: NumberFormatException) {
+ // happens upon !REF range
+ }
+
+ }
+
+ /**
+ * sets the parent of this Cell range
+ * Used Internally. Not intended for the End User.
+ *
+ * @param b
+ */
+ fun setParent(b: BiffRec) {
+ parent = b
+ }
+
+ /**
+ * Re-sort all cells in this cell range according to the column.
+ *
+ *
+ * A custom comparator can be passed in, or the default one can be used with
+ * sort(String, boolean).
+ *
+ *
+ * Comparators will be passed 2 CellHandle objects for comparison.
+ *
+ *
+ * Collections.reverse will be called on the results if ascending is set to
+ * false;
+ *
+ * @param rowNumber the 0 based (row 5 = 4) number of the row to be sorted upon
+ * @param comparator
+ * @throws RowNotFoundException
+ * @throws ColumnNotFoundException
+ */
+ @Throws(RowNotFoundException::class)
+ fun sort(rownumber: Int, comparator: Comparator, ascending: Boolean) {
+ this.createBlanks()
+ val sortRow = this.getCellsByRow(rownumber)
+ Collections.sort(sortRow, comparator)
+ if (!ascending)
+ Collections.reverse(sortRow)
+ // now we have sorted the array list, come up with a map to resort the rows.
+ var coords: IntArray? = null
+ try {
+ coords = this.rangeCoords
+ // fix stupid wrong offsets;
+ coords[0] = coords[0]--
+ coords[2] = coords[2]--
+ } catch (e1: CellNotFoundException) {
+ }
+
+ val outputCols = ArrayList>()
+ for (i in sortRow.indices) {
+ val cell = sortRow[i]
+ var cells: ArrayList<*>? = null
+ try {
+ cells = this.getCellsByCol(ExcelTools.getAlphaVal(cell.colNum))
+ } catch (e: ColumnNotFoundException) {
+ // if there are no cells in this column ignore it
+ }
+
+ outputCols.add(cells)
+ }
+ this.removeCells()
+ for (i in coords!![1]..coords[3]) {
+ val cells = outputCols[i - coords[1]]
+ for (x in cells.indices) {
+ val cell = cells[x] as CellHandle
+ val bs = this.getSheet()!!.boundsheet
+ cell.cell!!.setCol(i.toShort())
+ bs!!.addCell(cell.cell as CellRec)
+ }
+ }
+
+ }
+
+ /**
+ * Changes the cellRange to a createBlanks cellrange and re-initializes the
+ * range, creating the missing blanks.
+ */
+ private fun createBlanks() {
+ if (!this.createBlanks) {
+ this.createBlanks = true
+ this.initializeCells = true
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ }
+
+ }
+ }
+
+ /**
+ * Resort all cells in the range according to the rownumber passed in.
+ *
+ * @param rownumber the 0 based row number
+ * @param ascending
+ * @throws RowNotFoundException
+ * @throws ColumnNotFoundException
+ */
+ @Throws(RowNotFoundException::class)
+ fun sort(rownumber: Int, ascending: Boolean) {
+ val cp = CellComparator()
+ this.sort(rownumber, cp, ascending)
+ }
+
+ /**
+ * Re-sort all cells in this cell range according to the column.
+ *
+ *
+ * A custom comparator can be passed in, or the default one can be used with
+ * sort(String, boolean).
+ *
+ *
+ * Comparators will be passed 2 CellHandle objects for comparison.
+ *
+ *
+ * * Collections.reverse will be called on the results if ascending is set to
+ * false;
+ *
+ * @param columnName
+ * @param comparator
+ * @throws RowNotFoundException
+ * @throws ColumnNotFoundException
+ */
+ @Throws(ColumnNotFoundException::class)
+ fun sort(columnName: String, comparator: Comparator<*>, ascending: Boolean) {
+ if (!this.createBlanks) {
+ // we cannot have empty cells in this operation
+ this.createBlanks = true
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ }
+
+ }
+ val sortCol = this.getCellsByCol(columnName)
+ Collections.sort(sortCol, comparator)
+ if (!ascending)
+ Collections.reverse(sortCol)
+ // now we have sorted the array list, come up with a map to resort the rows.
+ var coords: IntArray? = null
+ try {
+ coords = this.rangeCoords
+ // fix stupid wrong offsets;
+ coords[0] = coords[0]--
+ coords[2] = coords[2]--
+ } catch (e1: CellNotFoundException) {
+ e1.printStackTrace()
+ }
+
+ val outputRows = ArrayList>()
+ for (i in sortCol.indices) {
+ var cells: ArrayList? = null
+ try {
+ cells = this.getCellsByRow(sortCol[i].rowNum)
+ } catch (e: RowNotFoundException) {
+ // ignore if no cells available
+ }
+
+ outputRows.add(cells)
+ }
+ this.removeCells()
+ for (i in coords!![0]..coords[2]) {
+ val cells = outputRows[i - coords[0]]
+ for (x in cells.indices) {
+ val cell = cells[x]
+ val bs = this.getSheet()!!.boundsheet
+ cell.cell!!.rowNumber = i - 1
+ bs!!.addCell(cell.cell as CellRec)
+ }
+ }
+ }
+
+ /**
+ * Resort all cells in the range according to the column passed in.
+ *
+ * @param columnName
+ * @param ascending
+ * @throws ColumnNotFoundException
+ * @throws RowNotFoundException
+ */
+ @Throws(ColumnNotFoundException::class)
+ fun sort(columnName: String, ascending: Boolean) {
+ val cp = CellComparator()
+ this.sort(columnName, cp, ascending)
+ }
+
+ /**
+ * gets the array of Cells in this Name
+ *
+ *
+ * NOTE: this method variation also returns the Sheetname for the name record if
+ * not null.
+ *
+ *
+ * Thus this method is limited to use with 2D ranges.
+ *
+ * @param fragment whether to enclose result in NameHandle tag
+ * @return Cell[] all Cells defined in this Name
+ */
+ fun getCellRangeXML(fragment: Boolean): String {
+ val sbx = StringBuffer()
+ if (!fragment)
+ sbx.append("")
+ sbx.append("")
+ sbx.append(xml)
+ sbx.append("")
+ return sbx.toString()
+ }
+
+ /**
+ * Constructor which creates a new CellRange using an array of cells as it's
+ * constructor.
+ * NOTE that if the array of cells you are adding is not a rectangle of data (ie
+ * [A1][B1][C1]) that you will have null cells in your cell range and operations
+ * on it may cause errors.
+ * If you wish to populate a cell range that is not contiguous, consider the
+ * constructor CellRange(CellHandle[] newcells, boolean createblanks), which
+ * will populate null cells with blank records, allowing normal operations such
+ * as formatting, merging, etc.
+ *
+ * @param CellHandle[] newcells - the array of cells from which to create the new
+ * CellRange
+ * @throws CellNotFoundException
+ */
+ @Throws(CellNotFoundException::class)
+ constructor(newcells: Array) {
+ this.workBook = newcells[0].workBook
+ this.sheet = newcells[0].workSheetHandle
+ for (x in newcells.indices) {
+ this.addCellToRange(newcells[x])
+ }
+ this.init()
+ }
+
+ /**
+ * create a new CellRange using an array of cells as it's constructor.
+ * If you wish to populate a cell range that is not contiguous, set createblanks
+ * to true, which will populate null cells with blank records, allowing normal
+ * operations such as formatting, merging, etc.
+ *
+ * @param CellHandle[] newcells - the array of cells from which to create the new
+ * CellRange
+ * @param boolean createblanks - true if should create blank cells if necesary
+ */
+ @Throws(CellNotFoundException::class)
+ constructor(newcells: Array, createblanks: Boolean) {
+ this.createBlanks = createblanks
+ this.workBook = newcells[0].workBook
+ this.sheet = newcells[0].workSheetHandle
+ for (x in newcells.indices) {
+ this.addCellToRange(newcells[x])
+ }
+ this.init()
+ }
+
+ /**
+ * Returns the WorkSheet referenced in this CellRange.
+ *
+ * @return WorkSheetHandle sheet referenced in this CellRange.
+ */
+ fun getSheet(): WorkSheetHandle? {
+ return sheet
+ }
+
+ /**
+ * initializes this CellRange
+ *
+ * @throws CellNotFoundException
+ */
+ @Throws(CellNotFoundException::class)
+ fun init() {
+ if (!FormulaParser.isComplexRange(range)) {
+ val coords = this.rangeCoords
+ var rowctr = coords[0]
+ val firstcellcol = coords[1]
+ val lastcellcol = coords[3]
+ val numcells = coords[4]
+
+ var cellctr = firstcellcol - 1
+ try {
+ if (sheetname != null) {
+ if (sheetname == "")
+ // 20080214 KSC - is this a good idea?
+ // default to work sheet 0
+ sheetname = this.workBook!!.getWorkSheet(0).sheetName
+ }
+ if (sheetname == null) {
+ if (this.sheet != null)
+ sheetname = this.sheet!!.sheetName
+ else
+ throw IllegalArgumentException("sheet name not specified: " + range!!)
+ }
+
+ var s = sheetname
+ if (s != null) {
+ // handle enclosing apostrophes which are added to PtgRefs
+ if (s[0] == '\'') {
+ s = s.substring(1)
+ if (s[s.length - 1] == '\'') {
+ s = s.substring(0, s.length - 1)
+ }
+ }
+ }
+ sheet = workBook!!.getWorkSheet(s)
+ // if wholerow or wholecol, don't gather cells
+ if (this.wholeCol || this.wholeRow)
+ return
+ cells = arrayOfNulls(numcells)
+ var resetFastAdds = false
+ if (sheet!!.fastCellAdds && this.createBlanks) {
+ resetFastAdds = true
+ sheet!!.fastCellAdds = false
+ }
+ for (i in 0 until numcells) {
+ if (cellctr == lastcellcol) {// if its the end of the row,
+ // increment row.
+ cellctr = firstcellcol - 1
+ rowctr++
+ }
+ ++cellctr
+ try {
+ // use caching 20080917 KSC: PROBLEM HERE [Claritas
+ // BugTracker 1862]
+ if (this.initializeCells)
+ cells[i] = sheet!!.getCell(rowctr - 1, cellctr, sheet!!.useCache) // 20080917 KSC: use
+ // cache
+ // setting instead of
+ // defaulting to true);
+ } catch (e: CellNotFoundException) {
+ if (this.createBlanks) {
+ cells[i] = sheet!!.add(null, rowctr - 1, cellctr)
+ }
+
+ }
+
+ }
+ if (resetFastAdds) {
+ sheet!!.fastCellAdds = true
+ }
+ } catch (e: WorkSheetNotFoundException) {
+ throw IllegalArgumentException(e.toString())
+ }
+
+ } else { // gather cells for a complex range ...
+ val pm = io.starter.formats.XLS.formulas.PtgMemFunc()
+ val b = XLSRecord()
+ b.workBook = this.workBook!!.workBook
+ pm.parentRec = b
+ try {
+ pm.location = range
+ val p = pm.components
+ val cellsfromcomplexrange = java.util.ArrayList()
+ for (i in p!!.indices) {
+ try {
+ cellsfromcomplexrange.add(workBook!!.getCell((p[i] as PtgRef).location))
+ } catch (e: CellNotFoundException) {
+ if (this.createBlanks) {
+ cells[i] = sheet!!.add(null, p[i].location)
+ }
+ }
+
+ }
+ cells = arrayOfNulls(cellsfromcomplexrange.size)
+ cells = cellsfromcomplexrange.toTypedArray()
+ } catch (e: Exception) {
+ throw IllegalArgumentException(e.toString())
+ }
+
+ }
+ isDirty = false
+ }
+
+ /**
+ * Initializes this `CellRange`'s cell list if necessary. This method
+ * is useful if this `CellRange` was created with
+ * `initCells` set to `false` and it is later necessary to
+ * retrieve the cell list.
+ *
+ * @param createBlanks whether missing cells should be created as blanks. If this is
+ * `false` they will appear in the cell list as
+ * `null`s.
+ */
+ fun initCells(createBlanks: Boolean) {
+ // If we don't need to do anything, return
+ if (initializeCells == true && (!createBlanks || this.createBlanks))
+ return
+
+ this.initializeCells = true
+ this.createBlanks = createBlanks
+
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ // This will never actually happen but we have to catch it anyway
+ throw Error()
+ }
+
+ }
+
+ /**
+ * Return the String representation of this range
+ *
+ * @return the String range
+ */
+ fun getRange(): String? {
+ return range
+ }
+
+ /**
+ * Sets the range of cells for this CellRange to a string range
+ *
+ * @param String rng - Range string
+ */
+ fun setRange(rng: String) {
+ range = rng
+ try {
+ this.init()
+ } catch (e: CellNotFoundException) {
+ // don't have to report anything
+ }
+
+ }
+
+ /**
+ * sets a border around the range of cells
+ *
+ * @param int width - line width
+ * @param int linestyle - line style
+ * @param java.awt.Color colr - color of border line
+ */
+ fun setBorder(width: Int, linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ val coords = getEdgePositions(ch[t], width)
+ // create Excel border -- top, left, bottom, right
+ if (coords[0] > 0) {
+ ch[t].setTopBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderTopColor(colr)
+ }
+ if (coords[1] > 0) {
+ ch[t].setLeftBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderLeftColor(colr)
+ }
+ if (coords[2] > 0) {
+ ch[t].setBottomBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderBottomColor(colr)
+ }
+ if (coords[3] > 0) {
+ ch[t].setRightBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderRightColor(colr)
+ }
+ }
+ }
+
+ /**
+ * update the CellRange when the underlying Cells change their location
+ *
+ * @return boolean true if the CellRange could be updated, false if there are no
+ * cells represented by this range
+ */
+ fun update(): Boolean {
+ if (cells == null)
+ return false // this is an invalid range -- see Mergedcells prob.
+ // jm
+
+ // arbitrarily set the initial vals...
+ if (cells!![0] != null) { // 20100106 KSC: if didn't create blanks it's possible that cells are null
+ firstcellrow = cells!![0].rowNum + 1
+ firstcellcol = cells!![0].colNum
+ lastcellrow = cells!![0].rowNum + 1
+ lastcellcol = cells!![0].colNum
+ for (t in cells!!.indices) {
+ val cx = cells!![t]
+ // 20090901 KSC: apparently can be null
+ if (cx != null)
+ this.addCellToRange(cx)
+ }
+ this.myrowints = null
+ this.mycolints = null
+ return true
+ } else if (this.range != null) {// 20100106 KSC: handle ranges containing null cell[0] (i.e. ranges referencing
+ // cells not present and createBlanks==false)
+ if (this.DEBUG)
+ Logger.logWarn("CellRange.update: trying to access blank cells in range " + this.range!!)
+ try {
+ this.rangeCoords
+ return true
+ } catch (e: CellNotFoundException) { // shouldn't
+ return false
+ }
+
+ }
+ return false // return false if it doesn't have it's cells defined
+ }
+
+ /**
+ * Sets the sheet reference for this CellRange.
+ *
+ * @param WorkSheetHandle aSheet
+ */
+ fun setSheet(aSheet: WorkSheetHandle) {
+ this.sheet = aSheet
+ this.sheetname = aSheet.sheetName
+ }
+
+ /**
+ * Copies this range to another location. At present only contents and complete
+ * formats may be copied.
+ *
+ * @param row the topmost row of the target area
+ * @param col the leftmost column of the target area
+ * @param what a set of flags determining what will be copied
+ * @return the destination range
+ */
+ fun copy(sheet: WorkSheetHandle, row: Int, col: Int, what: Int): CellRange {
+ var row = row
+ var col = col
+ val result = CellRange(sheet, row, col, this.width, this.height)
+
+ val first_col = col
+
+ // note these are not currently used, see setting below
+ val copy_contents = what and COPY_CONTENTS != 0
+ var copy_formulas = what and COPY_FORMULAS != 0
+ var copy_formats = what and COPY_FORMATS != 0
+
+ // set to true until this thing is fully implemented
+ copy_formats = true
+ copy_formulas = true
+
+ var cur_row = cells!![0].rowNum
+ for (idx in cells!!.indices) {
+ val source = cells!![idx]
+
+ if (source.rowNum != cur_row) {
+ cur_row = source.rowNum
+ row++
+ col = first_col
+ }
+
+ var target: CellHandle? = null
+ try {
+ target = sheet.getCell(row, col)
+ } catch (e: CellNotFoundException) {
+ }
+
+ val formatID: Int
+ if (copy_formats)
+ formatID = source.formatId
+ else if (target != null)
+ formatID = target.formatId
+ else
+ formatID = sheet.workBook!!.workBook!!.defaultIxfe
+
+ if (copy_contents) {
+ val value: Any?
+
+ if (copy_formulas && source.isFormula) {
+ try {
+ value = source.formulaHandle.formulaString
+ } catch (e: FormulaNotFoundException) {
+ // This shouldn't happen; we known the formula exists.
+ // If it does happen it indicates a bug in OpenXLS,
+ // thus we throw an Error.
+ throw Error("formula cell has no Formula record", e)
+ }
+
+ } else {
+ value = source.`val`
+ }
+
+ target = sheet.add(value, row, col, formatID)
+
+ if (target!!.isFormula)
+ try {
+ FormulaHandle.moveCellRefs(target.formulaHandle,
+ intArrayOf(row - source.rowNum, col - source.colNum))
+ } catch (e: FormulaNotFoundException) {
+ }
+
+ } else if (target == null) {
+ target = sheet.add(null, row, col, formatID)
+ }
+
+ if (copy_formats) {
+ target!!.formatId = formatID
+ }
+
+ result.cells[idx] = target
+ col++
+ }
+
+ return result
+ }
+
+ /**
+ * Fills this range from the given cell.
+ *
+ * @param source the cell whose attributes should be copied or `null` to
+ * copy from the first cell in the range
+ * @param what a set of flags determining what will be copied
+ * @param increment the amount by which to increment numeric values or
+ * `NaN` for no increment
+ */
+ fun fill(source: CellHandle?, what: Int, increment: Double) {
+ var source = source
+ if (null == source)
+ source = cells!![0]
+
+ val copy_contents = what and COPY_CONTENTS != 0
+ val copy_formulas = what and COPY_FORMULAS != 0
+ val copy_formats = what and COPY_FORMATS != 0
+
+ val sourceRow = source.rowNum
+ val sourceCol = source.colNum
+
+ var value: Any? = null
+ if (copy_contents) {
+ if (copy_formulas && source.isFormula) {
+ try {
+ value = source.formulaHandle.formulaString
+ } catch (e: FormulaNotFoundException) {
+ throw Error("formula cell has no Formula record", e)
+ }
+
+ } else {
+ value = source.`val`
+ }
+ }
+
+ // if increment is set, ensure the value can be incremented
+ if (!java.lang.Double.isNaN(increment) && !(copy_contents && value is Number))
+ throw IllegalArgumentException("cannot increment unless filling with a numeric value")
+
+ for (idx in cells!!.indices) {
+ var target: CellHandle? = cells!![idx]
+
+ // don't overwrite the source cell
+ if (source == target)
+ continue
+
+ if (!java.lang.Double.isNaN(increment))
+ value = (value as Number).toDouble() + increment
+
+ val formatID = (if (copy_formats) source else target).formatId
+
+ if (copy_contents) {
+ target = sheet!!.add(value, target!!.rowNum, target.colNum, formatID)
+ cells[idx] = target
+
+ if (target!!.isFormula)
+ try {
+ FormulaHandle.moveCellRefs(target.formulaHandle,
+ intArrayOf(target.rowNum - sourceRow, target.colNum - sourceCol))
+ } catch (e: FormulaNotFoundException) {
+ }
+
+ }
+
+ // when adding Date values passing the format ID to sheet.add
+ // doesn't set the format so we always set it here
+ if (copy_formats) {
+ target!!.formatId = formatID
+ }
+
+ }
+ }
+
+ fun calculateAffectedCellsOnSheet(): Collection {
+ val affected = HashSet()
+ for (cell in cells!!) {
+ if (cell != null) {
+ affected.add(cell)
+ affected.addAll(cell.calculateAffectedCellsOnSheet())
+ }
+ }
+ return affected
+ }
+
+ /**
+ * Get the cells from a particular rownumber, constrained by the boundaries of
+ * the cellRange
+ *
+ * @param rownumber
+ */
+ @Throws(RowNotFoundException::class)
+ fun getCellsByRow(rownumber: Int): ArrayList {
+ val al = ArrayList()
+ val r = this.getSheet()!!.getRow(rownumber)
+ val cells = r.cells
+ var coords: IntArray? = null
+ try {
+ coords = this.rangeCoords
+ } catch (e: CellNotFoundException) {
+ throw RowNotFoundException("Error getting internal coordinates for CellRange$e")
+ }
+
+ for (i in cells.indices) {
+ if (cells[i].colNum >= coords[1] && cells[i].colNum <= coords[3]) {
+ al.add(cells[i])
+ }
+ }
+ return al
+ }
+
+ /**
+ * Get the cells from a particular column, constrained by the boundaries of the
+ * cellRange
+ *
+ * @param rownumber
+ * @throws ColumnNotFoundException
+ */
+ @Throws(ColumnNotFoundException::class)
+ fun getCellsByCol(col: String): ArrayList {
+ val al = ArrayList()
+ val r = this.getSheet()!!.getCol(col)
+ val cells = r.cells
+ var coords: IntArray? = null
+ try {
+ coords = this.rangeCoords
+ coords[0] = coords[0] - 1
+ coords[2] = coords[2] - 1
+ } catch (e: CellNotFoundException) {
+ throw ColumnNotFoundException("Error getting internal coordinates for CellRange$e")
+ }
+
+ for (i in cells.indices) {
+ if (cells[i].rowNum >= coords[0] && cells[i].rowNum <= coords[2]) {
+ al.add(cells[i])
+ }
+ }
+ return al
+ }
+
+ /**
+ * removes the border from all of the cells in this range
+ */
+ fun removeBorder() {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].removeBorder()
+ }
+ }
+
+ /**
+ * Sets a bottom border on all cells in the cellrange
+ *
+ *
+ * Linestyle should be set through the FormatHandle constants
+ */
+ fun setInnerBorderBottom(linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].setBottomBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderBottomColor(colr)
+ }
+ }
+
+ /**
+ * Sets a right border on all cells in the cellrange
+ *
+ *
+ * Linestyle should be set through the FormatHandle constants
+ */
+ fun setInnerBorderRight(linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].setRightBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderRightColor(colr)
+ }
+ }
+
+ /**
+ * Sets a left border on all cells in the cellrange
+ *
+ *
+ * Linestyle should be set through the FormatHandle constants
+ */
+ fun setInnerBorderLeft(linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].setLeftBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderLeftColor(colr)
+ }
+ }
+
+ /**
+ * Sets a top border on all cells in the cellrange
+ *
+ *
+ * Linestyle should be set through the FormatHandle constants
+ */
+ fun setInnerBorderTop(linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].setTopBorderLineStyle(linestyle.toShort())
+ ch[t].setBorderTopColor(colr)
+ }
+ }
+
+ /**
+ * Sets a surround border on all cells in the cellrange
+ *
+ *
+ * Linestyle should be set through the FormatHandle constants
+ */
+ fun setInnerBorderSurround(linestyle: Int, colr: java.awt.Color) {
+ val ch = getCells()
+ for (t in ch!!.indices) {
+ ch[t].setBorderColor(colr)
+ ch[t].setBorderLineStyle(linestyle.toShort())
+ }
+ }
+
+ companion object {
+
+ /**
+ *
+ */
+ private const val serialVersionUID = -3609881364824289079L
+ val REMOVE_MERGED_CELLS = true
+ val RETAIN_MERGED_CELLS = false
+
+ var xmlResponsePre = ""
+ var xmlResponsePost = " "
+
+ /**
+ * Whether to copy the cell contents.
+ */
+ val COPY_CONTENTS = 0x01
+
+ /**
+ * Whether formulas should be copied. If this bit is not set the formula result
+ * will be copied instead.
+ */
+ val COPY_FORMULAS = 0x02
+
+ val COPY_FORMATS = 0x0100
+
+ /**
+ * return a JSON array of cell values for the given range
+ * static version
+ *
+ * @param String range - a string representation of the desired range of cells
+ * @param WorkBook wbh - the source WorkBook for the cell range
+ * @return JSONArray - a JSON representation of the desired cell range
+ */
+ fun getValuesAsJSON(range: String, wbh: WorkBook): JSONArray {
+ val rangeArray = JSONArray()
+ try {
+ val cr = CellRange(range, wbh, true)
+ for (j in 0 until cr.getCells()!!.size)
+ rangeArray.put(cr.getCells()!![j].`val`)
+ } catch (e: Exception) {
+ Logger.logErr("Error obtaining CellRange $range JSON: $e")
+ }
+
+ return rangeArray
+ }
+
+ /**
+ * returns the cells for a given range
+ * static version
+ *
+ * @param String range - a string representation of the desired range of cells
+ * @param WorkBook wbh - the source WorkBook for the cell range
+ * @return CellHandle[] array of cells represented by the desired cell range
+ */
+ fun getCells(range: String, wbh: WorkBookHandle): Array? {
+ val cr = CellRange(range, wbh, true)
+ return cr.getCells()
+ }
+ }
+
+}
+/**
+ * Initializes a `CellRange` from a `CellRangeRef`. The
+ * source `CellRangeRef` instance must be qualified with a single
+ * resolved worksheet.
+ *
+ * @param source the `CellRangeRef` from which to initialize
+ * @throws IllegalArgumentException if the source range does not have a resolved sheet or has more
+ * than one sheet
+`` */
+/**
+ * Constructor to create a new CellRange from a WorkSheetHandle and a set of
+ * range coordinates:
+ * coords[0] = first row
+ * coords[1] = first col
+ * coords[2] = last row
+ * coords[3] = last col
+ *
+ * @param WorkSheetHandle sht - handle to the WorkSheet containing the Range's Cells
+ * @param int[] coords - the cell coordinates
+ */
+/**
+ * Constructor which creates a new CellRange from a String range
+ * The String range must be in the format Sheet!CR:CR
+ * For Example, "Sheet1!C9:I19"
+ *
+ * @param String range - the range string
+ * @param WorkBook bk
+ * @throws CellNotFoundException
+ */
diff --git a/src/main/java/io/starter/OpenXLS/CellRangeRef.java b/src/main/java/io/starter/OpenXLS/CellRangeRef.java
deleted file mode 100644
index 62ba1f7..0000000
--- a/src/main/java/io/starter/OpenXLS/CellRangeRef.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import io.starter.formats.XLS.WorkSheetNotFoundException;
-import io.starter.formats.XLS.XLSRecord;
-
-/**
- * Represents a reference to a 3D range of cells.
- *
- * This class is not currently part of the public API.
- *
- * No input validation whatsoever is performed. Any combination of values may be
- * set, whether it makes any sense or not.
- *
- * Starter Inc.
- *
- * @see DataBoundCellRange
- * @see XLSRecord
- */
-public class CellRangeRef implements Cloneable {
- private int first_col, first_row, last_col, last_row;
- private String first_sheet_name, last_sheet_name;
- private WorkSheetHandle first_sheet, last_sheet;
-
- /** Private nullary constructor for use by static pseudo-constructors. */
- private CellRangeRef() {
- }
-
- public CellRangeRef(int first_row, int first_col, int last_row, int last_col) {
- this.first_row = first_row;
- this.first_col = first_col;
- this.last_row = last_row;
- this.last_col = last_col;
- }
-
- /**
- * return the number of cells in this rangeref
- *
- * @return number of cells in ref
- */
- public int numCells() {
- int ret = -1;
- int numrows = this.last_row - this.first_row;
- numrows++;
- int numcols = this.last_col - this.first_col;
- numcols++;
- ret = numrows * numcols;
- return ret;
- }
-
- public CellRangeRef(int first_row, int first_col, int last_row, int last_col, String first_sheet,
- String last_sheet) {
- this(first_row, first_col, last_row, last_col);
- this.first_sheet_name = first_sheet;
- this.last_sheet_name = last_sheet;
- }
-
- public CellRangeRef(int first_row, int first_col, int last_row, int last_col, WorkSheetHandle first_sheet,
- WorkSheetHandle last_sheet) {
- this(first_row, first_col, last_row, last_col);
- this.first_sheet = first_sheet;
- this.last_sheet = last_sheet;
- }
-
- /**
- * Parses a range in A1 notation and returns the equivalent CellRangeRef.
- */
- public static CellRangeRef fromA1(String reference) {
- CellRangeRef ret = new CellRangeRef();
- String range;
-
- {
- String[] parts = ExcelTools.stripSheetNameFromRange(reference);
- ret.first_sheet_name = parts[0];
- range = parts[1];
- ret.last_sheet_name = parts[2];
- }
-
- if (range == null)
- throw new IllegalArgumentException("missing range component");
-
- {
- int[] parts = ExcelTools.getRangeRowCol(range);
- ret.first_row = parts[0];
- ret.first_col = parts[1];
- ret.last_row = parts[2];
- ret.last_col = parts[3];
- }
-
- return ret;
- }
-
- /**
- * Convenience method combining {@link #fromA1(String)} and
- * {@link #resolve(WorkBookHandle)}.
- */
- public static CellRangeRef fromA1(String reference, WorkBookHandle book) throws WorkSheetNotFoundException {
- CellRangeRef ret = fromA1(reference);
- ret.resolve(book);
- return ret;
- }
-
- /**
- * Resolves sheet names into sheet handles against the given book.
- *
- * @param book
- * the book against which the sheet names should be resolved
- * @throws WorkSheetNotFoundException
- * if either of the sheets does not exist in the given book
- */
- public void resolve(WorkBookHandle book) throws WorkSheetNotFoundException {
- if (first_sheet_name != null)
- first_sheet = book.getWorkSheet(first_sheet_name);
- if (last_sheet_name != null)
- last_sheet = book.getWorkSheet(last_sheet_name);
- }
-
- /**
- * Returns the lowest-indexed row in this range.
- *
- * @return the row index or null if this is a column range
- */
- public int getFirstRow() {
- return first_row;
- }
-
- /**
- * Returns the lowest-indexed column in this range.
- *
- * @return the column index or null if this is a row range
- */
- public int getFirstColumn() {
- return first_col;
- }
-
- /**
- * Returns the highest-indexed row in this range.
- *
- * @return the row index or null if this is a column range
- */
- public int getLastRow() {
- return last_row;
- }
-
- /**
- * Returns the highest-indexed column in this range.
- *
- * @return the column index or null if this is a row range
- */
- public int getLastColumn() {
- return last_col;
- }
-
- /**
- * Returns the name of the first sheet in this range.
- *
- * @return the name of the sheet or null if this range is not qualified with a
- * sheet
- */
- public String getFirstSheetName() {
- if (first_sheet != null)
- return first_sheet.getSheetName();
- else
- return first_sheet_name;
- }
-
- /**
- * Returns the first sheet in this range.
- *
- * @return the WorkSheetHandle or null if this range is not qualified with a
- * sheet or the sheet names have not been resolved
- */
- public WorkSheetHandle getFirstSheet() {
- return first_sheet;
- }
-
- /**
- * Returns the name of the last sheet in this range.
- *
- * @return the name of the sheet or null if this range is not qualified with a
- * sheet
- */
- public String getLastSheetName() {
- if (last_sheet != null)
- return last_sheet.getSheetName();
- else
- return last_sheet_name;
- }
-
- /**
- * Returns the last sheet in this range.
- *
- * @return the WorkSheetHandle or null if this range is not qualified with a
- * sheet or the sheet names have not been resolved
- */
- public WorkSheetHandle getLastSheet() {
- return last_sheet;
- }
-
- /**
- * Determines whether this range is qualified with a sheet.
- */
- public boolean hasSheet() {
- return first_sheet != null || first_sheet_name != null;
- }
-
- /**
- * Determines whether this range spans multiple sheets.
- */
- public boolean isMultiSheet() {
- return (first_sheet != null && last_sheet != null && first_sheet != last_sheet)
- || (first_sheet_name != null && last_sheet_name != null && first_sheet_name != last_sheet_name);
- }
-
- /**
- * Sets the first row in this range.
- *
- * @param value
- * the row index to set
- */
- public void setFirstRow(int value) {
- first_row = value;
- }
-
- /**
- * Sets the first column in this range.
- *
- * @param value
- * the column index to set
- */
- public void setFirstColumn(int value) {
- first_col = value;
- }
-
- /**
- * Sets the first sheet in this range.
- */
- public void setFirstSheet(WorkSheetHandle sheet) {
- first_sheet_name = null;
- first_sheet = sheet;
- }
-
- /**
- * Sets the last row in this range.
- *
- * @param value
- * the row index to set
- */
- public void setLastRow(int value) {
- last_row = value;
- }
-
- /**
- * Sets the last column in this range.
- *
- * @param value
- * the column index to set
- */
- public void setLastColumn(int value) {
- last_col = value;
- }
-
- /**
- * Sets the last sheet in this range.
- */
- public void setLastSheet(WorkSheetHandle sheet) {
- last_sheet_name = null;
- last_sheet = sheet;
- }
-
- /**
- * Returns whether this range entirely contains the given range. This ignores
- * the sheets, if any, and compares only the cell ranges.
- */
- public boolean contains(CellRangeRef range) {
- return this.first_row <= range.first_row && this.last_row >= range.last_row && this.first_col <= range.first_col
- && this.last_col >= range.last_col;
- }
-
- /**
- * Compares this range to the specified object. The result is true
- * if and only if the argument is not null and is a
- * CellRangeRef object that represents the same range as this
- * object.
- */
- @Override
- public boolean equals(Object other) {
- // if it's null or not a CellRangeRef it can't be equal
- if (other == null || !(other instanceof CellRangeRef))
- return false;
-
- return this.toString().equals(other.toString());
- }
-
- /** Creates and returns a copy of this range. */
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException e) {
- // This can't happen (we're Cloneable) but we have to catch it
- throw new Error("Object.clone() threw CNSE but we're Cloneable");
- }
- }
-
- /** Gets this range in A1 notation. */
- @Override
- public String toString() {
- String sheet1 = getFirstSheetName();
- String sheet2 = getLastSheetName();
- return (sheet1 != null ? sheet1 + (sheet2 != null && sheet2 != sheet1 ? ":" + sheet2 : "") + "!" : "")
- + ExcelTools.formatRange(new int[] { first_col, first_row, last_col, last_row });
- }
-}
diff --git a/src/main/java/io/starter/OpenXLS/CellRangeRef.kt b/src/main/java/io/starter/OpenXLS/CellRangeRef.kt
new file mode 100644
index 0000000..114f09f
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/CellRangeRef.kt
@@ -0,0 +1,300 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.WorkSheetNotFoundException
+import io.starter.formats.XLS.XLSRecord
+
+/**
+ * Represents a reference to a 3D range of cells.
+ *
+ *
+ * This class is not currently part of the public API.
+ *
+ *
+ * No input validation whatsoever is performed. Any combination of values may be
+ * set, whether it makes any sense or not.
+ *
+ * [Starter Inc.](http://starter.io)
+ *
+ * @see DataBoundCellRange
+ *
+ * @see XLSRecord
+ */
+class CellRangeRef : Cloneable {
+ /**
+ * Returns the lowest-indexed column in this range.
+ *
+ * @return the column index or null if this is a row range
+ */
+ /**
+ * Sets the first column in this range.
+ *
+ * @param value the column index to set
+ */
+ var firstColumn: Int = 0
+ /**
+ * Returns the lowest-indexed row in this range.
+ *
+ * @return the row index or null if this is a column range
+ */
+ /**
+ * Sets the first row in this range.
+ *
+ * @param value the row index to set
+ */
+ var firstRow: Int = 0
+ /**
+ * Returns the highest-indexed column in this range.
+ *
+ * @return the column index or null if this is a row range
+ */
+ /**
+ * Sets the last column in this range.
+ *
+ * @param value the column index to set
+ */
+ var lastColumn: Int = 0
+ /**
+ * Returns the highest-indexed row in this range.
+ *
+ * @return the row index or null if this is a column range
+ */
+ /**
+ * Sets the last row in this range.
+ *
+ * @param value the row index to set
+ */
+ var lastRow: Int = 0
+ private var first_sheet_name: String? = null
+ private var last_sheet_name: String? = null
+ private var first_sheet: WorkSheetHandle? = null
+ private var last_sheet: WorkSheetHandle? = null
+
+ /**
+ * Returns the name of the first sheet in this range.
+ *
+ * @return the name of the sheet or null if this range is not qualified with a
+ * sheet
+ */
+ val firstSheetName: String?
+ get() = if (first_sheet != null)
+ first_sheet!!.sheetName
+ else
+ first_sheet_name
+
+ /**
+ * Returns the first sheet in this range.
+ *
+ * @return the WorkSheetHandle or null if this range is not qualified with a
+ * sheet or the sheet names have not been resolved
+ */
+ /**
+ * Sets the first sheet in this range.
+ */
+ var firstSheet: WorkSheetHandle?
+ get() = first_sheet
+ set(sheet) {
+ first_sheet_name = null
+ first_sheet = sheet
+ }
+
+ /**
+ * Returns the name of the last sheet in this range.
+ *
+ * @return the name of the sheet or null if this range is not qualified with a
+ * sheet
+ */
+ val lastSheetName: String?
+ get() = if (last_sheet != null)
+ last_sheet!!.sheetName
+ else
+ last_sheet_name
+
+ /**
+ * Returns the last sheet in this range.
+ *
+ * @return the WorkSheetHandle or null if this range is not qualified with a
+ * sheet or the sheet names have not been resolved
+ */
+ /**
+ * Sets the last sheet in this range.
+ */
+ var lastSheet: WorkSheetHandle?
+ get() = last_sheet
+ set(sheet) {
+ last_sheet_name = null
+ last_sheet = sheet
+ }
+
+ /**
+ * Determines whether this range spans multiple sheets.
+ */
+ val isMultiSheet: Boolean
+ get() = first_sheet != null && last_sheet != null && first_sheet !== last_sheet || first_sheet_name != null && last_sheet_name != null && first_sheet_name !== last_sheet_name
+
+ /**
+ * Private nullary constructor for use by static pseudo-constructors.
+ */
+ private constructor() {}
+
+ constructor(first_row: Int, first_col: Int, last_row: Int, last_col: Int) {
+ this.firstRow = first_row
+ this.firstColumn = first_col
+ this.lastRow = last_row
+ this.lastColumn = last_col
+ }
+
+ /**
+ * return the number of cells in this rangeref
+ *
+ * @return number of cells in ref
+ */
+ fun numCells(): Int {
+ var ret = -1
+ var numrows = this.lastRow - this.firstRow
+ numrows++
+ var numcols = this.lastColumn - this.firstColumn
+ numcols++
+ ret = numrows * numcols
+ return ret
+ }
+
+ constructor(first_row: Int, first_col: Int, last_row: Int, last_col: Int, first_sheet: String,
+ last_sheet: String) : this(first_row, first_col, last_row, last_col) {
+ this.first_sheet_name = first_sheet
+ this.last_sheet_name = last_sheet
+ }
+
+ constructor(first_row: Int, first_col: Int, last_row: Int, last_col: Int, first_sheet: WorkSheetHandle,
+ last_sheet: WorkSheetHandle) : this(first_row, first_col, last_row, last_col) {
+ this.first_sheet = first_sheet
+ this.last_sheet = last_sheet
+ }
+
+ /**
+ * Resolves sheet names into sheet handles against the given book.
+ *
+ * @param book the book against which the sheet names should be resolved
+ * @throws WorkSheetNotFoundException if either of the sheets does not exist in the given book
+ */
+ @Throws(WorkSheetNotFoundException::class)
+ fun resolve(book: WorkBookHandle) {
+ if (first_sheet_name != null)
+ first_sheet = book.getWorkSheet(first_sheet_name)
+ if (last_sheet_name != null)
+ last_sheet = book.getWorkSheet(last_sheet_name)
+ }
+
+ /**
+ * Determines whether this range is qualified with a sheet.
+ */
+ fun hasSheet(): Boolean {
+ return first_sheet != null || first_sheet_name != null
+ }
+
+ /**
+ * Returns whether this range entirely contains the given range. This ignores
+ * the sheets, if any, and compares only the cell ranges.
+ */
+ operator fun contains(range: CellRangeRef): Boolean {
+ return (this.firstRow <= range.firstRow && this.lastRow >= range.lastRow && this.firstColumn <= range.firstColumn
+ && this.lastColumn >= range.lastColumn)
+ }
+
+ /**
+ * Compares this range to the specified object. The result is `true`
+ * if and only if the argument is not `null` and is a
+ * `CellRangeRef` object that represents the same range as this
+ * object.
+ */
+ override fun equals(other: Any?): Boolean {
+ // if it's null or not a CellRangeRef it can't be equal
+ return if (other == null || other !is CellRangeRef) false else this.toString() == other.toString()
+
+ }
+
+ /**
+ * Creates and returns a copy of this range.
+ */
+ public override fun clone(): Any {
+ try {
+ return super.clone()
+ } catch (e: CloneNotSupportedException) {
+ // This can't happen (we're Cloneable) but we have to catch it
+ throw Error("Object.clone() threw CNSE but we're Cloneable")
+ }
+
+ }
+
+ /**
+ * Gets this range in A1 notation.
+ */
+ override fun toString(): String {
+ val sheet1 = firstSheetName
+ val sheet2 = lastSheetName
+ return (if (sheet1 != null) sheet1 + (if (sheet2 != null && sheet2 !== sheet1) ":$sheet2" else "") + "!" else "") + ExcelTools.formatRange(intArrayOf(firstColumn, firstRow, lastColumn, lastRow))
+ }
+
+ companion object {
+
+ /**
+ * Parses a range in A1 notation and returns the equivalent CellRangeRef.
+ */
+ fun fromA1(reference: String): CellRangeRef {
+ val ret = CellRangeRef()
+ var range: String?
+
+ run {
+ val parts = ExcelTools.stripSheetNameFromRange(reference)
+ ret.first_sheet_name = parts[0]
+ range = parts[1]
+ ret.last_sheet_name = parts[2]
+ }
+
+ if (range == null)
+ throw IllegalArgumentException("missing range component")
+
+ run {
+ val parts = ExcelTools.getRangeRowCol(range!!)
+ ret.firstRow = parts[0]
+ ret.firstColumn = parts[1]
+ ret.lastRow = parts[2]
+ ret.lastColumn = parts[3]
+ }
+
+ return ret
+ }
+
+ /**
+ * Convenience method combining [.fromA1] and
+ * [.resolve].
+ */
+ @Throws(WorkSheetNotFoundException::class)
+ fun fromA1(reference: String, book: WorkBookHandle): CellRangeRef {
+ val ret = fromA1(reference)
+ ret.resolve(book)
+ return ret
+ }
+ }
+}
diff --git a/src/main/java/io/starter/OpenXLS/ChartHandle.java b/src/main/java/io/starter/OpenXLS/ChartHandle.java
deleted file mode 100644
index e7d193a..0000000
--- a/src/main/java/io/starter/OpenXLS/ChartHandle.java
+++ /dev/null
@@ -1,3632 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Vector;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import io.starter.formats.OOXML.Layout;
-import io.starter.formats.OOXML.OOXMLConstants;
-import io.starter.formats.OOXML.SpPr;
-import io.starter.formats.OOXML.Title;
-import io.starter.formats.OOXML.TwoCellAnchor;
-import io.starter.formats.OOXML.TxPr;
-import io.starter.formats.XLS.Boundsheet;
-import io.starter.formats.XLS.CellNotFoundException;
-import io.starter.formats.XLS.Font;
-import io.starter.formats.XLS.FormatConstants;
-import io.starter.formats.XLS.OOXMLAdapter;
-import io.starter.formats.XLS.WorkSheetNotFoundException;
-import io.starter.formats.XLS.charts.Chart;
-import io.starter.formats.XLS.charts.ChartConstants;
-import io.starter.formats.XLS.charts.ChartType;
-import io.starter.formats.XLS.charts.OOXMLChart;
-import io.starter.formats.XLS.charts.Series;
-import io.starter.formats.XLS.charts.ThreeD;
-import io.starter.toolkit.Logger;
-
-/**
- * Chart Handle allows for manipulation of Charts within a WorkBook.
- * Allows for run-time modification of Chart titles, labels, categories, and
- * data Cells.
- * Modification of Chart data cells allows you to completely modify the data
- * shown on the Chart.
- *
- * To create a new chart and add to a worksheet, use:
- * ChartHandle.createNewChart(sheet, charttype, chartoptions).
- *
- * To Obtain an array of existing chart handles, use
- * WorkBookHandle.getCharts()
- * or WorkBookHandle.getCharts(chart title)
- *
- * Starter Inc.
- *
- * @see WorkBookHandle
- *
- */
-public class ChartHandle implements ChartConstants {
- // 20080114 KSC: delegate so visible
- public static final int BARCHART = ChartConstants.BARCHART;
- public static final int COLCHART = ChartConstants.COLCHART;
- public static final int LINECHART = ChartConstants.LINECHART;
- public static final int PIECHART = ChartConstants.PIECHART;
- public static final int AREACHART = ChartConstants.AREACHART;
- public static final int SCATTERCHART = ChartConstants.SCATTERCHART;
- public static final int RADARCHART = ChartConstants.RADARCHART;
- public static final int SURFACECHART = ChartConstants.SURFACECHART;
- public static final int DOUGHNUTCHART = ChartConstants.DOUGHNUTCHART;
- public static final int BUBBLECHART = ChartConstants.BUBBLECHART;
- public static final int OFPIECHART = ChartConstants.OFPIECHART;
- public static final int PYRAMIDCHART = ChartConstants.PYRAMIDCHART;
- public static final int CYLINDERCHART = ChartConstants.CYLINDERCHART;
- public static final int CONECHART = ChartConstants.CONECHART;
- public static final int PYRAMIDBARCHART = ChartConstants.PYRAMIDBARCHART;
- public static final int CYLINDERBARCHART = ChartConstants.CYLINDERBARCHART;
- public static final int CONEBARCHART = ChartConstants.CONEBARCHART;
- public static final int RADARAREACHART = ChartConstants.RADARAREACHART;
- public static final int STOCKCHART = ChartConstants.STOCKCHART;
-
- // legacy
- public static final int BAR = BARCHART;
- public static final int COL = COLCHART;
- public static final int LINE = LINECHART;
- public static final int PIE = PIECHART;
- public static final int AREA = AREACHART;
- public static final int SCATTER = SCATTERCHART;
- public static final int RADAR = RADARCHART;
- public static final int SURFACE = SURFACECHART;
- public static final int DOUGHNUT = DOUGHNUTCHART;
- public static final int BUBBLE = BUBBLECHART;
- public static final int RADARAREA = RADARAREACHART;
- public static final int PYRAMID = PYRAMIDCHART;
- public static final int CYLINDER = CYLINDERCHART;
- public static final int CONE = CONECHART;
- public static final int PYRAMIDBAR = PYRAMIDBARCHART;
- public static final int CYLINDERBAR = CYLINDERBARCHART;
- public static final int CONEBAR = CONEBARCHART;
- // axis types
- public static final int XAXIS = ChartConstants.XAXIS;
- public static final int YAXIS = ChartConstants.YAXIS;
- public static final int ZAXIS = ChartConstants.ZAXIS;
- public static final int XVALAXIS = ChartConstants.XVALAXIS; // an X axis type but VAL records
- // coordinates
- public static final int X = 0;
- public static final int Y = 1;
- public static final int WIDTH = 2;
- public static final int HEIGHT = 3;
-
- protected WorkBookHandle wbh;
- private Chart mychart;
-
- /**
- * Constructor which creates a new ChartHandle from an existing Chart Object
- *
- * @param Chart
- * c - the source Chart object
- * @param WorkBookHandle
- * wb - the parent WorkBookHandle
- */
- public ChartHandle(Chart c, WorkBookHandle wb) {
- // super();
- mychart = c;
- wbh = wb;
- if (mychart.getWorkBook() == null) // TODO: WHY IS THIS NULL????
- mychart.setWorkBook(wb.getWorkBook());
- }
-
- /**
- * Returns the title of the Chart
- *
- * @return String title of the Chart
- */
- public String getTitle() {
- return mychart.getTitle();
- }
-
- /**
- * Sets the title of the Chart
- *
- * @param String
- * title - Chart title
- */
- public void setTitle(String title) {
- this.mychart.setTitle(title);
- }
-
- /**
- * returns the data range used by the chart
- *
- * @return
- */
- public String getDataRangeJSON() {
- return this.mychart.getChartSeries().getDataRangeJSON().toString();
- }
-
- public int[] getEncompassingDataRange() {
- return getEncompassingDataRange(this.mychart.getChartSeries().getDataRangeJSON());
- }
-
- /**
- * returns the encompassing range for this chart, or null if the chart data is
- * too complex to represent
- *
- * @param jsonDataRange
- * @return
- */
- public static int[] getEncompassingDataRange(JSONObject jsonDataRange) {
- try {
- String catrange = jsonDataRange.get("c").toString();
- String sheet = catrange.substring(0, catrange.indexOf('!'));
- int[] retVals = ExcelTools.getRangeRowCol(catrange);
- int nSeries = jsonDataRange.getJSONArray("Series").length();
- for (int i = 0; i < nSeries; i++) {
- JSONObject series = (JSONObject) jsonDataRange.getJSONArray("Series").get(i);
- String serrange = series.get("v").toString();
- if (!serrange.startsWith(sheet))
- continue;
- int[] locs = ExcelTools.getRangeRowCol(serrange);
- try {
- if (locs[0] < retVals[0])
- retVals[0] = locs[0];
- if (locs[1] < retVals[1])
- retVals[1] = locs[1];
- if (locs[2] > retVals[2])
- retVals[2] = locs[2];
- if (locs[3] > retVals[3])
- retVals[3] = locs[3];
-
- String legendrange = series.get("l").toString();
- locs = ExcelTools.getRowColFromString(legendrange);
- if (locs[0] < retVals[0])
- retVals[0] = locs[0];
- if (locs[1] < retVals[1])
- retVals[1] = locs[1];
- if (locs[0] > retVals[2])
- retVals[2] = locs[0];
- if (locs[1] > retVals[3])
- retVals[3] = locs[1];
-
- if (series.has("b")) {
- String bubblerange = series.get("b").toString();
- locs = ExcelTools.getRangeRowCol(serrange);
- if (locs[0] < retVals[0])
- retVals[0] = locs[0];
- if (locs[1] < retVals[1])
- retVals[1] = locs[1];
- if (locs[2] > retVals[2])
- retVals[2] = locs[2];
- if (locs[3] > retVals[3])
- retVals[3] = locs[3];
- }
- } catch (Exception e) {
- // just continue
- }
- }
- return retVals;
- } catch (Exception e) {
- }
- return null;
- /*
- * while (ptgs.hasNext()) { PtgRef pr= (PtgRef) ptgs.next(); // PtgRef pr=
- * (PtgRef)refs[i]; int[] locs = pr.getIntLocation(); for (int x=0;x<2;x++) {
- * if((locs[x]retValues[x]))retValues[x]=locs[x]; } i++; }
- */
- }
-
- /**
- * returns the ordinal id associated with the underlying Chart Object
- *
- * @return int chart id
- * @see WorkBookHandle.getChartById
- */
- public int getId() {
- return this.mychart.getId();
- }
-
- /**
- * returns the string representation of this ChartHandle
- */
- @Override
- public String toString() {
- return mychart.getTitle();
- }
-
- /***************************************************************************************************************************************/
- /**
- * Returns an ordered array of strings representing all the series ranges in the
- * Chart.
- * Each series can only represent one bar, line or wedge of data.
- *
- * @see ChartHandle.getCategories
- * @return String[] each item being a Cell Range representing one bar, line or
- * wedge of data in the Chart
- */
- public String[] getSeries() {
- return mychart.getSeries(-1); // -1 is flag for all rather than for a specific chart
- }
-
- /**
- * Returns an ordered array of strings representing all the category ranges in
- * the chart.
- * This vector corresponds to the getSeries() method so will often contain
- * duplicates, as while the series data changes frequently, category data is the
- * same throughout the chart.
- *
- * @see ChartHandle.getSeries
- * @return String[] each item being a Cell Range representing the Category Data
- */
- public String[] getCategories() {
- return getCategories(-1); // -1 is flag for all rather than for a specific chart
- }
-
- /**
- * Returns an ordered array of strings representing all the category ranges in
- * the chart.
- * This vector corresponds to the getSeries() method so will often contain
- * duplicates, as while the series data changes frequently, category data is the
- * same throughout the chart.
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @see ChartHandle.getSeries
- * @return String[] each item being a Cell Range representing the Category Data
- */
- private String[] getCategories(int nChart) {
- return mychart.getCategories(nChart);
- }
-
- /**
- * Returns an array of ChartSeriesHandle Objects, one for each bar, line or
- * wedge of data.
- *
- * @return ChartSeriesHandle[] Array of ChartSeriesHandle Objects representing
- * Chart Series Data (Series and Categories)
- * @see ChartSeriesHandle
- */
- public ChartSeriesHandle[] getAllChartSeriesHandles() {
- return getAllChartSeriesHandles(-1); // get ALL
- }
-
- /**
- * Returns an array of ChartSeriesHandle Objects for the desired chart, one for
- * each bar, line or wedge of data.
- * A chart number of 0 means the default chart, 1-9 indicate series for overlay
- * charts
- * NOTE: using this method returns the series for the desired chart ONLY
- * You MUST use the corresponding removeSeries(index, nChart) when removing
- * series to properly match the series index. Otherwise a mismatch will occur.
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return ChartSeriesHandle[] Array of ChartSeriesHandle Objects representing
- * Chart Series Data (Series and Categories)
- * @see ChartSeriesHandle
- */
- public ChartSeriesHandle[] getAllChartSeriesHandles(int nChart) {
- Vector> v = mychart.getAllSeries(nChart);
- ChartSeriesHandle[] csh = new ChartSeriesHandle[v.size()];
- for (int i = 0; i < v.size(); i++) {
- Series s = (Series) v.get(i);
- csh[i] = new ChartSeriesHandle(s, this.wbh);
- }
- return csh;
- }
-
- /**
- * Get the ChartSeriesHandle representing Chart Series Data (Series and
- * Categories) for the specified Series range
- *
- * @param String
- * seriesRange - For example, "Sheet1!A12:A21"
- * @return ChartSeriesHandle
- * @see ChartSeriesHandle
- */
- public ChartSeriesHandle getChartSeriesHandle(String seriesRange) {
- ChartSeriesHandle[] series = this.getAllChartSeriesHandles();
- for (int i = 0; i < series.length; i++) {
- String sr = series[i].getSeriesRange();
- if (seriesRange.equalsIgnoreCase(sr)) {
- return series[i];
- }
- }
- return null;
- }
-
- /**
- * Get the ChartSeriesHandle representing Chart Series Data (Series and
- * Categories) for the specified Series index
- *
- * @param int
- * idx - the index (0 based) of the series
- * @see ChartSeriesHandle
- * @return ChartSeriesHandle
- */
- public ChartSeriesHandle getChartSeriesHandle(int idx) {
- ChartSeriesHandle[] series = this.getAllChartSeriesHandles();
- if (series.length >= idx)
- return series[idx];
- return null;
- }
-
- /**
- * Get the ChartSeriesHandle representing Chart Series Data (Series and
- * Categories) for the Series specified by label (legend)
- *
- * @param String
- * legend - label for the desired series
- * @return ChartSeriesHandle
- * @see ChartSeriesHandle
- */
- public ChartSeriesHandle getChartSeriesHandleByName(String legend) {
- Series s = mychart.getSeries(legend, -1); // -1 is flag for all rather than for a specific chart
- return new ChartSeriesHandle(s, this.wbh);
- }
-
- /**
- * sets or removes the axis title
- *
- * @param axisType
- * one of: XAXIS, YAXIS, ZAXIS
- * @param ttl
- * String new title or null to remove
- */
- public void setAxisTitle(int axisType, String ttl) {
- mychart.getAxes().setTitle(axisType, ttl);
- }
-
- /**
- * returns the Y axis Title
- *
- * @return String title
- */
- public String getYAxisLabel() {
- return mychart.getAxes().getTitle(YAXIS);
- }
-
- /**
- * Sets the Y axis Title
- *
- * @param String
- * yTitle - new Y Axis title
- */
- public void setYAxisLabel(String yTitle) {
- mychart.getAxes().setTitle(YAXIS, yTitle);
- }
-
- /**
- * returns the X axis Title
- *
- * @return String title
- */
- public String getXAxisLabel() {
- return mychart.getAxes().getTitle(XAXIS);
- }
-
- /**
- * Sets the XAxisTitle
- *
- * @param String
- * xTitle - new X Axis title
- */
- public void setXAxisLabel(String xTitle) {
- mychart.getAxes().setTitle(XAXIS, xTitle);
- }
-
- /**
- * returns the Z axis Title, if any
- *
- * @return String Title
- */
- public String getZAxisLabel() {
- return mychart.getAxes().getTitle(ZAXIS);
- }
-
- /**
- * set the Z AxisTitle
- *
- * @param String
- * zTitle - new Z Axis Title
- */
- public void setZAxisLabel(String zTitle) {
- mychart.getAxes().setTitle(ZAXIS, zTitle);
- }
-
- /**
- * Sets the automatic scale option on or off for the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * Automatic Scaling automatically sets the scale maximum, minimum and tick
- * units upon data changes, and is the default setting for charts
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @param boolean
- * b - true if set Automatic scaling on, false otherwise
- * @see setAxisAutomaticScale(boolean b)
- */
- public void setAxisAutomaticScale(int axisType, boolean b) {
- mychart.getAxes().setAxisAutomaticScale(axisType, b);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * Returns the minimum scale value of the the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @return int Miminum Scale value for the desired axis
- * @see getAxisMinScale()
- */
- public double getAxisMinScale(int axisType) {
- double[] minmax = mychart.getMinMax(this.wbh);
- return mychart.getAxes().getMinMax(minmax[0], minmax[1], axisType)[0];
- }
-
- /**
- * Returns the maximum scale value of the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @return int - Maximum Scale value for the desired axis
- * @see getAxisMaxScale()
- */
- public double getAxisMaxScale(int axisType) {
- double[] minmax = mychart.getMinMax(this.wbh); // -1 is flag for all rather than for a specific chart
- return mychart.getAxes().getMinMax(minmax[0], minmax[1], axisType)[1];
- }
-
- /**
- * Returns the major tick unit of the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @return int major tick unit
- * @see getAxisMajorUnit()
- */
- public int getAxisMajorUnit(int axisType) {
- return mychart.getAxes().getAxisMajorUnit(axisType);
- }
-
- /**
- * Returns the minor tick unit of the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @return int - minor tick unit of the desired axis
- * @see getAxisMinorUnit()
- */
- public int getAxisMinorUnit(int axisType) {
- return mychart.getAxes().getAxisMinorUnit(axisType);
- }
-
- /**
- * Sets the maximum scale value of the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * Note: The default scale setting for charts is known as Automatic Scaling
- * When data changes, the chart automatically adjusts the scale as necessary
- *
- * Setting the scale manually (either Minimum or Maximum Value) removes
- * Automatic Scaling
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @param int
- * MaxValue - desired maximum value of the desired axis
- * @see setAxisMax(int MaxValue)
- */
- public void setAxisMax(int axisType, int MaxValue) {
- mychart.getAxes().setAxisMax(axisType, MaxValue);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * Sets the minimum scale value of the desired Value axis
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * Note: The default setting for charts is known as Automatic Scaling
- * When data values change, the chart automatically adjusts the scale as
- * necessary
- * Setting the scale manually (either Minimum or Maximum Value) removes
- * Automatic Scaling
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @param int
- * MinValue - the desired Minimum scale value
- * @see setAxisMin(int MinValue)
- */
- public void setAxisMin(int axisType, int MinValue) {
- mychart.getAxes().setAxisMin(axisType, MinValue);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * Returns true if the desired Value axis is set to automatic scale
- *
- * The Value axis contains numbers rather than labels, and is normally the Y
- * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
- * well
- *
- * Note: The default setting for charts is known as Automatic Scaling
- * When data changes, the chart automatically adjusts the scale as necessary
- *
- * Setting the scale manually (either Minimum or Maximum Value) removes
- * Automatic Scaling
- *
- * @param int
- * axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
- * ChartHandle.ZAXIS
- * @return boolean true if Automatic Scaling is turned on
- * @see getAxisAutomaticScale()
- */
- public boolean getAxisAutomaticScale(int axisType) {
- return mychart.getAxes().getAxisAutomaticScale(axisType);
- }
-
- /**
- * Returns true if the Y Axis (Value axis) is set to automatic scale
- *
- * The default setting for charts is known as Automatic Scaling
- * When data changes, the chart automatically adjusts the scale (minimum,
- * maximum values plus major and minor tick units) as necessary
- *
- * @return boolean true if Automatic Scaling is turned on
- * @see getAxisAutomaticScale(int axisType)
- */
- public boolean getAxisAutomaticScale() {
- return mychart.getAxisAutomaticScale();
- }
-
- /**
- * Sets the automatic scale option on or off for the Y Axis (Value axis)
- *
- * Automatic Scaling will automatically set the scale maximum, minimum and tick
- * units upon data changes, and is the default chart setting
- *
- * @param b
- * @see setAxisAutomaticScale(int axisType boolean b)
- */
- public void setAxisAutomaticScale(boolean b) {
- mychart.getAxes().setAxisAutomaticScale(b);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * Returns the minimum value of the Y Axis (Value Axis) scale
- *
- * @return int Miminum Scale value for Y axis
- * @see getAxisMinScale(int axisType)
- */
- public double getAxisMinScale() {
- double[] minmax = mychart.getMinMax(this.wbh); // -1 is flag for all rather than for a specific chart
- return mychart.getAxes().getMinMax(minmax[0], minmax[1])[0];
- }
-
- /**
- * Returns the maximum value of the Y Axis (Value Axis) scale
- *
- * @return int Maximum Scale value for Y axis
- * @see getAxisMaxScale(int axisType)
- */
- public double getAxisMaxScale() {
- double[] minmax = mychart.getMinMax(this.wbh);
- return mychart.getAxes().getMinMax(minmax[0], minmax[1])[1];
- }
-
- /**
- * Returns the major tick unit of the Y Axis (Value Axis)
- *
- * @return int major tick unit
- * @see getAxisMajorUnit(int axisType)
- */
- public int getAxisMajorUnit() {
- double[] minmax = mychart.getMinMax(this.wbh);
- return (int) mychart.getAxes().getMinMax(minmax[0], minmax[1])[2];
- }
-
- /**
- * Returns the minor tick unit of the Y Axis (Value Axis)
- *
- * @return int minor tick unit
- * @see getAxisMinorUnit(int axisType)
- */
- public int getAxisMinorUnit() {
- double[] minmax = mychart.getMinMax(this.wbh);
- return (int) mychart.getAxes().getMinMax(minmax[0], minmax[1])[1];
- }
-
- /**
- * Sets the maximum value of the Y Axis (Value Axis) Scale
- *
- * Note: The default scale setting for charts is known as Automatic Scaling
- * When data changes, the chart automatically adjusts the scale as necessary
- *
- * Setting the scale manually (either Minimum or Maximum Value) removes
- * Automatic Scaling
- *
- * @param int
- * MaxValue - the desired maximum scale value
- * @see ChartHandle.setAxisMax(int axisType, int MaxValue)
- */
- public void setAxisMax(int MaxValue) {
- mychart.getAxes().setAxisMax(MaxValue);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * Sets the minimum value of the Y Axis (Value Axis) Scale
- *
- * Note: The default setting for charts is known as Automatic Scaling
- * When data changes, the chart automatically adjusts the scale as necessary
- *
- * Setting the scale manually (either Minimum or Maximum Value) removes
- * Automatic Scaling
- *
- * @param int
- * MinValue - the desired minimum scale value
- * @see ChartHandle.setAxisMin(int axisType, int MinValue)
- */
- public void setAxisMin(int MinValue) {
- mychart.getAxes().setAxisMin(MinValue);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * sets an option for this axis
- *
- * @param axisType
- * one of: XAXIS, YAXIS, ZAXIS
- * @param op
- * option name; one of: CatCross, LabelCross, Marks, CrossBetween,
- * CrossMax, MajorGridLines, AddArea, AreaFg, AreaBg or Linked Text
- * Display options: Label, ShowKey, ShowValue, ShowLabelPct, ShowPct,
- * ShowCatLabel, ShowBubbleSizes, TextRotation, Font
- * @param val
- * option value
- */
- public void setAxisOption(int axisType, String op, String val) {
- mychart.getAxes().setChartOption(axisType, op, val);
-
- }
-
- /**
- * set the font for the chart title
- *
- * @param String
- * name - font name
- * @param int
- * height - font height in 1/20 point units
- * @param boolean
- * bold - true if bold
- * @param boolean
- * italic - true if italic
- * @param boolean
- * underline - true if underlined
- */
- public void setTitleFont(String name, int height, boolean bold, boolean italic, boolean underline) {
- Font f = new Font(name, 200, height);
- f.setBold(bold);
- f.setItalic(italic);
- f.setUnderlined(underline);
- int idx = wbh.getWorkBook().getFontIdx(f);
- if (idx == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- idx = wbh.getWorkBook().insertFont(f) + 1;
- }
- mychart.setTitleFont(idx);
- }
-
- /**
- * set the font for the Chart Title
- *
- * @param io.starter.Formats.XLS.Font
- * f - desired font for the Chart Title
- * @see Font
- */
- public void setTitleFont(Font f) {
- int idx = wbh.getWorkBook().getFontIdx(f);
- if (idx == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- idx = wbh.getWorkBook().insertFont(f) + 1;
- }
- mychart.setTitleFont(idx);
- }
-
- /**
- * returns the Font associated with the Chart Title
- *
- * @return io.starter.Formats.XLS.Font
- * @see Font
- */
- public Font getTitleFont() {
- return mychart.getTitleFont();
- }
-
- /**
- * set the font for all axes on the chart
- *
- * @param String
- * name - font name
- * @param int
- * height - font height in 1/20 point units
- * @param boolean
- * bold - true if bold
- * @param boolean
- * italic - true if italic
- * @param boolean
- * underline - true if underlined
- */
- public void setAxisFont(String name, int height, boolean bold, boolean italic, boolean underline) {
- Font f = new Font(name, 200, height);
- f.setBold(bold);
- f.setItalic(italic);
- f.setUnderlined(underline);
- int idx = wbh.getWorkBook().getFontIdx(f);
- if (idx == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- idx = wbh.getWorkBook().insertFont(f) + 1;
- }
- mychart.getAxes().setTitleFont(XAXIS, idx);
- mychart.getAxes().setTitleFont(YAXIS, idx);
- mychart.getAxes().setTitleFont(ZAXIS, idx);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * set the font for all axes on the Chart
- *
- * @param io.starter.Formats.XLS.Font
- * f - desired font for the Chart axes
- * @see Font
- */
- public void setAxisFont(Font f) {
- int idx = wbh.getWorkBook().getFontIdx(f);
- if (idx == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- idx = wbh.getWorkBook().insertFont(f) + 1;
- }
- mychart.getAxes().setTitleFont(XAXIS, idx);
- mychart.getAxes().setTitleFont(YAXIS, idx);
- mychart.getAxes().setTitleFont(ZAXIS, idx);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * return the Font associated with the Chart Axes
- *
- * @return io.starter.Formats.XLS.Font for Chart Axes or null if no axes
- * @see Font
- */
- public Font getAxisFont() {
- Font f = null;
- f = mychart.getAxes().getTitleFont(XAXIS);
- if (f != null)
- return f;
- f = mychart.getAxes().getTitleFont(YAXIS);
- if (f != null)
- return f;
- f = mychart.getAxes().getTitleFont(ZAXIS);
- if (f != null)
- return f;
- return null;
- }
-
- /**
- * resets all fonts in the chart to the default font of the workbook
- */
- public void resetFonts() {
- mychart.resetFonts();
- }
-
- /**
- * returns the underlhying Sheet Object this Chart is attached to
- * For Internal Use
- *
- * @return Boundsheet
- */
- public Boundsheet getSheet() {
- return mychart.getSheet();
- }
-
- /**
- * return the background color of this chart's Plot Area as an int
- *
- * @return int background color constant
- * @see FormatHandle.COLOR_* constants
- */
- public int getPlotAreaBgColor() {
- String bg = mychart.getPlotAreaBgColor();
- return FormatHandle.HexStringToColorInt(bg, (short) 0);
- }
-
- public String getPlotAreaBgColorStr() {
- return mychart.getPlotAreaBgColor();
- }
-
- /**
- * sets the Plot Area background color
- *
- * @param int
- * bg - color constant
- * @see FormatHandle.COLOR_* constants
- */
- public void setPlotAreaBgColor(int bg) {
- mychart.setPlotAreaBgColor(bg);
- }
-
- /**
- * Change the value of a Chart object.
- * NOTE: THIS HAS NOT BEEN 100% IMPLEMENTED YET
- * You can use this method to change:
- *
- *
- * - the Title of the Chart
- * - the Text Labels of Categories and Values (X and Y)
- *
- *
- * eg:
- *
- *
- * To change the value of the Chart title
- * chart.changeObjectValue("Template Chart Title", "Widget Sales By Quarter");
- *
- *
- * To change the text label of the categories
- * chart.changeObjectValue("Category X", "Fiscal Year");
- *
- *
- * To change the text label of the values
- * chart.changeObjectValue("Value Y", "Sales in US$");
- *
- * @param String
- * originalval - One of: "Template Chart Title", "Category X" or
- * "Value Y"
- * @param Sring
- * newval - the new setting
- * @return whether the change was successful
- *
- */
- public boolean changeTextValue(String originalval, String newval) {
- /*
- * KSC: TODO: Refactor *** for(int x=0;x
- * To see possible Chart Types, view the public static int's in ChartHandle.
- *
- * Possible Chart Types:
- * BARCHART
- * COLCHART
- * LINECHART
- * PIECHART
- * AREACHART
- * SCATTERCHART
- * RADARCHART
- * SURFACECHART
- * DOUGHNUTCHART
- * BUBBLECHART
- * RADARAREACHART
- * PYRAMIDCHART
- * CYLINDERCHART
- * CONECHART
- * PYRAMIDBARCHART
- * CYLINDERBARCHART
- * CONEBAR
- *
- * @param int
- * chartType - representing the chart type
- */
- public void setChartType(int chartType) {
- mychart.setChartType(chartType, 0, EnumSet.noneOf(ChartOptions.class)); // no specific options
- }
-
- /**
- * Chart Options. CLUSTERED, bar, col charts only STACKED, PERCENTSTACKED, 100%
- * stacked THREED, 3d Effect EXPLODED, Pie, Donut HASLINES, Scatter, Line charts
- * ... WIREFRAME, Surface DROPLINES, DOWNBARS, line, stock UPDOWNBARS, line,
- * stock SERLINES, bar, ofpie
- * Use these chart options when creating new charts
- * A chart may have multiple chart options e.g. 3D Exploded pie chart
- *
- * @see ChartHandle.createNewChart
- */
- // need: hasMarkers ****
- public enum ChartOptions {
- CLUSTERED,
- /** bar, col charts only */
- STACKED, PERCENTSTACKED,
- /** 100% stacked */
- THREED,
- /** 3d Effect */
- EXPLODED,
- /** Pie, Donut */
- HASLINES,
- /** Scatter, Line */
- SMOOTHLINES,
- /** Scatter, Line, Radar */
- WIREFRAME,
- /** Surface */
- DROPLINES,
- /** line, area, stock charts */
- UPDOWNBARS,
- /** line, stock */
- SERLINES,
- /** bar, ofpie */
- HILOWLINES,
- /** line, stock charts */
- FILLED /** radar */
- }
-
- /**
- * Static method to create a new chart on WorkSheet sheet of type chartType with
- * chart Options options
- * After creating, you can set the chart title via ChartHandle.setTitle
- * and Position via ChartHandle.setRelativeBounds (row/col-based) or
- * ChartHandle.setCoords (pixel-based)
- * as well as several other customizations possible
- *
- * @param book
- * WorkBookHandle
- * @param sheet
- * WorkSheetHandle
- * @param chartType
- * one of:
- * BARCHART
- * COLCHART
- * LINECHART
- * PIECHART
- * AREACHART
- * SCATTERCHART
- * RADARCHART
- * SURFACECHART
- * DOUGHNUTCHART
- * BUBBLECHART
- * RADARAREACHART
- * PYRAMIDCHART
- * CYLINDERCHART
- * CONECHART
- * PYRAMIDBARCHART
- * CYLINDERBARCHART
- * CONEBARCHART
- * @param options
- * EnumSet
- * @see ChartHandle.ChartOptions
- * @see setChartType
- * @return
- */
- public static ChartHandle createNewChart(WorkSheetHandle sheet, int chartType, EnumSet options) {
- // Create Initial Basic Chart
- ChartHandle cht = sheet.getWorkBook().createChart("", sheet);
- // Change Chart Type with Desired Options:
- cht.setChartType(chartType, 0, options);
- return cht;
- }
-
- /**
- * Sets the Chart type to the specified type (no 3d, no stacked ...)
- * To see possible Chart Types, view the public static int's in ChartHandle.
- *
- * Possible Chart Types:
- * BARCHART
- * COLCHART
- * LINECHART
- * PIECHART
- * AREACHART
- * SCATTERCHART
- * RADARCHART
- * SURFACECHART
- * DOUGHNUTCHART
- * BUBBLECHART
- * RADARAREACHART
- * PYRAMIDCHART
- * CYLINDERCHART
- * CONECHART
- * PYRAMIDBARCHART
- * CYLINDERBARCHART
- * CONEBARCHART
- *
- * @param int
- * chartType - representing the chart type
- * @param nChart
- * - 0 (default) or 1-9 for complex overlay charts
- * @param EnumSet
- * 0 or more chart options (Such as Stacked, Exploded ...)
- * @see ChartHandle.ChartOptions
- */
- public void setChartType(int chartType, int nChart, EnumSet options) {
- mychart.setChartType(chartType, nChart, options);
- }
-
- /**
- * Sets the basic chart type (no 3d, stacked...) for multiple or overlay Charts.
- *
- * You can specify the drawing order of the Chart, where 0 is the default chart,
- * and 1-9 are overlay charts.
- * The default chart (chart 0) is always present; however, using this method,
- * you can create a new overlay chart (up to 9 maximum).
- * NOTE: The chart number must be unique and in order
- * If the desired chart number is not present in the chart, a new overlay chart
- * will be created.
- * To set explicit chart options, @see setChartType(chartType, nChart, is3d,
- * isStacked, is100PercentStacked)
- *
- * To see possible Chart Types, view the public static int's in ChartHandle.
- *
- * Possible Chart Types:
- * BARCHART
- * COLCHART
- * LINECHART
- * PIECHART
- * AREACHART
- * SCATTERCHART
- * RADARCHART
- * SURFACECHART
- * DOUGHNUTCHART
- * BUBBLECHART
- * RADARAREACHART
- * PYRAMIDCHART
- * CYLINDERCHART
- * CONECHART
- * PYRAMIDBARCHART
- * CYLINDERBARCHART
- * CONEBARCHART
- *
- * @param int
- * chartType - representing the chart type
- * @param chartType
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- */
- public void setChartType(int chartType, int nChart) {
- mychart.setChartType(chartType, nChart, EnumSet.noneOf(ChartOptions.class)); // no specific options
- }
-
- /**
- * Return an int corresponding to this ChartHandle's Chart Type for the default
- * chart
- * To see possible Chart Types, view the public static int's in ChartHandle.
- *
- * @see ChartHandle static Chart Type Constants
- * @see ChartHandle.setChartType
- * @return int chart type
- *
- */
- public int getChartType() {
- return mychart.getChartType();
- }
-
- /**
- * Return an int corresponding to this ChartHandle's Chart Type for the
- * specified chart
- * To see possible Chart Types, view the public static int's in ChartHandle.
- *
- * @see ChartHandle static Chart Type Constants
- * @see ChartHandle.setChartType
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return int chart type
- */
- public int getChartType(int nChart) {
- return mychart.getChartType(nChart);
- }
-
- /**
- * Sets the location lock on the Cell Reference at the specified location
- *
- * Used to prevent updating of the Cell Reference when Cells are moved.
- *
- * @param location
- * of the Cell Reference to be locked/unlocked
- * @param lock
- * status setting
- * @return boolean whether the Cell Reference was found and modified
- */
- /*
- * TODO: NEEDED?? public boolean setLocationLocked(String loc, boolean l){ int x
- * = Ptg.PTG_LOCATION_POLICY_UNLOCKED; if(l)x = Ptg.PTG_LOCATION_POLICY_LOCKED;
- * return setLocationPolicy(loc, x); }
- */
-
- /**
- * Change the Cell Range referenced by one of the Series (a bar, line or wedge
- * of data) in the Chart.
- *
- * For Example, if the data values for one of the Series in the Chart are
- * obtained from the range Sheet1!A1:A10 and we want to add 5 more values to
- * that Series, use:
- *
- *
- * boolean changedOK =
- * charthandle.changeSeriesRange("Sheet1!A1:A10","Sheet1!A1:A15");
- *
- * Please keep in mind this is only the data range; it does not include labels
- * that may have been automatically created when you chose the chart range.
- *
- * To illustrate this, if A1 = "label" A2 = "data" A3 = "data", and we want to
- * add 2 more data points, we would use: changeSeriesRange("Sheet1!A2:A3",
- * "Sheet1!A2:A5");
- *
- * Series are always expressed as one single line of data. If your chart
- * encompasses a range of rows and columns you will need to modify each of the
- * series in the chart handle. To determine the series that already exist in
- * your chart, utilize the String[] getSeries() method.
- *
- * @param String
- * originalrange - the original Series (bar, line or wedge of data)
- * to alter
- * @param String
- * newrange -the new data range
- * @return whether the change was successful
- */
- public boolean changeSeriesRange(String originalrange, String newrange) {
- return mychart.changeSeriesRange(originalrange, newrange);
- }
-
- /**
- * Change the Cell Range representing the Categories in the Chart.
- * Categories usually appear on the X Axis and are textual, not numeric
- * For example: the Category values in the Chart are obtained from the range
- * Sheet1!A1:A10 and we want to add 5 more categories to the chart:
- * boolean changedOK =
- * chart.changeCategoryRange("Sheet1!A1:A10","Sheet1!A1:A15");
- * Note that Category Range is the same for each Series (bar, line or wedge of
- * data)
- * i.e. there is only one Category Range for the Chart, but there may be many
- * Series Ranges
- *
- * @param String
- * originalrange - Original Category Range
- * @param String
- * newrange - New Category Range
- * @return true if the change was successful
- */
- public boolean changeCategoryRange(String originalrange, String newrange) {
- return mychart.changeCategoryRange(originalrange, newrange);
- }
-
- /**
- * Changes or adds a Series to the chart via Series Index. Each bar, line or
- * wedge in a chart represents a Series.
- * If the Series index is greater than the number of series already present in
- * the chart, the series will be added to the end.
- * Otherwise the Series at the index position will be altered.
- * This method allows altering of every aspect of the Series: Data (Series)
- * Range, Legend Cell Address, Category Range and/or Bubble Range.
- *
- * @param int
- * index - the series index. If greater than the number of series
- * already present in the chart, the series will be added to the end
- * @param String
- * legendCell - String representation of Legend Cell Address
- * @param String
- * categoryRange - String representation of Category Range (should be
- * same for all series)
- * @param String
- * seriesRange - String representation of the Series Data Range for
- * this series
- * @param String
- * bubbleRange - String representation of Bubble Range (representing
- * bubble sizes), if bubble chart. null if not
- * @return a ChartSeriesHandle representing the new or altered Series
- * @throws CellNotFoundException
- */
- public ChartSeriesHandle setSeries(int index, String legendCell, String categoryRange, String seriesRange,
- String bubbleRange) throws CellNotFoundException {
- String legendText = "";
- try {
- CellHandle ICell = null;
- if (legendCell != null && !legendCell.equals("")) {
- // 20070707 KSC: allow addition of new cell ranges for legendCell (see
- // OpenXLS.handleChartElement)
- try {
- ICell = wbh.getCell(legendCell);
- } catch (CellNotFoundException c) {
- int shtpos = legendCell.indexOf("!");
- if (shtpos > 0) {
- String sheetstr = legendCell.substring(0, shtpos);
- WorkSheetHandle sht = wbh.getWorkSheet(sheetstr);
- String celstr = legendCell.substring(shtpos + 1);
- ICell = sht.add("", celstr);
- }
- }
- legendText = ICell.getStringVal();
- }
- return setSeries(index, legendCell, legendText, categoryRange, seriesRange, bubbleRange);
- } catch (WorkSheetNotFoundException e) {
- throw new CellNotFoundException("Error locating cell for adding series range: " + legendCell);
- }
- }
-
- /**
- * Changes or adds a Series to the chart via Series Index. Each bar, line or
- * wedge in a chart represents a Series.
- * If the Series index is greater than the number of series already present in
- * the chart, the series will be added to the end.
- * Otherwise the Series at the index position will be altered.
- * This method allows altering of every aspect of the Series: Data (Series)
- * Range, Legend Text, Legend Cell Address, Category Range and/or Bubble Range.
- *
- * @param int
- * index - the series index. If greater than the number of series
- * already present in the chart, the series will be added to the end
- * @param String
- * legendCell - String representation of Legend Cell Address
- * @param String
- * legendText - String Legend text
- * @param String
- * categoryRange - String representation of Category Range (should be
- * same for all series)
- * @param String
- * seriesRange - String representation of the Series Data Range for
- * this series
- * @param String
- * bubbleRange - String representation of Bubble Range (representing
- * bubble sizes), if bubble chart. null if not
- * @return a ChartSeriesHandle representing the new or altered Series
- * @throws CellNotFoundException
- */
- public ChartSeriesHandle setSeries(int index, String legendCell, String legendText, String categoryRange,
- String seriesRange, String bubbleRange) throws CellNotFoundException {
- return setSeries(index, legendCell, legendText, categoryRange, seriesRange, bubbleRange, 0); // for default
- // chart
- }
-
- /**
- * Changes or adds a Series to the desired Chart (either default or overlay) via
- * Series Index. Each bar, line or wedge in a chart represents a Series.
- * If the Series index is greater than the number of series already present in
- * the chart, the series will be added to the end.
- * Otherwise the Series at the index position will be altered.
- * This method allows altering of every aspect of the Series: Data (Series)
- * Range, Legend Text, Legend Cell Address, Category Range and/or Bubble Range.
- *
- * @param int
- * index - the series index. If greater than the number of series
- * already present in the chart, the series will be added to the end
- * @param String
- * legendCell - String representation of Legend Cell Address
- * @param String
- * legendText - String Legend text
- * @param String
- * categoryRange - String representation of Category Range (should be
- * same for all series)
- * @param String
- * seriesRange - String representation of the Series Data Range for
- * this series
- * @param String
- * bubbleRange - String representation of Bubble Range (representing
- * bubble sizes), if bubble chart. null if not
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return a ChartSeriesHandle representing the new or altered Series
- * @throws CellNotFoundException
- */
- public ChartSeriesHandle setSeries(int index, String legendCell, String legendText, String categoryRange,
- String seriesRange, String bubbleRange, int nChart) throws CellNotFoundException {
- // if (index < mychart.getAllSeries(nChart).size() && index >= 0) {
- try {
- Series s = (Series) mychart.getAllSeries(nChart).get(index);
- ChartSeriesHandle csh = new ChartSeriesHandle(s, this.wbh);
- csh.setSeries(legendCell, categoryRange, seriesRange, bubbleRange);
- setDimensionsRecord();
- return csh;
- } catch (ArrayIndexOutOfBoundsException ae) { // not found - add
- return addSeriesRange(legendCell, legendText, categoryRange, seriesRange, bubbleRange, nChart);
- }
- }
-
- /**
- * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
- * a Series.
- *
- * @param String
- * legendAddress - The cell address defining the legend for the
- * series
- * @param Srring
- * legendText - Text of the legend
- * @param String
- * categoryRange - Cell Range defining the category (normally will be
- * the same range for all series)
- * @param String
- * seriesRange - Cell range defining the data points of the series
- * @param String
- * bubbleRange - Cell range defining the bubble sizes for this series
- * (bubble charts only)
- * @return ChartSeriesHandle representing the new series
- * @throws CellNotFoundException
- */
- private ChartSeriesHandle addSeriesRange(String legendAddress, String legendText, String categoryRange,
- String seriesRange, String bubbleRange) throws CellNotFoundException {
- return addSeriesRange(legendAddress, legendText, categoryRange, seriesRange, bubbleRange, 0); // for default
- // chart
- }
-
- /**
- * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
- * a Series.
- *
- * @param String
- * legendAddress - The cell address defining the legend for the
- * series
- * @param Srring
- * legendText - Text of the legend
- * @param String
- * categoryRange - Cell Range defining the category (normally will be
- * the same range for all series)
- * @param String
- * seriesRange - Cell range defining the data points of the series
- * @param String
- * bubbleRange - Cell range defining the bubble sizes for this series
- * (bubble charts only)
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return ChartSeriesHandle representing the new series
- * @throws CellNotFoundException
- */
- private ChartSeriesHandle addSeriesRange(String legendAddress, String legendText, String categoryRange,
- String seriesRange, String bubbleRange, int nChart) throws CellNotFoundException {
- Series s = null;
- if (bubbleRange == null || bubbleRange.equals(""))
- s = mychart.addSeries(seriesRange, categoryRange, "", legendAddress, legendText, nChart);
- else
- s = mychart.addSeries(seriesRange, categoryRange, bubbleRange, legendAddress, legendText, nChart);
- if (nChart > 0) { // must update SeriesList record for overlay charts
- // TODO: FINISH
- }
- setDimensionsRecord();
- return new ChartSeriesHandle(s, wbh);
- }
-
- /**
- * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
- * a Series.
- * An Example of adding multiple series to a chart:
- *
- * ChartHandle.addSeriesRange("Sheet1!A3", "Sheet1!B1:E1", "Sheet1:B3:E3",
- * null);
- * ChartHandle.addSeriesRange("Sheet1!A4", "Sheet1!B1:E1", "Sheet1:B4:E4",
- * null);
- * ChartHandle.addSeriesRange("Sheet1!A5", "Sheet1!B1:E1", "Sheet1:B5:E5",
- * null);
- * etc...
- *
- * Note that the category does not change, it is usually constant through
- * series.
- * Also note that the example above is for a non-bubble-type chart.
- *
- * @param String
- * legendCell - Cell reference for the legend cell (e.g. Sheet1!A1)
- * @param String
- * categoryRange - Category Cell range (e.g. Sheet1!B1:B1);
- * @param String
- * seriesRange - Series Data range (e.g. Sheet1!B3:E3);
- * @param String
- * bubbleRange - Cell Range representing Bubble sizes (e.g.
- * Sheet1!A2:A5); or null if chart is not of type Bubble.
- * @return ChartSeriesHandle referencing the newly added series
- */
- public ChartSeriesHandle addSeriesRange(String legendCell, String categoryRange, String seriesRange,
- String bubbleRange) throws CellNotFoundException {
- return this.addSeriesRange(legendCell, categoryRange, seriesRange, bubbleRange, 0); // target default chart
- }
-
- /**
- * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
- * a Series.
- * An Example of adding multiple series to a chart:
- *
- * ChartHandle.addSeriesRange("Sheet1!A3", "Sheet1!B1:E1", "Sheet1:B3:E3",
- * null);
- * ChartHandle.addSeriesRange("Sheet1!A4", "Sheet1!B1:E1", "Sheet1:B4:E4",
- * null);
- * ChartHandle.addSeriesRange("Sheet1!A5", "Sheet1!B1:E1", "Sheet1:B5:E5",
- * null);
- * etc...
- *
- * Note that the category does not change, it is usually constant through
- * series.
- * Also note that the example above is for a non-bubble-type chart.
- *
- * @param String
- * legendCell - Cell reference for the legend cell (e.g. Sheet1!A1)
- * @param String
- * categoryRange - Category Cell range (e.g. Sheet1!B1:B1);
- * @param String
- * seriesRange - Series Data range (e.g. Sheet1!B3:E3);
- * @param String
- * bubbleRange - Cell Range representing Bubble sizes (e.g.
- * Sheet1!A2:A5); or null if chart is not of type Bubble.
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return ChartSeriesHandle referencing the newly added series
- */
- public ChartSeriesHandle addSeriesRange(String legendCell, String categoryRange, String seriesRange,
- String bubbleRange, int nChart) throws CellNotFoundException {
- String legendText = "";
- String legendAddr = "";
- try {
- CellHandle ICell = null;
- if (legendCell != null && !legendCell.equals("")) {
- try {
- ICell = wbh.getCell(legendCell);
- if (legendCell.indexOf("!") == -1)
- legendAddr = ICell.getWorkSheetName() + "!" + ICell.getCellAddress();
- else
- legendAddr = legendCell;
- } catch (CellNotFoundException c) {
- int shtpos = legendCell.indexOf("!");
- if (shtpos > 0) {
- String sheetstr = legendCell.substring(0, shtpos);
- WorkSheetHandle sht = wbh.getWorkSheet(sheetstr);
- String celstr = legendCell.substring(shtpos + 1);
- ICell = sht.add("", celstr); // TODO: Why is this being added?
- legendAddr = celstr;
- }
- }
- if (ICell != null)
- legendText = ICell.getStringVal();
- else
- legendText = legendCell;
- }
- Series s = null;
- if (bubbleRange == null)
- s = mychart.addSeries(seriesRange, categoryRange, "", legendAddr, legendText, nChart);
- else
- s = mychart.addSeries(seriesRange, categoryRange, bubbleRange, legendAddr, legendText, nChart);
- setDimensionsRecord(); // update chart DIMENSIONS record upon update of series
- return new ChartSeriesHandle(s, wbh);
- } catch (WorkSheetNotFoundException e) {
- throw new CellNotFoundException("Error locating cell for adding series range: " + legendCell);
- }
- }
-
- /**
- * Adds a new Series to the chart via CellHandles and CellRange Objects. Each
- * bar, line or wedge in a chart represents a Series.
- *
- * @param CellHandle
- * legendCell - references the legend cell for this series
- * @param CellRange
- * categoryRange - The CellRange referencing the category (should be
- * the same for all Series)
- * @param CelLRange
- * seriesRange - The CellRange referencing the data points for one
- * bar, line or wedge in the chart
- * @param CellRange
- * bubbleRange -The CellRange referencing bubble sizes for this
- * series, or null if chart is not of type BUBBLE
- * @see ChartHandle.addSeriesRange(String legendCell, String categoryRange,
- * String seriesRange, String bubbleRange)
- * @return ChartSeriesHandle referencing the newly added series
- */
- public ChartSeriesHandle addSeriesRange(CellHandle legendCell, CellRange categoryRange, CellRange seriesRange,
- CellRange bubbleRange) {
- return this.addSeriesRange(legendCell, categoryRange, seriesRange, bubbleRange, 0); // 0=default chart
- }
-
- /**
- * Adds a new Series to the chart via CellHandles and CellRange Objects. Each
- * bar, line or wedge in a chart represents a Series.
- * This method can update the default chart (nChart==0) or overlay charts
- * (nChart 1-9)
- *
- * @param CellHandle
- * legendCell - references the legend cell for this series
- * @param CellRange
- * categoryRange - The CellRange referencing the category (should be
- * the same for all Series)
- * @param CelLRange
- * seriesRange - The CellRange referencing the data points for one
- * bar, line or wedge in the chart
- * @param CellRange
- * bubbleRange -The CellRange referencing bubble sizes for this
- * series, or null if chart is not of type BUBBLE
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @see ChartHandle.addSeriesRange(String legendCell, String categoryRange,
- * String seriesRange, String bubbleRange)
- * @return ChartSeriesHandle referencing the newly added series
- */
- public ChartSeriesHandle addSeriesRange(CellHandle legendCell, CellRange categoryRange, CellRange seriesRange,
- CellRange bubbleRange, int nChart) {
- Series s = null;
- if (bubbleRange == null)
- s = mychart.addSeries(seriesRange.toString(), categoryRange.toString(), "",
- legendCell.getWorkSheetName() + "!" + legendCell.getCellAddress(), legendCell.getStringVal(),
- nChart);
- else
- s = mychart.addSeries(seriesRange.toString(), categoryRange.toString(), bubbleRange.toString(),
- legendCell.getWorkSheetName() + "!" + legendCell.getCellAddress(), legendCell.getStringVal(),
- nChart);
- setDimensionsRecord(); // 20080417 KSC: update chart DIMENSIONS record upon update of series
- return new ChartSeriesHandle(s, wbh);
- }
-
- /**
- * remove the Series (bar, line or wedge) at the desired index
- *
- * @param int
- * index - series index (valid values: 0 to
- * getAllChartSeriesHandles().length-1)
- * @see getAllChartSeriesHandles
- */
- public void removeSeries(int index) {
- removeSeries(index, -1); // -1 flag for all series
- }
-
- /**
- * remove the Series (bar, line or wedge) at the desired index
- *
- * @param int
- * index - series index (valid values: 0 to
- * getAllChartSeriesHandles().length-1)
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @see getAllChartSeriesHandles
- */
- public void removeSeries(int index, int nChart) {
- Vector> seriesperchart = mychart.getAllSeries(nChart);
- Series seriestodelete = (Series) seriesperchart.get(index); // series to delete
- mychart.removeSeries(seriestodelete);
- setDimensionsRecord();
- }
-
- /**
- * updates (replaces) every Chart Series (bar, line or wedge on the Chart) with
- * the data from the array of values, legends, bubble sizes (optional) and
- * category range.
- * NOTE: all arrays must be the same size (the exception is the bubleSizeRanges
- * array, which may be null)
- *
- * NOTE: String arrays come in reverse order from plugins, so this method adds
- * series LIFO i.e. reversed
- *
- * @param String[]
- * valueRanges - Array of Cell Ranges representing the Values or Data
- * points for each series (bar, line or wedge) on the Chart
- * @param String[]
- * legendCells - Array of Cell Addresses representing the legends for
- * each Series
- * @param String[]
- * bubbleSizeRanges - Array of Cell ranges representing the bubble
- * sizes for the Chart, or null if chart is not of type BUBBLE
- * @param String
- * categoryRange - The Cell Range representing the categories (X
- * Axis) for the entire Chart
- */
- public void addAllSeries(String[] valueRanges, String[] legendCells, String[] bubbleSizeRanges,
- String categoryRange) {
- addAllSeries(valueRanges, legendCells, bubbleSizeRanges, categoryRange, 0); // do for default chart
- }
-
- /**
- * updates (replaces) every Chart Series (bar, line or wedge on the Chart) with
- * the data from the array of values, legends, bubble sizes (optional) and
- * category range For the desired chart (0=default 1-9=overlay charts)
- * NOTE: all arrays must be the same size (the exception is the bubleSizeRanges
- * array, which may be null)
- *
- * NOTE: String arrays come in reverse order from plugins, so this method adds
- * series LIFO i.e. reversed
- *
- * @param String[]
- * valueRanges - Array of Cell Ranges representing the Values or Data
- * points for each series (bar, line or wedge) on the Chart
- * @param String[]
- * legendCells - Array of Cell Addresses representing the legends for
- * each Series
- * @param String[]
- * bubbleSizeRanges - Array of Cell ranges representing the bubble
- * sizes for the Chart, or null if chart is not of type BUBBLE
- * @param String
- * categoryRange - The Cell Range representing the categories (X
- * Axis) for the entire Chart
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- */
- private void addAllSeries(String[] valueRanges, String[] legendCells, String[] bubbleSizeRanges,
- String categoryRange, int nChart) {
- // first, remove all existing series
- Vector> v = mychart.getAllSeries();
- for (int i = 0; i < v.size(); i++) {
- mychart.removeSeries((Series) v.get(i));
- }
- try {
- HashMap chartMetrics = mychart.getMetrics(wbh); // build or retrieve Chart Metrics -->
- // dimensions + series data ...
- this.mychart.getLegend().resetPos(chartMetrics.get("y"), chartMetrics.get("h"), chartMetrics.get("canvash"),
- legendCells.length);
- } catch (Exception e) {
- }
- setDimensionsRecord();
- // now add series
- boolean hasBubbles = ((bubbleSizeRanges != null && bubbleSizeRanges.length == valueRanges.length));
- for (int i = valueRanges.length - 1; i >= 0; i--) {
- try {
- if (!hasBubbles) // usual case
- this.addSeriesRange(legendCells[i], categoryRange, valueRanges[i], null, nChart);
- else
- this.addSeriesRange(legendCells[i], categoryRange, valueRanges[i], bubbleSizeRanges[i], nChart);
- } catch (Exception e) {
- Logger.logErr("Error adding series: " + e.toString());
- }
- }
- }
-
- /**
- * Appends a series one row below the last series in the chart.
- *
- * This can be utilized when programmatically adding rows of data that should be
- * reflected in the chart.
- * Legend cell will be incremented by one row if a reference. Category range
- * will stay the same.
- *
- *
- * In order for this method to work properly the chart must have row-based
- * series. If your chart utilizes column-based series, then you need to append a
- * category.
- *
- * @return ChartSeriesHandle representing newly added series
- * @see ChartHandle.appendRowCategoryToChart
- */
- public ChartSeriesHandle appendRowSeriesToChart() {
- return appendRowSeriesToChart(0); // do for default chart (0)
- }
-
- /**
- * Appends a series one row below the last series in the chart for the desired
- * chart
- *
- * This can be utilized when programmatically adding rows of data that should be
- * reflected in the chart.
- * Legend cell will be incremented by one row if a reference. Category range
- * will stay the same.
- *
- *
- * In order for this method to work properly the chart must have row-based
- * series. If your chart utilizes column-based series, then you need to append a
- * category.
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return ChartSeriesHandle representing newly added series
- * @see ChartHandle.appendRowCategoryToChart
- */
- public ChartSeriesHandle appendRowSeriesToChart(int nChart) {
- ChartSeriesHandle[] handles = this.getAllChartSeriesHandles(nChart);
- ChartSeriesHandle theHandle = handles[handles.length - 1];
- String legendRef = theHandle.getSeriesLegendReference();
- if (legendRef != null && !legendRef.equals("")) {
- String sheetnm = legendRef.substring(0, legendRef.indexOf("!"));
- legendRef = legendRef.substring(legendRef.indexOf("!") + 1, legendRef.length());
- int[] rc = ExcelTools.getRowColFromString(legendRef);
- rc[0] = rc[0] + 1;
- legendRef = sheetnm + "!" + ExcelTools.formatLocation(rc);
- } else if (legendRef == null) {
- legendRef = theHandle.getSeriesLegend();
- } else {
- legendRef = "";
- }
- String categoryRange = theHandle.getCategoryRange();
- String seriesRange = theHandle.getSeriesRange();
- String sheetnm = seriesRange.substring(0, seriesRange.indexOf("!"));
- seriesRange = seriesRange.substring(seriesRange.indexOf("!") + 1, seriesRange.length());
- int[] rc = ExcelTools.getRangeRowCol(seriesRange);
- // fiddle it, since exceltools doesn't translate back/forth
- int[] newRc = new int[4];
- newRc[0] = rc[1];
- newRc[1] = rc[0] + 1;
- newRc[2] = rc[3];
- newRc[3] = rc[2] + 1;
- seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc);
- try {
- return this.addSeriesRange(legendRef, "", categoryRange, seriesRange, "", nChart);
- } catch (CellNotFoundException e) {
- Logger.logErr("ChartHandle.appendRowSeriesToChart: Unable to append series to chart: " + e);
- }
- return null;
- }
-
- /**
- * Append a row of categories to the bottom of the chart.
- * Expands all Series to include the new bottom row.
- * To be utilized when expanding a chart to encompass more data that has a
- * col-based series.
- *
- * @see ChartHandle.appendRowSeriesToChart
- */
- public void appendRowCategoryToChart() {
- appendRowCategoryToChart(0); // default chart
- }
-
- /**
- * Append a row of categories to the bottom of the chart.
- * Expands all Series to include the new bottom row.
- * To be utilized when expanding a chart to encompass more data that has a
- * col-based series.
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @see ChartHandle.appendRowSeriesToChart
- */
- public void appendRowCategoryToChart(int nChart) {
- ChartSeriesHandle[] handles = this.getAllChartSeriesHandles(nChart);
-
- for (int i = 0; i < handles.length; i++) {
- ChartSeriesHandle theHandle = handles[i];
- // update the series
- String seriesRange = theHandle.getSeriesRange();
- String[] s = ExcelTools.stripSheetNameFromRange(seriesRange);
- String sheetnm = s[0];
- seriesRange = s[1];
- // String sheetnm = seriesRange.substring(0, seriesRange.indexOf("!"));
- // seriesRange = seriesRange.substring( seriesRange.indexOf("!")+1,
- // seriesRange.length());
- // Strip 2nd sheet ref, if any 20080213 KSC
- // int n= seriesRange.indexOf('!');
- // int m= seriesRange.indexOf(':');
- // seriesRange= seriesRange.substring(0, m+1) + seriesRange.substring(n+1);
-
- int[] rc = ExcelTools.getRangeRowCol(seriesRange);
- int[] newRc = new int[4];
- newRc[0] = rc[1];
- newRc[1] = rc[0];
- newRc[2] = rc[3];
- newRc[3] = rc[2] + 1;
- seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc);
- theHandle.setSeriesRange(seriesRange);
- // update the category
- seriesRange = theHandle.getCategoryRange();
- s = ExcelTools.stripSheetNameFromRange(seriesRange);
- sheetnm = s[0];
- seriesRange = s[1];
- /*
- * sheetnm = seriesRange.substring(0, seriesRange.indexOf("!")); seriesRange =
- * seriesRange.substring( seriesRange.indexOf("!")+1, seriesRange.length()); //
- * Strip 2nd sheet ref, if any 20080213 KSC n= seriesRange.indexOf('!'); m=
- * seriesRange.indexOf(':'); seriesRange= seriesRange.substring(0, m+1) +
- * seriesRange.substring(n+1);
- */
- rc = ExcelTools.getRangeRowCol(seriesRange);
- newRc = new int[4];
- newRc[0] = rc[1];
- newRc[1] = rc[0];
- newRc[2] = rc[3];
- newRc[3] = rc[2] + 1;
- seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc);
- theHandle.setCategoryRange(seriesRange);
- }
- }
-
- /*
- * NOT IMPLEMENTED YET adjust chart cell references upon row insertion or
- * deletion NOTE: Assumes we're on the correct sheet NOT COMPLETELY IMPLEMENTED
- * YEt
- *
- * @param rownum
- *
- * @param shiftamt +1= insert row, -1= delete row
- *
- * public void adjustCellRefs(int rownum, int shiftamt) { Vector v =
- * mychart.getAllSeries(); boolean bSeriesRows= false; boolean bMod= false; for
- * (int i=0;i 0) { // insert row i.e.
- * shift ai location down if ((loc.length==2 && loc[0]>=rownum) ||
- * (loc[0]>=rownum || loc[2]>=rownum)) { adjustAiLocation(ai,
- * p[0].getIntLocation(), shiftamt); bMod= true; } } else { if ((loc.length==2
- * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum)) { // remove it
- * this.removeSeries(i); bMod= true; continue; } } } catch(Exception e) {
- *
- * } } catch (Exception e) {
- *
- * } try { // CATEGORY Ai ai= s.getCategoryValueAi(); Ptg[]
- * p=ai.getCellRangePtgs(); try { int[] loc= p[0].getIntLocation(); if (shiftamt
- * > 0) { // insert row i.e. shift ai location down if ((loc.length==2 &&
- * loc[0]>=rownum) || (loc[0]>=rownum || loc[2]>=rownum)) { adjustAiLocation(ai,
- * p[0].getIntLocation(), shiftamt); bMod= true; } } else { if ((loc.length==2
- * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum)) { // remove it ????
- * this.removeSeries(i); bMod= true; } } } catch(Exception e) {
- *
- * } } catch (Exception e) {
- *
- * } try { // LEGEND Ai ai= s.getLegendAi(); Ptg[] p=ai.getCellRangePtgs();
- * int[] loc= p[0].getIntLocation(); if (shiftamt > 0) { // insert row i.e.
- * shift ai location down if ((loc.length==2 && loc[0]>=rownum) ||
- * (loc[0]>=rownum || loc[2]>=rownum)) { adjustAiLocation(ai,
- * p[0].getIntLocation(), shiftamt); bMod= true; } } else { if ((loc.length==2
- * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum)) { // remove it
- * this.removeSeries(i); bMod= true; } } } catch(Exception e) {
- *
- * } } if (bMod)// one or more series elements were modified
- * setDimensionsRecord(); // update dimensions i.e. Data Range
- *
- * }
- */
-
- /*
- * doesn't appear to be used right now move the ai location (row) according to
- * shift amount
- *
- * @param ai
- *
- * @param loc
- *
- * @param shift
- *
- * private void adjustAiLocation(Ai ai, int[] loc, int shift) { String oldloc=
- * ExcelTools.formatLocation(loc); if (loc.length>2) // get 2nd part of range
- * oldloc += ":" + ExcelTools.formatLocation(new int[]{loc[2], loc[3]}); oldloc=
- * this.getSheet().getSheetName() + "!" + oldloc; if (loc.length==2)// single
- * cell loc[0]+=shift; else { // range loc[0]+=shift; loc[2]+=shift; } String
- * newloc= ExcelTools.formatLocation(loc); if (loc.length>2) // get 2nd part of
- * range newloc += ":" + ExcelTools.formatLocation(new int[]{loc[2], loc[3]});
- * ai.changeAiLocation(oldloc, newloc); }
- *
- */
- /**
- * Get the Chart's bytes
- *
- * This is an internal method that is not useful to the end user.
- *
- */
- public byte[] getChartBytes() {
- return mychart.getChartBytes();
- }
-
- public byte[] getSerialBytes() {
- return mychart.getSerialBytes();
- }
-
- /**
- * get the chart-type-specific options in XML form
- *
- * @return String XML
- */
- private String getChartOptionsXML() {
- return mychart.getChartOptionsXML(0); // 0 for default chart
- }
-
- private String t(int n) {
- String tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t";
- return (tabs.substring(0, n));
- }
-
- /**
- * given a XmlPullParser positioned at the chart element, parse all chart
- * elements to create desired chart
- *
- * @param sht
- * WorkSheetHandle
- * @param xpp
- * XmlPullParser
- */
- public void parseXML(WorkSheetHandle sht, XmlPullParser xpp, HashMap, ?> maps) {
- try {
- int eventType = xpp.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.START_TAG) {
- String tnm = xpp.getName();
- if (tnm.equals("ChartFonts")) {
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- this.setChartFont(xpp.getAttributeName(x), xpp.getAttributeValue(x));
- }
- } else if (tnm.equals("ChartFontRec")) {
- String fName = "";
- int fontId = 0, fSize = 0, fWeight = 0, fColor = 0, fUnderline = 0;
- boolean bIsBold = false;
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- String attr = xpp.getAttributeName(x);
- String val = xpp.getAttributeValue(x);
- if (attr.equals("name")) {
- fName = val;
- } else if (attr.equals("id")) {
- fontId = Integer.parseInt(val);
- } else if (attr.equals("size")) {
- fSize = Font.PointsToFontHeight(Double.parseDouble(val));
- } else if (attr.equals("color")) {
- fColor = FormatHandle.HexStringToColorInt(val, FormatHandle.colorFONT);
- if (fColor == 0)
- fColor = 32767; // necessary?
- } else if (attr.equals("weight")) {
- fWeight = Integer.parseInt(val);
- } else if (attr.equals("bold")) {
- bIsBold = true;
- } else if (attr.equals("underline")) {
- fUnderline = Integer.parseInt(val);
- }
- }
- while (this.getWorkBook().getNumFonts() < fontId - 1) {
- this.getWorkBook().insertFont(new Font("Arial", FormatConstants.PLAIN, 10));
- }
- if (this.getWorkBook().getNumFonts() < fontId) {
- Font f = new Font(fName, fWeight, fSize);
- f.setColor(fColor);
- f.setBold(bIsBold);
- f.setUnderlineStyle((byte) fUnderline);
- this.getWorkBook().insertFont(f);
- } else { // TODO: this will screw up linked fonts, perhaps, so what to do?
- Font f = this.getWorkBook().getFont(fontId);
- f.setFontWeight(fWeight);
- f.setFontName(fName);
- f.setFontHeight(fSize);
- f.setColor(fColor);
- f.setBold(bIsBold);
- f.setUnderlineStyle((byte) fUnderline);
- }
- } else if (tnm.equals("FormatChartArea")) { // TODO: something!
- // ChartBorder
- // ChartProperties
- } else if (tnm.equals("Series")) { // series -->
- // Legend Range Category shape typex typey
- String legend = "", series = "", category = "", bubble = "";
- String dataTypeX = "", dataTypeY = "";
- String shape = "";
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- if (xpp.getAttributeName(x).equalsIgnoreCase("Legend"))
- legend = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Range"))
- series = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Category"))
- category = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Bubbles"))
- bubble = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("TypeX"))
- dataTypeX = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("TypeY"))
- dataTypeY = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Shape"))
- shape = xpp.getAttributeValue(x);
- }
- // 20070709 KSC: can't add until all cells are added
- // ch.addSeriesRange(legend, category, series);
- String[] s = { legend, series, category, bubble, dataTypeX, dataTypeY, shape };
- HashMap map = (HashMap) maps.get("chartseries");
- map.put(s, this);
- } else if (tnm.equals("ChartOptions")) { // handle chart-type-specific options such as legend
- // options
- // 20070716 KSC: handle chart-type-specific options in a very generic way ...
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- this.setChartOption(xpp.getAttributeName(x), xpp.getAttributeValue(x));
- }
- } else if (tnm.equals("ThreeD")) { // handle three-d options
- // handle threeD record options in a very generic way ...
- this.make3D(); // default chart - TODO; if mutliple charts, handle
- for (int x = 0; x < xpp.getAttributeCount(); x++) { // now add threed rec options
- this.setChartOption(xpp.getAttributeName(x), xpp.getAttributeValue(x));
- }
- } else if (tnm.endsWith("Axis")) { // handle axis specs (Label + options ...)
- // 20070720 KSC: handle Axis record options ...
- int type = 0;
- String axis = xpp.getName();
- if (axis.equalsIgnoreCase("XAxis"))
- type = XAXIS;
- else if (axis.equalsIgnoreCase("YAxis"))
- type = YAXIS;
- else if (axis.equalsIgnoreCase("ZAxis"))
- type = ZAXIS;
- if (xpp.getAttributeCount() > 0) { // then has axis options
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- this.setAxisOption(type, xpp.getAttributeName(x), xpp.getAttributeValue(x));
- }
- } else { // no axis options means no axis present; remove
- this.removeAxis(type);
- }
- } else if (tnm.equals("Series")) { // handle series data
- // Legend Range Category
- String legend = "", series = "", category = "", bubble = "";
- String dataTypeX = "", dataTypeY = "";
- String shape = "";
- for (int x = 0; x < xpp.getAttributeCount(); x++) {
- if (xpp.getAttributeName(x).equalsIgnoreCase("Legend"))
- legend = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Range"))
- series = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Category"))
- category = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Bubbles"))
- bubble = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("TypeX"))
- dataTypeX = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("TypeY"))
- dataTypeY = xpp.getAttributeValue(x);
- else if (xpp.getAttributeName(x).equalsIgnoreCase("Shape"))
- shape = xpp.getAttributeValue(x);
- }
- // 20070709 KSC: can't add until all cells are added
- // ch.addSeriesRange(legend, category, series);
- String[] s = { legend, series, category, bubble, dataTypeX, dataTypeY, shape };
- HashMap map = (HashMap) maps.get("chartseries");
- map.put(s, this);
- }
- } else if (eventType == XmlPullParser.END_TAG) {
- if (xpp.getName().equals("Chart"))
- break;
- }
- eventType = xpp.next();
- }
- } catch (Exception e) {
- Logger.logWarn("ChartHandle.parseXML <" + xpp.getName() + ">: " + e.toString());
- // TODO: propogate Exception???
- }
- }
-
- /**
- * returns an XML representation of this chart
- *
- * @return String XML
- */
- public String getXML() {
- StringBuffer sb = new StringBuffer(t(1) + "\n");
-
- // Chart Fonts
- sb.append(t(2) + "" + this.getChartFontRecsXML());
- sb.append("\n" + t(2) + " \n");
- sb.append(t(2) + " \n");
- // Format Chart Area
- sb.append(t(2) + "\n");
- sb.append(t(3) + " \n"); // KSC: TODO: BORDER
- sb.append(t(3) + " \n"); // TODO: Properties
- sb.append(t(2) + " \n");
- // Source Data
- sb.append(t(2) + "\n");
- ChartSeriesHandle[] series = this.getAllChartSeriesHandles();
- for (int i = 0; i < series.length; i++) {
- sb.append(t(3) + " \n");
- }
- sb.append(t(2) + " \n");
- // Chart Options
- sb.append(t(2) + " \n");
- // Axis Options
- sb.append(t(2) + "\n");
- sb.append(t(3) + " \n");
- sb.append(t(3) + " \n");
- sb.append(t(3) + " \n");
- sb.append(t(2) + " \n");
- // ThreeD rec opts
- if (this.isThreeD()) {
- sb.append(t(2) + " \n");
- }
-
- sb.append(t(1) + " \n");
- return sb.toString();
- }
-
- /********************************************************************
- * OOXML Generation Methods
- **********************************************************************/
- /**
- * Generates OOXML (chartML) for this chart object.
- *
- *
- * NOTE: necessary root chartSpace element + namespaces are not set here
- *
- * @param int
- * rId -reference ID for this chart
- * @return String representing the OOXML describing this Chart
- */
- public String getOOXML(int rId) {
- // TODO: finish 3d options- floor, sideWall, backWall
- // TODO: finish axis options
- // TODO: printSettings
-
- // generate OOXML (chartML)
- StringBuffer cooxml = new StringBuffer();
- try {
- mychart.getChartSeries().resetSeriesNumber(); // reset series idx
- // retrieve pertinent chart data
- // axes id's TODO: HANDLE MULTIPLE AXES per chart ...
- String catAxisId = Integer.toString((int) (Math.random() * 1000000));
- String valAxisId = Integer.toString((int) (Math.random() * 1000000));
- String serAxisId = Integer.toString((int) (Math.random() * 1000000));
- OOXMLChart thischart;
- if ((mychart instanceof OOXMLChart))
- thischart = (OOXMLChart) mychart;
- else { // XLS->XLSX
- thischart = new OOXMLChart(mychart, wbh);
- mychart = thischart;
- thischart.getChartSeries().setParentChart(thischart);
- }
- thischart.wbh = this.wbh;
-
- cooxml.append(thischart.getOOXML(catAxisId, valAxisId, serAxisId));
-
- // TODO:
- ArrayList> chartEmbeds = thischart.getChartEmbeds();
- if (chartEmbeds != null) {
- int j = 0;
- for (int i = 0; i < chartEmbeds.size(); i++) {
- if (((String[]) chartEmbeds.get(i))[0].equals("userShape")) {
- j++;
- cooxml.append(" ");
- }
- }
- }
- } catch (Exception e) {
- Logger.logErr("ChartHandle.getOOXML: error generating OOXML. Chart not created: " + e.toString());
- }
- return cooxml.toString();
- }
-
- /**
- * generates the OOXML specific for DrawingML, specifying offsets and
- * identifying the chart object.
- * this Drawing ML (OOXML) is distinct from Chart ML (OOXML) which actually
- * defines the chart object including series, categories and axes
- * This is an internal method that is not useful to the end user.
- *
- * @param int
- * id - the reference id for this chart
- * @return String OOXML
- */
- public String getChartDrawingOOXML(int id) {
- TwoCellAnchor t = new TwoCellAnchor(((OOXMLChart) mychart).getEditMovement());
- t.setAsChart(id, OOXMLAdapter.stripNonAscii(this.getOOXMLName()).toString(),
- TwoCellAnchor.convertBoundsFromBIFF8(this.getSheet(), mychart.getBounds())); // adjust BIFF8 bounds to
- // OOXML units
- return t.getOOXML();
- }
-
- /********************************************************************************
- * Parsing OOXML Methods
- **********************************************************************/
- /**
- * defines this chart object based on a Chart ML (OOXML) input Stream (root
- * element=c:chartSpace)
- * This is an internal method that is not useful to the end user.
- *
- * @param inputStream
- * ii - representing chart OOXML
- */
- public void parseOOXML(java.io.InputStream ii) {
- // overlay in title, after layout
- // varyColors val= "0" -- after grouping and before ser
-
- // series colors by theme:
- /*
- * accent1 - 6
- */
- /**
- * chartSpace: chart (Chart) §5.7.2.27 clrMapOvr (Color Map Override) §5.7.2.30
- * date1904 (1904 Date System) §5.7.2.38 externalData (External Data
- * Relationship) §5.7.2.63 extLst (Chart Extensibility) §5.7.2.64 lang (Editing
- * Language) §5.7.2.87 pivotSource (Pivot Source) §5.7.2.145 printSettings
- * (Print Settings) §5.7.2.149 protection (Protection) §5.7.2.150 roundedCorners
- * (Rounded Corners) §5.7.2.160 spPr (Shape Properties) §5.7.2.198 style (Style)
- * §5.7.2.203 txPr (Text Properties) §5.7.2.217 userShapes (Reference to Chart
- * Drawing Part) §5.7.2.222
- */
- try {
- OOXMLChart thischart = (OOXMLChart) mychart;
- int drawingOrder = 0; // drawing order of the chart (0=default, 1-9 for multiple charts in 1)
- boolean hasPivotTableSource = false;
-
- // remove any undesired formatting from default chart:
- this.setTitle(""); // clear any previously set
- mychart.getAxes().setPlotAreaBgColor(FormatConstants.COLOR_WHITE);
- mychart.getAxes().setPlotAreaBorder(-1, -1); // remove plot area border
-
- java.util.Stack lastTag = new java.util.Stack(); // keep track of element hierarchy
-
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- XmlPullParser xpp = factory.newPullParser();
-
- xpp.setInput(ii, null); // using XML 1.0 specification
- int eventType = xpp.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.START_TAG) {
- String tnm = xpp.getName(); // main entry= chartSpace, children: lang, chart
- lastTag.push(tnm); // keep track of element hierarchy
- if (tnm.equals("chart")) { // beginning of DrawingML for a single image or chart; children: title,
- // plotArea, legend,
- /**
- * 5
- * 6
- * 7
- * 8
- * 9
- * 10
- * 11
- * 12
- *
- * plotArea contains layout, , serAx, valAx, catAx, dateAx, spPr,
- * dTable 13
- * 14
- *
- * 15
- * 16
- * 17
- *
- * 18
- */
- } else if (tnm.equals("lang")) {
- thischart.lang = xpp.getAttributeValue(0);
- } else if (tnm.equals("roundedCorners")) {
- thischart.roundedCorners = xpp.getAttributeValue(0).equals("1");
- } else if (tnm.equals("pivotSource")) { // has a pivot table
- hasPivotTableSource = true;
- } else if (tnm.equals("view3D")) {
- ThreeD.parseOOXML(xpp, lastTag, thischart);
- } else if (tnm.equals("layout")) {
- thischart.plotAreaLayout = (Layout) Layout.parseOOXML(xpp, lastTag).cloneElement();
- } else if (tnm.equals("legend")) {
- thischart.showLegend(true, false);
- thischart.ooxmlLegend = (io.starter.formats.OOXML.Legend) io.starter.formats.OOXML.Legend
- .parseOOXML(xpp, lastTag, this.wbh).cloneElement();
- thischart.ooxmlLegend.fill2003Legend(thischart.getLegend());
- // Parse actual CHART TYPE element (barChart, pieChart, etc.)
- } else if (tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.BARCHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.LINECHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.PIECHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.AREACHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.SCATTERCHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.RADARCHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.SURFACECHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.DOUGHNUTCHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.BUBBLECHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.OFPIECHART])
- || tnm.equals(OOXMLConstants.twoDchartTypes[ChartHandle.STOCKCHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.BARCHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.LINECHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.PIECHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.AREACHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.SCATTERCHART])
- || tnm.equals(OOXMLConstants.threeDchartTypes[ChartHandle.SURFACECHART])) { // specific
- // chart type-
- ChartType.parseOOXML(xpp, this.wbh, mychart, drawingOrder++);
- lastTag.pop();
- } else if (tnm.equals("title")) {
- thischart.setOOXMLTitle((Title) Title.parseOOXML(xpp, lastTag, this.wbh).cloneElement(),
- this.wbh);
- this.setTitle(thischart.getOOXMLTitle().getTitle());
- } else if (tnm.equals("spPr")) { // shape properties -- can be for plot area or chart space
- String parent = lastTag.get(lastTag.size() - 2);
- if (parent.equals("plotArea")) {
- thischart.setSpPr(0, (SpPr) SpPr.parseOOXML(xpp, lastTag, this.wbh).cloneElement());
- } else if (parent.equals("chartSpace")) {
- thischart.setSpPr(1, (SpPr) SpPr.parseOOXML(xpp, lastTag, this.wbh).cloneElement());
- }
- } else if (tnm.equals("txPr")) { // text formatting
- thischart.setTxPr((TxPr) TxPr.parseOOXML(xpp, lastTag, this.wbh).cloneElement());
- } else if (tnm.equals("catAx")) { // child of plotArea
- mychart.getAxes().parseOOXML(XAXIS, xpp, tnm, lastTag, this.wbh);
- } else if (tnm.equals("valAx")) { // child of plotArea
- if (mychart.getAxes().hasAxis(ChartConstants.XAXIS)) // usual, have a catAx then a valAx
- mychart.getAxes().parseOOXML(ChartConstants.YAXIS, xpp, tnm, lastTag, this.wbh);
- else if (mychart.getAxes().hasAxis(ChartConstants.YAXIS)) // for bubble charts, has two valAxes
- // and no
- // catAx
- mychart.getAxes().parseOOXML(ChartConstants.XVALAXIS, xpp, tnm, lastTag, this.wbh);
- else // 2nd val axis is Y axis
- mychart.getAxes().parseOOXML(ChartConstants.YAXIS, xpp, tnm, lastTag, this.wbh);
- } else if (tnm.equals("serAx")) { // series axis - 3d charts
- mychart.getAxes().parseOOXML(ZAXIS, xpp, tnm, lastTag, this.wbh);
- } else if (tnm.equals("dateAx")) { // TODO: not finished: figure out!
- // ??
- }
-
- } else if (eventType == XmlPullParser.END_TAG) {
- lastTag.pop();
- String endTag = xpp.getName();
- if (endTag.equals("chartSpace")) {
- setDimensionsRecord();
- break; // done processing
- }
- }
- if (xpp.getEventType() != XmlPullParser.END_DOCUMENT)
- eventType = xpp.next();
- else
- eventType = XmlPullParser.END_DOCUMENT;
- }
- } catch (Exception e) {
- Logger.logErr("ChartHandle.parseChartOOXML: " + e.toString());
- }
- }
-
- /**
- * Specifies how to resize or move this Chart upon edit
- * This is an internal method that is not useful to the end user.
- * Excel 7/OOXML specific
- *
- * @param editMovement
- * String OOXML-specific edit movement setting
- */
- public void setEditMovement(String editMovement) {
- ((OOXMLChart) mychart).setEditMovement(editMovement);
- }
-
- /**
- * return the Excel 7/OOXML-specific name for this chart
- *
- * @return String OOXML name
- */
- private String getOOXMLName() {
- return ((OOXMLChart) mychart).getOOXMLName();
- }
-
- /**
- * set the Excel 7/OOXML-specific name for this chart
- *
- * @param String
- * name
- */
- public void setOOXMLName(String name) {
- ((OOXMLChart) mychart).setOOXMLName(name);
- }
-
- /**
- * returns the drawingml file name which defines the userShape (if any)
- * a userShape is a drawing or shape ontop of a chart associated with this chart
- *
- * @return
- */
- public ArrayList> getChartEmbeds() {
- return ((OOXMLChart) mychart).getChartEmbeds();
- }
-
- /**
- * sets external information linked to or "embedded" in this OOXML chart; can be
- * a chart user shape, an image ...
- * NOTE: a userShape is a drawingml file name which defines the userShape (if
- * any)
- * a userShape is a drawing or shape ontop of a chart
- *
- * @param String[]
- * embedType, filename e.g. {"userShape", "userShape file name"}
- */
- public void addChartEmbed(String[] ce) {
- ((OOXMLChart) mychart).addChartEmbed(ce);
- }
-
- /**
- * set the chart DIMENSIONS record based on the series ranges in the chart
- * APPEARS THAT for charts, the DIMENSIONS record merely notes the range of
- * values: 0, #points in series, 0, #series
- */
- protected void setDimensionsRecord() {
- ChartSeriesHandle[] series = this.getAllChartSeriesHandles();
- int nSeries = series.length;
- int nPoints = 0;
- for (int i = 0; i < series.length; i++) {
- try {
- int[] coords = ExcelTools.getRangeCoords(series[i].getSeriesRange());
- if (coords[3] > coords[1])
- nPoints = Math.max(nPoints, coords[3] - coords[1] + 1); // c1-c0
- else
- nPoints = Math.max(nPoints, coords[2] - coords[0] + 1); // r1-r0
- } catch (Exception e) {
- }
- }
- mychart.setDimensionsRecord(0, nPoints, 0, nSeries);
- }
-
- /**
- * Method for setting Chart-Type-specific options in a generic fashion e.g.
- * charthandle.setChartOption("Stacked", "true");
- *
- * Note: since most Chart Type Options are interdependent, there are several
- * makeXX methods that set the desired group of options e.g. makeStacked(); use
- * setChartOption with care
- *
- * Note that not all Chart Types will have every option available
- *
- * Possible Options:
- *
- * "Stacked" - true or false - set Chart Series to be Stacked
- * "Cluster" - true or false - set Clustered for Column and Bar Chart Types
- * "PercentageDisplay" - true or false - Each Category is broken down as a
- * percentge
- * "Percentage" - Distance of pie slice from center of pie as % for Pie Charts
- * (0 for all others)
- * "donutSize" - Donut size for Donut Charts Only
- * "Overlap" - Space between bars (default= 0%)
- * "Gap" - Space between categories (%) (default=50%)
- * "SmoothedLine" - true or false - the Line series has a smoothed line
- * "AnRot" - Rotation Angle (0 to 360 degrees), usually 0 for pie, 20 for others
- * (3D option)
- * "AnElev" - Elevation Angle (-90 to 90 degrees) (15 is default) (3D option)
- *
- * "ThreeDScaling" - true or false - 3d effect
- * "TwoDWalls" - true if 2D walls (3D option)
- * "PcDist" - Distance from eye to chart (0 to 100) (30 is default) (3D option)
- *
- * "ThreeDBubbles" - true or false - Draw bubbles with a 3d effect
- * "ShowLdrLines" - true or false - Show Pie and Donut charts Leader Lines
- * "MarkerFormat" - "0" thru "9" for various marker options @see
- * ChartHandle.setMarkerFormat
- * "ShowLabel" - true or false - show Series/Data Label
- * "ShowCatLabel" - true or false - show Category Label
- * "ShowLabelPct" - true or false - show percentage labels for Pie charts
- * "ShowBubbleSizes" - true or false - show bubble sizes for Bubble charts
- *
- * NOTE: all values must be in String form
- *
- * @see ChartHandle.getXML
- */
- public void setChartOption(String op, String val) {
- mychart.setChartOption(op, val);
- }
-
- /**
- * Method for setting Chart-Type-specific options in a generic fashion e.g.
- * charthandle.setChartOption("Stacked", "true");
- *
- * @param op
- * @param val
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- */
- private void setChartOption(String op, String val, int nChart) {
- mychart.setChartOption(op, val, nChart);
- }
-
- /**
- * @return true if Chart has 3D effects, false otherwise
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- */
- public boolean isThreeD(int nChart) {
- return mychart.isThreeD(nChart);
- }
-
- /**
- * @return true if Chart has 3D effects, false otherwise
- */
- public boolean isThreeD() {
- return mychart.isThreeD(0); // default chart
- }
-
- /**
- * @return boolean true if Chart contains Stacked Series, false otherwise
- */
- public boolean isStacked() {
- return mychart.isStacked(0); // default chart
- }
-
- /**
- * @return boolean true if Chart is of type 100% Stacked, false otherwise
- */
- public boolean is100PercentStacked() {
- return mychart.is100PercentStacked(0); // default chart
- }
-
- /**
- * @return boolean true if Chart contains Clustered Bars or Columns, false
- * otherwise
- */
- public boolean isClustered() {
- return mychart.isClustered(0); // default chart
- }
-
- /**
- * @return String ThreeD options in XML form
- */
- public String getThreeDXML() {
- return mychart.getThreeDXML(0); // 0 for default chart
- }
-
- /**
- * Make chart 3D if not already
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @return ThreeD rec
- */
- private ThreeD initThreeD(int nChart) {
- return mychart.initThreeD(nChart, this.getChartType(nChart));
- }
-
- /**
- * @return String XML representation of the desired Axis
- * @param int
- * Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
- */
- private String getAxisOptionsXML(int Axis) {
- return mychart.getAxes().getAxisOptionsXML(Axis);
- }
-
- /**
- * Returns the Axis Label Placement or position as an int
- *
- * One of:
- * Axis.INVISIBLE - axis is hidden
- * Axis.LOW - low end of plot area
- * Axis.HIGH - high end of plot area
- * Axis.NEXTTO- next to axis (default)
- *
- * @param int
- * Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
- * @return int - one of the Axis Label placement constants above
- */
- public int getAxisPlacement(int Axis) {
- return mychart.getAxes().getAxisPlacement(Axis);
- }
-
- /**
- * Sets the Axis labels position or placement to the desired value (these match
- * Excel placement options)
- *
- * Possible options:
- * Axis.INVISIBLE - hides the axis
- * Axis.LOW - low end of plot area
- * Axis.HIGH - high end of plot area
- * Axis.NEXTTO- next to axis (default)
- *
- * @param int
- * Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
- * @param Placement
- * - int one of the Axis placement constants listed above
- */
- public void setAxisPlacement(int Axis, int Placement) {
- mychart.getAxes().setAxisPlacement(Axis, Placement);
- mychart.setDirtyFlag(true);
- }
-
- /*
- * returns the desired axis If bCreateIfNecessary, will creates if doesn't exist
- *
- * @return Axis Object / private Axis getAxis(int axisType, boolean
- * bCreateIfNecessary) { return mychart.getAxis(axisType, bCreateIfNecessary); }
- */
-
- /**
- * removes the desired Axis from the Chart
- *
- * @param int
- * axisType - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
- */
- public void removeAxis(int axisType) {
- mychart.getAxes().removeAxis(axisType);
- mychart.setDirtyFlag(true);
- }
-
- /**
- * returns Chart-specific Font Records in XML form
- *
- * @return String Chart Font information in XML format
- */
- public String getChartFontRecsXML() {
- return mychart.getChartFontRecsXML();
- }
-
- /**
- * Return non-axis Chart font ids in XML form
- *
- * @return String Font information in XML format
- */
- public String getChartFontsXML() {
- return mychart.getChartFontsXML();
- }
-
- /**
- * Set non-axis chart font id for title, default, etc
- * For Internal Use Only
- *
- * @param String
- * type - font type
- * @param String
- * val - font id
- */
- public void setChartFont(String type, String val) {
- mychart.setChartFont(type, val);
- }
-
- /**
- * @return the WorkBook Object attached to this Chart
- */
- public io.starter.formats.XLS.WorkBook getWorkBook() {
- return mychart.getWorkBook();
- }
-
- public WorkBookHandle getWorkBookHandle() {
- return this.wbh;
- }
-
- public WorkSheetHandle getWorkSheetHandle() {
- try {
- return this.wbh.getWorkSheet(mychart.getSheet().getSheetNum());
- } catch (WorkSheetNotFoundException e) {
- // this should be impossible
- throw new RuntimeException(e);
- }
- }
-
- /**
- * sets the coordinates or bounds (position, width and height) of this chart in
- * pixels
- *
- * @param short[4]
- * bounds - left or x value, top or y value, width, height
- * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
- */
- // NOTE: THIS SHOULD BE RENAMED TO setCoords as Bounds and Coords are very
- // distinct
- public void setBounds(short[] bounds) {
- mychart.setCoords(bounds);
- }
-
- /**
- * returns the coordinates or bounds (position, width and height) of this chart
- * in pixels
- *
- * @return short[4] bounds - left or x value, top or y value, width, height
- * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
- */
- // NOTE: THIS SHOULD BE RENAMED TO setCoords as Bounds and Coords are very
- // distinct
- public short[] getBounds() {
- return mychart.getCoords();
- }
-
- /**
- * sets the coordinates (position, width and height) for this chart in Excel
- * size units
- *
- * @return short[4] pixel coords - left or x value, top or y value, width,
- * height
- * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
- */
- public void setCoords(short[] coords) {
- mychart.setCoords(coords);
- }
-
- /**
- * returns the coordinates (position, width and height) of this chart in Excel
- * size units
- *
- * @return short[4] pixel coords - left or x value, top or y value, width,
- * height
- * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
- */
- public short[] getCoords() {
- mychart.getMetrics(this.wbh);
- return mychart.getCoords();
- }
-
- /**
- * get the bounds of the chart using coordinates relative to row/cols and their
- * offsets
- *
- * @return short[8] bounds - COL, COLOFFSET, ROW, ROWOFFST, COL1, COLOFFSET1,
- * ROW1, ROWOFFSET1
- */
- public short[] getRelativeBounds() {
- return mychart.getBounds();
- }
-
- /**
- * returns the offset within the column in pixels
- *
- * @return
- */
- public short getColOffset() {
- return mychart.getColOffset();
- }
-
- /**
- * sets the bounds of the chart using coordinates relative to row/cols and their
- * offsets
- *
- * @param short[8]
- * bounds - COL, COLOFFSET, ROW, ROWOFFST, COL1, COLOFFSET1, ROW1,
- * ROWOFFSET1
- *
- */
- public void setRelativeBounds(short[] bounds) {
- mychart.setBounds(bounds);
- }
-
- // 20070802 KSC: Debug uility to write out chartrecs
- /*
- * For internal debugging use only
- *
- * public void writeChartRecs(String fName) { mychart.writeChartRecs(fName); }
- *
- * /** set DataLabels option for this chart
- *
- * @param String type - see below
- *
- * @param boolean bShowLegendKey - true if show legend key, false otherwise
- * possible String type values: Series Category Value
- * Percentage (Only for Pie Charts) Bubble (Only for Bubble Charts)
- * X Value (Only for Bubble Charts) Y Value (Only for Bubble Charts)
- * CandP
- *
- * NOTE: not 100% implemented at this time
- */
- public void setDataLabel(String/* [] */ type, boolean bShowLegendKey) {
- /*
- * for now, only 1 option is valid - multiple legend settings e.g. Category and
- * Value are not figured out yet for (int i= 0; i < type.length; i++)
- * mychart.setChartOption("DataLabel", type[i]);
- */
- if (!bShowLegendKey)
- mychart.setChartOption("DataLabel", type);
- else
- mychart.setChartOption("DataLabelWithLegendKey", type);
- }
-
- /**
- * shows or removes the Data Table for this chart
- *
- * @param boolean
- * bShow - true if show data table
- */
- public void showDataTable(boolean bShow) {
- mychart.showDataTable(bShow);
- }
-
- /**
- * shows or hides the Chart legend key
- *
- * @param booean
- * bShow - true if show legend, false to hide
- * @param boolean
- * vertical - true if show vertically, false for horizontal
- */
- public void showLegend(boolean bShow, boolean vertical) {
- mychart.showLegend(bShow, vertical);
- }
-
- /**
- * returns true if Chart has a Data Legend Key showing
- *
- * @return true if Chart has a Data Legend Key showing
- */
- public boolean hasDataLegend() {
- return mychart.hasDataLegend();
- }
-
- public void removeLegend() {
- mychart.removeLegend();
- }
-
- // 20070905 KSC: Group chart options for ease of setting
- // almost all charts have these specific ChartTypes:
- /**
- * makes this Chart Stacked
- * sets the group of options necessary to create a stacked chart
- * For Chart Types:
- * BAR, COL, LINE, AREA, PYRAMID, PYRAMIDBAR, CYLINDER, CYLINDERBAR, CONE,
- * CONEBAR
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated
- */
- @Deprecated
- public void makeStacked(int nChart) { // bar, col, line, area, pyramid col + bar, cone col + bar, cylinder col + bar
- int chartType = this.getChartType(nChart);
- this.setChartOption("Stacked", "true", nChart);
- switch (chartType) {
- case ChartConstants.BARCHART:
- case ChartConstants.COLCHART:
- this.setChartOption("Overlap", "-100", nChart);
- break;
- case ChartConstants.CYLINDERCHART:
- case ChartConstants.CYLINDERBARCHART:
- case ChartConstants.CONECHART:
- case ChartConstants.CONEBARCHART:
- case ChartConstants.PYRAMIDCHART:
- case ChartConstants.PYRAMIDBARCHART:
- this.setChartOption("Overlap", "-100", nChart);
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("Cluster", "false");
- break;
- case ChartConstants.LINECHART:
- this.setChartOption("Percentage", "0", nChart);
- break;
- case ChartConstants.AREACHART:
- this.setChartOption("Overlap", "-100", nChart);
- this.setChartOption("Percentage", "25", nChart);
- this.setChartOption("SmoothedLine", "true", nChart);
- break;
- }
- }
-
- /**
- * makes this Chart 100% Stacked
- * sets the group of options necessary to create a 100% stacked chart
- * For Chart Types:
- * BAR, COL, LINE, PYRAMID, PYRAMIDBAR, CYLINDER, CYLINDERBAR, CONE, CONEBAR
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated
- */
- @Deprecated
- public void make100PercentStacked(int nChart) { // bar, col, line, pyramid col + bar, cone col + bar, cylinder col +
- // bar
- int chartType = this.getChartType(nChart);
- this.setChartOption("Stacked", "true", nChart);
- this.setChartOption("PercentageDisplay", "true", nChart);
- switch (chartType) {
- case ChartConstants.COLCHART: // + pyramid
- case ChartConstants.BARCHART:
- this.setChartOption("Overlap", "-100", nChart);
- break;
- case ChartConstants.CYLINDERCHART:
- case ChartConstants.CYLINDERBARCHART:
- case ChartConstants.CONECHART:
- case ChartConstants.CONEBARCHART:
- case ChartConstants.PYRAMIDCHART:
- case ChartConstants.PYRAMIDBARCHART:
- this.setChartOption("Overlap", "-100", nChart);
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("Cluster", "false");
- break;
- case ChartConstants.LINECHART:
- break;
- }
- }
-
- /**
- * makes this Chart Stacked with a 3D Effect
- * sets the group of options necessary to create a Stacked 3D chart
- * For Chart Types:
- * BAR, COL, AREA
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- */
- public void makeStacked3D(int nChart) { // bar, col, area
- int chartType = this.getChartType(nChart);
- this.setChartOption("Stacked", "true", nChart);
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "20");
- td.setChartOption("ThreeDScaling", "true");
- td.setChartOption("TwoDWalls", "true");
- switch (chartType) {
- case ChartConstants.COLCHART:
- case ChartConstants.BARCHART:
- this.setChartOption("Overlap", "-100", nChart);
- break;
- case ChartConstants.AREACHART:
- this.setChartOption("Percentage", "25", nChart);
- this.setChartOption("SmoothedLine", "true", nChart);
- break;
- }
- }
-
- /**
- * makes this Chart 100% Stacked with a 3D Effect
- * sets the group of options necessary to create a 100% Stacked 3D chart
- * For Chart Types:
- * BAR, COL, AREA
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated
- */
- @Deprecated
- public void make100PercentStacked3D(int nChart) { // bar, col, area
- int chartType = this.getChartType(nChart);
- this.setChartOption("Stacked", "true", nChart);
- this.setChartOption("PercentageDisplay", "true", nChart);
- switch (chartType) {
- case ChartConstants.COLCHART: // + pyramid
- case ChartConstants.BARCHART:
- this.setChartOption("Overlap", "-100", nChart);
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "20");
- td.setChartOption("ThreeDScaling", "true");
- td.setChartOption("TwoDWalls", "true");
- break;
- case ChartConstants.AREACHART:
- this.setChartOption("Percentage", "25", nChart);
- this.setChartOption("SmoothedLine", "true", nChart);
- break;
- }
- }
-
- /**
- * makes the default Chart hava a 3D effect
- * sets the group of options necessary to create a 3D chart
- * For Chart Types:
- * BARCHART, COLCHART, LINECHART, PIECHART, AREACHART, BUBBLECHART,
- * PYRAMIDCHART, CYLINDERCHART, CONECHART
- *
- * @deprecated use setChartType(chartType, 0, is3d, isStacked,
- * is100PercentStacked) instead
- */
- @Deprecated
- public void make3D() { // bar, col, line, pie, area, bubble, pyramid, cone, cylinder
- make3D(0);
- }
-
- /**
- * makes the desired Chart hava a 3D effect
- * where nChart 0= default, 1-9=multiple charts in one
- * sets the group of options necessary to create a 3D chart
- * For Chart Types:
- * BARCHART, COLCHART, LINECHART, PIECHART, AREACHART, BUBBLECHART,
- * PYRAMIDCHART, CYLINDERCHART, CONECHART
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated use setChartType(chartType, nChart, is3d, isStacked,
- * is100%Stacked) instead
- */
- @Deprecated
- public void make3D(int nChart) { // bar, col, line, pie, area, bubble, pyramid, cone, cylinder
- int chartType = this.getChartType(nChart);
- ThreeD td = null;
- switch (chartType) {
- case ChartConstants.COLCHART:
- case ChartConstants.BARCHART:
- td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "20");
- td.setChartOption("ThreeDScaling", "true");
- td.setChartOption("TwoDWalls", "true");
- break;
- case ChartConstants.CYLINDERCHART:
- case ChartConstants.CONECHART:
- case ChartConstants.PYRAMIDCHART:
- td = this.initThreeD(nChart);
- td.setChartOption("Cluster", "false");
- break;
- case ChartConstants.AREACHART:
- this.setChartOption("Percentage", "25", nChart);
- this.setChartOption("SmoothedLine", "true", nChart);
- td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "20");
- td.setChartOption("ThreeDScaling", "true");
- td.setChartOption("TwoDWalls", "true");
- td.setChartOption("Perspective", "true");
- break;
- case ChartConstants.PIECHART:
- case ChartConstants.LINECHART:
- this.initThreeD(nChart); // just create a threeD rec w/ no extra options
- break;
- case ChartConstants.BUBBLECHART:
- this.setChartOption("Percentage", "25", nChart);
- this.setChartOption("SmoothedLine", "true", nChart);
- this.setChartOption("ThreeDBubbles", "true", nChart);
- td = this.initThreeD(nChart); // 20081228 KSC
- break;
- }
- }
-
- // more specialized option sets
- /**
- * makes this Chart Clusted with a 3D effect
- * sets the group of options necessary to create a Clusted 3D chart
- * For Chart Types:
- * BAR, COL
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated
- */
- @Deprecated
- public void makeClustered3D(int nChart) { // only for Column and Bar (?)
- int chartType = this.getChartType(nChart);
- switch (chartType) {
- case ChartConstants.BARCHART:
- case ChartConstants.COLCHART:
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "20");
- td.setChartOption("Cluster", "true");
- td.setChartOption("ThreeDScaling", "true");
- td.setChartOption("TwoDWalls", "true");
- break;
- }
- }
-
- /**
- * makes this chart's wedges exploded i.e. separated
- * For Chart Types:
- * PIECHART, DOUGHNUTCHART
- *
- * @deprecated
- */
- @Deprecated
- public void makeExploded() { // pie, donut
- int chartType = this.getChartType();
- switch (chartType) {
- case ChartConstants.DOUGHNUTCHART:
- this.setChartOption("SmoothedLine", "true");
- case ChartConstants.PIECHART:
- this.setChartOption("ShowLdrLines", "true");
- this.setChartOption("Percentage", "25");
- break;
- // ShowLdrLines="true" Percentage="25"/>
- // exploded donut: ShowLdrLines="true" Donut="50" Percentage="25"
- // SmoothedLine="true"/>
- }
- }
-
- /**
- * makes this chart's wedges exploded 3D i.e. separated with a 3D effect
- * For Chart Types:
- * PIECHART, DOUGHNUTCHART
- *
- * @param nChart
- * number and drawing order of the desired chart (default= 0 max=9
- * where 1-9 indicate an overlay chart)
- * @deprecated
- */
- @Deprecated
- public void makeExploded3D(int nChart) { // pie
- // ShowLdrLines="true" Percentage="25"
- // AnRot="236"
- int chartType = this.getChartType(nChart);
- switch (chartType) {
- case ChartConstants.DOUGHNUTCHART:
- case ChartConstants.PIECHART:
- this.setChartOption("ShowLdrLines", "true", nChart);
- this.setChartOption("Percentage", "25", nChart);
- ThreeD td = this.initThreeD(nChart);
- td.setChartOption("AnRot", "236");
- break;
- }
- }
-
- /*
- * NOT IMPLEMENTED YET TODO: IMPLEMENT Make this Chart have smoothed lines
- * (Scatter only)
- *
- * public void makeSmoothedLines() { // scatter //Percentage="25"
- * SmoothedLine="true }
- *
- * public void makeWireFrame() { // surface // NO ColorFill, only //
- * Percentage="25" SmoothedLine="true" // AnRot="20" Perspective="true"
- * ThreeDScaling="true" TwoDWalls="true"/> // all else should be default for
- * surface charts } public void makeContour() { // surface -- for wireframe
- * surface, no ColorFill //ColorFill="true" Percentage="25"
- * SmoothedLine="true"/> // AnElev="90" pcDist="0" Perspective="true"
- * ThreeDScaling="true" TwoDWalls="true" }
- */
-
- /**
- * set the marker format style for this chart
- * one of:
- * 0 = no marker
- * 1 = square
- * 2 = diamond
- * 3 = triangle
- * 4 = X
- * 5 = star
- * 6 = Dow-Jones
- * 7 = standard deviation
- * 8 = circle
- * 9 = plus sign
- * For Chart Types:
- * LINE, SCATTER
- *
- * @param int
- * imf - marker format constant from list above
- */
- public void setMarkerFormat(int imf) { // line, scatter ...
- this.setChartOption("MarkerFormat", String.valueOf(imf));
- }
-
- /**
- * returs the JSON representation of this chart, based upon
- * Dojo-charting-specifics
- *
- * @return String JSON representation of the chart
- *
- */
- public String getJSON() {
- JSONObject theChart = new JSONObject();
- try {
- JSONObject titles = new JSONObject();
- int type = this.getChartType(); // necessary for parsing AXIS options: horizontal charts "switch" axes ...
-
- // titles/labels
- titles.put("title", this.getTitle());
- titles.put("XAxis", (type != ChartConstants.BARCHART) ? (this.getXAxisLabel()) : this.getYAxisLabel()); // bar
- // axes
- // are
- // reversed
- // ...
- titles.put("YAxis", (type != ChartConstants.BARCHART) ? (this.getYAxisLabel()) : this.getXAxisLabel());
- try {
- titles.put("ZAxis", this.getZAxisLabel());
- } catch (Exception e) {
- Logger.logWarn("ChartHandle.getJSON failed getting zaxislable:" + e.toString());
- }
- theChart.put("titles", titles);
-
- // Chart dimensions (width, height)
- short[] coords = mychart.getCoords();
- theChart.put("width", coords[ChartHandle.WIDTH]);
- theChart.put("height", coords[ChartHandle.HEIGHT]);
- theChart.put("row", mychart.getRow0()); // TODO: may not be necessary, see usage ...
- theChart.put("col", mychart.getCol0());
- // Plot Area Background color
- int plotAreabg = this.getPlotAreaBgColor();
- if (plotAreabg == 0x4D || plotAreabg == 0x4E)
- plotAreabg = FormatConstants.COLOR_WHITE;
- theChart.put("fill", FormatConstants.SVGCOLORSTRINGS[plotAreabg]);
-
- Double[] jMinMax = new Double[3];
- JSONObject chartObjectJSON = this.mychart.getChartObject().getJSON(this.mychart.getChartSeries(), this.wbh,
- jMinMax);
- double yMax = 1.0, yMin = 0.0;
- int nSeries = 0;
- try { // it's possible to not have any series defined ...
- theChart.put("Series", chartObjectJSON.getJSONArray("Series"));
- // 20080416 KSC: Save SeriesJSON for later comparisons
- mychart.setSeriesJSON(chartObjectJSON.getJSONArray("Series"));
- theChart.put("SeriesFills", chartObjectJSON.getJSONArray("SeriesFills")); // 20090729 KSC: capture bar
- // colors or fills
- } catch (Exception e) {
- }
- theChart.put("type", chartObjectJSON.getJSONObject("type"));
- yMin = jMinMax[0].doubleValue();
- yMax = jMinMax[1].doubleValue();
- nSeries = jMinMax[2].intValue();
-
- // Axes + Category Labels + Grid Lines
- try {
- // inputJSONObject(theChart, this.getAxis(YAXIS, false).getJSON(this.wbh, type,
- // yMax, yMin, nSeries));
- theChart.put("y",
- mychart.getAxes().getJSON(YAXIS, this.wbh, type, yMax, yMin, nSeries).getJSONObject("y"));
- theChart.put("back_grid", mychart.getAxes().getJSON(YAXIS, this.wbh, type, yMax, yMin, nSeries)
- .getJSONObject("back_grid"));
- } catch (Exception e) {
- }
- try {
- // inputJSONObject(theChart, this.getAxis(XAXIS, false).getJSON(this.wbh, type,
- // yMax, yMin, nSeries));
- theChart.put("x",
- mychart.getAxes().getJSON(XAXIS, this.wbh, type, yMax, yMin, nSeries).getJSONObject("x"));
- theChart.put("back_grid", mychart.getAxes()
- .getJSON(ChartConstants.YAXIS, this.wbh, type, yMax, yMin, nSeries).getJSONObject("back_grid"));
- } catch (Exception e) {
- }
- // TODO: 3d Charts (z axis)
-
- /*
- * /* Chart Fonts sb.append(t(2) + "" +
- * this.getChartFontRecsXML()); sb.append("\n" + t(2) + " \n");
- * sb.append(t(2) + " \n");
- */
- /*
- * Format Chart Area
- */
- /* TODO: read in legend settings */
-
- // Chart Legend
- if (this.hasDataLegend()) {
- short s = this.mychart.getLegend().getLegendPosition();
- String[] legends = this.mychart.getLegends(-1); // -1 is flag for all rather than for a specific chart
- String l = "";
- for (int i = 0; i < legends.length; i++)
- l += legends[i] + ",";
- if (l.length() > 0)
- l = l.substring(0, l.length() - 1);
- theChart.put("legend", new JSONObject("{position:" + s + ",labels:[" + l + "]}"));
- }
-
- } catch (JSONException e) {
- Logger.logErr("Error getting Chart JSON: " + e);
- }
- return theChart.toString();
- }
-
- /**
- * utility to add a JSON object
- * This is an internal method that is not useful to the end user.
- *
- * @param source
- * @param input
- */
- protected void inputJSONObject(JSONObject source, JSONObject input) {
- if (source != null) {
- try {
- for (int j = 0; j < input.names().length(); j++) {
- source.put(input.names().getString(j), input.get(input.names().getString(j)));
- }
- } catch (JSONException e) {
- Logger.logErr("Error inputting JSON Object: " + e);
- }
- }
- }
-
- /**
- * retrieves the saved Series JSON for comparisons
- * This is an internal method that is not useful to the end user.
- *
- * @return JSONArray
- */
- public JSONArray getSeriesJSON() {
- return mychart.getSeriesJSON();
- }
-
- /**
- * sets the saved Series JSON
- * This is an internal method that is not useful to the end user.
- *
- * @param JSONArray
- * s -
- * @throws JSONException
- */
- public void setSeriesJSON(JSONArray s) throws JSONException {
- mychart.setSeriesJSON(s);
- }
-
- /**
- * retrieves current series and axis scale info in JSONObject form used upon
- * chart updating
- * This is an internal method that is not useful to the end user.
- *
- * @return JSONObject series and axis info
- */
- public JSONObject getCurrentSeries() {
- JSONObject retJSON = new JSONObject();
- // Retrieve series data + yMin yMax, nSeries
- Double[] jMinMax = new Double[3];
- try {
- // Series Data
- // 20080516 KSC: See above JSONObject chartObjectJSON=
- // ((GenericChartObject)this.mychart.getChartObject()).getJSON(
- // this.getAllChartSeriesHandles(), this.getCategories()[0], this.wbh, minMax);
- JSONObject chartObjectJSON = this.mychart.getChartObject().getJSON(this.mychart.getChartSeries(), this.wbh,
- jMinMax);
-
- try {
- retJSON.put("Series", chartObjectJSON.getJSONArray("Series"));
- } catch (Exception e) {
- Logger.logWarn("ChartHandle.getCurrentSeries problem:" + e.toString());
- }
-
- // Retrieve Axis Scale info
- double yMax = 0.0, yMin = 0.0;
- int nSeries = 0;
- yMin = jMinMax[0].doubleValue();
- yMax = jMinMax[1].doubleValue();
- nSeries = jMinMax[2].intValue();
-
- int type = this.getChartType(); // necessary for parsing AXIS options: horizontal charts "switch" axes ...
- // Axes + Category Labels + Grid Lines
- /*
- * KSC: TAKE OUT JSON STUFF FOR NOW; WILL REFACTOR LATER try {
- * inputJSONObject(retJSON, mychart.getAxes().getMinMaxJSON(YAXIS, this.wbh,
- * type, yMax, yMin, nSeries)); } catch (Exception e) { } try {
- * inputJSONObject(retJSON, mychart.getAxes().getMinMaxJSON(XAXIS, this.wbh,
- * type, yMax, yMin, nSeries)); } catch (Exception e) { }
- */
- // TODO: 3d Charts (z axis)
- } catch (JSONException e) {
- Logger.logErr("ChartHandle.getCurrentSeries: Error getting Series JSON: " + e);
- }
- return retJSON;
- }
-
- /**
- * returns a JSON representation of all Series Data (Legend, Categogies, Series
- * Values) for the chart
- * This is an internal method that is not useful to the end user.
- *
- * @return String JSON representation
- */
- public String getAllSeriesDataJSON() {
- JSONArray s = new JSONArray();
- ChartSeriesHandle[] series = this.getAllChartSeriesHandles();
- try {
- for (int i = 0; i < series.length; i++) {
- JSONObject ser = new JSONObject();
- ser.put("l", series[i].getSeriesLegendReference());
- ser.put("v", series[i].getSeriesRange());
- ser.put("b", series[i].getBubbleSizes());
- if (i == 0)
- ser.put("c", series[i].getCategoryRange()); // 1 per chart
- s.put(ser);
- }
- } catch (JSONException e) {
- Logger.logErr("ChartHandle.getAllSeriesDataJSON: " + e);
- }
- return s.toString();
- }
-
- /**
- * Take current Chart object and return the SVG code necessary to define it.
- */
- /**
- * TODO: Less Common Charts: STOCK RADAR SURFACE COLUMN- 3D, CONE, CYLINDER,
- * PYRAMID BAR- 3D, CONE, CYLINDER, PYRAMID 3D PIE 3D LINE 3D AREA
- *
- * LINE CHART APPEARS THAT STARTS AND ENDS A BIT TOO EARLY ***************** Z
- * Axis
- *
- * CHART OPTIONS: STACKED CLUSTERED
- */
- public String getSVG() {
- return getSVG(1);
- }
-
- /**
- * /** Take current Chart object and return the SVG code necessary to define it,
- * scaled to the desired percentage e.g. 0.75= 75%
- *
- * @param scale
- * double scale factor
- * @return String SVG
- */
- public String getSVG(double scale) {
- HashMap chartMetrics = mychart.getMetrics(wbh); // build or retrieve Chart Metrics -->
- // dimensions + series data ...
-
- StringBuffer svg = new StringBuffer();
- // required header
- // svg.append("\r\n"); // referneces
- // the DTD
- // svg.append("\r\n");
-
- // Define SVG Canvas:
- svg.append("\r\n");
- svg.append(""); // scale chart -default scale=1 == 100%
- // JavaScript hooks
- svg.append(getJavaScript());
-
- // Data Legend Box -- do before drawing plot area as legends box may change plot
- // area coordinates
- String legendSVG = getLegendSVG(chartMetrics); // but have to append it after because should overlap the
- // plotarea
-
- String bgclr = this.mychart.getPlotAreaBgColor();
- // setup gradients
- svg.append("");
- svg.append("");
- svg.append(" ");
- svg.append(" ");
- svg.append(" ");
- svg.append(" ");
-
- // PLOT AREA BG + RECT
- // rectangle around entire chart canvas
- if (!(mychart instanceof OOXMLChart) || !((OOXMLChart) mychart).roundedCorners)
- svg.append(" \r\n");
- else // OOXML rounded corners
- svg.append(" \r\n");
-
- // actual plot area
- svg.append(" \r\n");
-
- // AXES, IF PRESENT - DO BEFORE ACTUAL SERIES DATA SO DRAWS CORRECTLY + ADJUST
- // CHART DIMENSIONS
- svg.append(mychart.getAxes().getSVG(XAXIS, chartMetrics, mychart.getChartSeries().getCategories()));
- svg.append(mychart.getAxes().getSVG(YAXIS, chartMetrics, mychart.getChartSeries().getCategories()));
- // TODO: Z Axis
-
- // After Axes and gridlines (if present),
- // ACTUAL bar/series/area/etc. svg generated from series and scale data
- svg.append(this.mychart.getChartObject().getSVG(chartMetrics, mychart.getAxes().getMetrics(),
- mychart.getChartSeries()));
-
- svg.append(legendSVG); // append legend SVG obtained above
-
- // CHART TITLE
-
- if (mychart.getTitleTd() != null)
- svg.append(mychart.getTitleTd().getSVG(chartMetrics));
-
- svg.append(" ");
- svg.append(" ");
- /*
- * //KSC: TESTING: REMOVE WHEN DONE if
- * (WorkBookFactory.PID==WorkBookFactory.E360) { // save svg for testing
- * purposes try { java.io.File f= new java.io.File(
- * "c:/eclipse/workspace/testfiles/io.starter.OpenXLS/output/charts/FromSheetster.svg"
- * ); java.io.FileOutputStream fos= new java.io.FileOutputStream(f);
- * fos.write(svg.toString().getBytes()); fos.flush(); fos.close(); } catch
- * (Exception e) {} }
- */
- return svg.toString();
- }
-
- private String getLegendSVG(HashMap chartMetrics) {
- try {
- return mychart.getLegend().getSVG(chartMetrics, mychart.getChartObject(), mychart.getChartSeries());
- } catch (NullPointerException ne) { // no legend??
- return null;
- }
- }
-
- /**
- * returns the svg for javascript for highlight and restore
- *
- * @return
- */
- protected String getJavaScript() {
- StringBuffer svg = new StringBuffer();
- svg.append("");
- return svg.toString();
- }
-
- /**
- * debugging utility remove when done
- */
- public void WriteMainChartRecs(String fName) {
- mychart.getChartObject().WriteMainChartRecs(fName);
- }
-}
diff --git a/src/main/java/io/starter/OpenXLS/ChartHandle.kt b/src/main/java/io/starter/OpenXLS/ChartHandle.kt
new file mode 100644
index 0000000..ea72834
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ChartHandle.kt
@@ -0,0 +1,3927 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or
+ * modify
+ * it under the terms of the GNU Lesser General Public
+ * License as
+ * published by the Free Software Foundation, either version
+ * 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be
+ * useful,
+ * but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.OOXML.*
+import io.starter.formats.XLS.*
+import io.starter.formats.XLS.charts.*
+import io.starter.toolkit.Logger
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserFactory
+
+import java.util.ArrayList
+import java.util.EnumSet
+import java.util.HashMap
+import java.util.Vector
+
+/**
+ * Chart Handle allows for manipulation of Charts within a WorkBook.
+ * Allows for run-time modification of Chart titles, labels, categories, and
+ * data Cells.
+ * Modification of Chart data cells allows you to completely modify the data
+ * shown on the Chart.
+ *
+ * To create a new chart and add to a worksheet, use:
+ * ChartHandle.createNewChart(sheet, charttype, chartoptions).
+ *
+ * To Obtain an array of existing chart handles, use
+ * WorkBookHandle.getCharts()
+ * or WorkBookHandle.getCharts(chart title)
+ *
+ * [Starter Inc.](http://starter.io)
+ *
+ * @see WorkBookHandle
+ */
+class ChartHandle
+/**
+ * Constructor which creates a new ChartHandle from an existing Chart Object
+ *
+ * @param Chart c - the source Chart object
+ * @param WorkBookHandle wb - the parent WorkBookHandle
+ */
+(private var mychart: Chart?, wb: WorkBookHandle) : ChartConstants {
+
+ var workBookHandle: WorkBookHandle
+ protected set
+
+ /**
+ * Returns the title of the Chart
+ *
+ * @return String title of the Chart
+ */
+ /**
+ * Sets the title of the Chart
+ *
+ * @param String title - Chart title
+ */
+ var title: String?
+ get() = mychart!!.title
+ set(title) {
+ this.mychart!!.title = title
+ }
+
+ /**
+ * returns the data range used by the chart
+ *
+ * @return
+ */
+ val dataRangeJSON: String
+ get() = this.mychart!!.chartSeries.dataRangeJSON.toString()
+
+ val encompassingDataRange: IntArray?
+ get() = getEncompassingDataRange(this.mychart!!.chartSeries
+ .dataRangeJSON)
+
+ /**
+ * returns the ordinal id associated with the underlying Chart Object
+ *
+ * @return int chart id
+ * @see WorkBookHandle.getChartById
+ */
+ val id: Int
+ get() = this.mychart!!.id
+
+ /** */
+ /**
+ * Returns an ordered array of strings representing all the series ranges in the
+ * Chart.
+ * Each series can only represent one bar, line or wedge of data.
+ *
+ * @return String[] each item being a Cell Range representing one bar, line or
+ * wedge of data in the Chart
+ * @see ChartHandle.getCategories
+ */
+ // -1 is flag for all rather than for a
+ // specific chart
+ val series: Array
+ get() = mychart!!.getSeries(-1)
+
+ /**
+ * Returns an ordered array of strings representing all the category ranges in
+ * the chart.
+ * This vector corresponds to the getSeries() method so will often contain
+ * duplicates, as while the series data changes frequently, category data is the
+ * same throughout the chart.
+ *
+ * @return String[] each item being a Cell Range representing the Category Data
+ * @see ChartHandle.getSeries
+ */
+ // -1 is flag for all rather than for a
+ // specific chart
+ val categories: Array
+ get() = getCategories(-1)
+
+ /**
+ * Returns an array of ChartSeriesHandle Objects, one for each bar, line or
+ * wedge of data.
+ *
+ * @return ChartSeriesHandle[] Array of ChartSeriesHandle Objects representing
+ * Chart Series Data (Series and Categories)
+ * @see ChartSeriesHandle
+ */
+ // get ALL
+ val allChartSeriesHandles: Array
+ get() = getAllChartSeriesHandles(-1)
+
+ /**
+ * returns the Y axis Title
+ *
+ * @return String title
+ */
+ /**
+ * Sets the Y axis Title
+ *
+ * @param String yTitle - new Y Axis title
+ */
+ var yAxisLabel: String
+ get() = mychart!!.axes!!.getTitle(YAXIS)
+ set(yTitle) = mychart!!.axes!!.setTitle(YAXIS, yTitle)
+
+ /**
+ * returns the X axis Title
+ *
+ * @return String title
+ */
+ /**
+ * Sets the XAxisTitle
+ *
+ * @param String xTitle - new X Axis title
+ */
+ var xAxisLabel: String
+ get() = mychart!!.axes!!.getTitle(XAXIS)
+ set(xTitle) = mychart!!.axes!!.setTitle(XAXIS, xTitle)
+
+ /**
+ * returns the Z axis Title, if any
+ *
+ * @return String Title
+ */
+ /**
+ * set the Z AxisTitle
+ *
+ * @param String zTitle - new Z Axis Title
+ */
+ var zAxisLabel: String
+ get() = mychart!!.axes!!.getTitle(ZAXIS)
+ set(zTitle) = mychart!!.axes!!.setTitle(ZAXIS, zTitle)
+
+ /**
+ * Returns true if the Y Axis (Value axis) is set to automatic scale
+ *
+ *
+ * The default setting for charts is known as Automatic Scaling
+ * When data changes, the chart automatically adjusts the scale (minimum,
+ * maximum values plus major and minor tick units) as necessary
+ *
+ * @return boolean true if Automatic Scaling is turned on
+ * @see getAxisAutomaticScale
+ */
+ /**
+ * Sets the automatic scale option on or off for the Y Axis (Value axis)
+ *
+ *
+ * Automatic Scaling will automatically set the scale maximum, minimum and tick
+ * units upon data changes, and is the default chart setting
+ *
+ * @param b
+ * @see setAxisAutomaticScale
+ */
+ var axisAutomaticScale: Boolean
+ get() = mychart!!.axisAutomaticScale
+ set(b) {
+ mychart!!.axes!!.axisAutomaticScale = b
+ mychart!!.setDirtyFlag(true)
+ }
+
+ /**
+ * Returns the minimum value of the Y Axis (Value Axis) scale
+ *
+ * @return int Miminum Scale value for Y axis
+ * @see getAxisMinScale
+ */
+ // -1 is flag for all
+ // rather than for a
+ // specific chart
+ val axisMinScale: Double
+ get() {
+ val minmax = mychart!!.getMinMax(this.workBookHandle)
+ return mychart!!.axes!!.getMinMax(minmax[0], minmax[1])[0]
+ }
+
+ /**
+ * Returns the maximum value of the Y Axis (Value Axis) scale
+ *
+ * @return int Maximum Scale value for Y axis
+ * @see getAxisMaxScale
+ */
+ val axisMaxScale: Double
+ get() {
+ val minmax = mychart!!.getMinMax(this.workBookHandle)
+ return mychart!!.axes!!.getMinMax(minmax[0], minmax[1])[1]
+ }
+
+ /**
+ * Returns the major tick unit of the Y Axis (Value Axis)
+ *
+ * @return int major tick unit
+ * @see getAxisMajorUnit
+ */
+ val axisMajorUnit: Int
+ get() {
+ val minmax = mychart!!.getMinMax(this.workBookHandle)
+ return mychart!!.axes!!.getMinMax(minmax[0], minmax[1])[2].toInt()
+ }
+
+ /**
+ * Returns the minor tick unit of the Y Axis (Value Axis)
+ *
+ * @return int minor tick unit
+ * @see getAxisMinorUnit
+ */
+ val axisMinorUnit: Int
+ get() {
+ val minmax = mychart!!.getMinMax(this.workBookHandle)
+ return mychart!!.axes!!.getMinMax(minmax[0], minmax[1])[1].toInt()
+ }
+
+ /**
+ * returns the Font associated with the Chart Title
+ *
+ * @return io.starter.Formats.XLS.Font
+ * @see Font
+ */
+ /**
+ * set the font for the Chart Title
+ *
+ * @param io.starter.Formats.XLS.Font f - desired font for the Chart Title
+ * @see Font
+ */
+ // font doesn't exist yet, add to streamer
+ // flag to insert
+ var titleFont: Font?
+ get() = mychart!!.titleFont
+ set(f) {
+ var idx = workBookHandle.workBook!!.getFontIdx(f)
+ if (idx == -1) {
+ f.idx = -1
+ idx = workBookHandle.workBook!!.insertFont(f) + 1
+ }
+ mychart!!.setTitleFont(idx)
+ }
+
+ /**
+ * return the Font associated with the Chart Axes
+ *
+ * @return io.starter.Formats.XLS.Font for Chart Axes or null if no axes
+ * @see Font
+ */
+ /**
+ * set the font for all axes on the Chart
+ *
+ * @param io.starter.Formats.XLS.Font f - desired font for the Chart axes
+ * @see Font
+ */
+ // font doesn't exist yet, add to streamer
+ // flag to insert
+ var axisFont: Font?
+ get() {
+ var f: Font? = null
+ f = mychart!!.axes!!.getTitleFont(XAXIS)
+ if (f != null)
+ return f
+ f = mychart!!.axes!!.getTitleFont(YAXIS)
+ if (f != null)
+ return f
+ f = mychart!!.axes!!.getTitleFont(ZAXIS)
+ return f
+ }
+ set(f) {
+ var idx = workBookHandle.workBook!!.getFontIdx(f)
+ if (idx == -1) {
+ f.idx = -1
+ idx = workBookHandle.workBook!!.insertFont(f) + 1
+ }
+ mychart!!.axes!!.setTitleFont(XAXIS, idx)
+ mychart!!.axes!!.setTitleFont(YAXIS, idx)
+ mychart!!.axes!!.setTitleFont(ZAXIS, idx)
+ mychart!!.setDirtyFlag(true)
+ }
+
+ /**
+ * returns the underlhying Sheet Object this Chart is attached to
+ * For Internal Use
+ *
+ * @return Boundsheet
+ */
+ val sheet: Boundsheet?
+ get() = mychart!!.sheet
+
+ /**
+ * return the background color of this chart's Plot Area as an int
+ *
+ * @return int background color constant
+ * @see FormatHandle.COLOR_* constants
+ */
+ /**
+ * sets the Plot Area background color
+ *
+ * @param int bg - color constant
+ * @see FormatHandle.COLOR_* constants
+ */
+ var plotAreaBgColor: Int
+ get() {
+ val bg = mychart!!.plotAreaBgColor
+ return FormatHandle.HexStringToColorInt(bg, 0.toShort())
+ }
+ set(bg) = mychart!!.setPlotAreaBgColor(bg)
+
+ val plotAreaBgColorStr: String
+ get() = mychart!!.plotAreaBgColor
+
+ /**
+ * Return an int corresponding to this ChartHandle's Chart Type for the default
+ * chart
+ * To see possible Chart Types, view the public static int's in ChartHandle.
+ *
+ * @return int chart type
+ * @see ChartHandle static Chart Type Constants
+ *
+ * @see ChartHandle.setChartType
+ */
+ /**
+ * Sets the Chart type to the specified basic type (no 3d, no stacked ...)
+ * To see possible Chart Types, view the public static int's in ChartHandle.
+ *
+ * Possible Chart Types:
+ * BARCHART
+ * COLCHART
+ * LINECHART
+ * PIECHART
+ * AREACHART
+ * SCATTERCHART
+ * RADARCHART
+ * SURFACECHART
+ * DOUGHNUTCHART
+ * BUBBLECHART
+ * RADARAREACHART
+ * PYRAMIDCHART
+ * CYLINDERCHART
+ * CONECHART
+ * PYRAMIDBARCHART
+ * CYLINDERBARCHART
+ * CONEBAR
+ *
+ * @param int chartType - representing the chart type
+ */
+ // no
+ // specific
+ // options
+ var chartType: Int
+ get() = mychart!!.chartType
+ set(chartType) = mychart!!.setChartType(chartType, 0, EnumSet.noneOf(ChartOptions::class.java))
+
+ /*
+ * NOT IMPLEMENTED YET adjust chart cell references upon row
+ * insertion or
+ * deletion NOTE: Assumes we're on the correct sheet NOT
+ * COMPLETELY IMPLEMENTED
+ * YEt
+ *
+ * @param rownum
+ *
+ * @param shiftamt +1= insert row, -1= delete row
+ *
+ * public void adjustCellRefs(int rownum, int shiftamt) {
+ * Vector v =
+ * mychart.getAllSeries(); boolean bSeriesRows= false;
+ * boolean bMod= false; for
+ * (int i=0;i 0) { //
+ * insert row i.e.
+ * shift ai location down if ((loc.length==2 &&
+ * loc[0]>=rownum) ||
+ * (loc[0]>=rownum || loc[2]>=rownum)) {
+ * adjustAiLocation(ai,
+ * p[0].getIntLocation(), shiftamt); bMod= true; } } else {
+ * if ((loc.length==2
+ * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum))
+ * { // remove it
+ * this.removeSeries(i); bMod= true; continue; } } }
+ * catch(Exception e) {
+ *
+ * } } catch (Exception e) {
+ *
+ * } try { // CATEGORY Ai ai= s.getCategoryValueAi(); Ptg[]
+ * p=ai.getCellRangePtgs(); try { int[] loc=
+ * p[0].getIntLocation(); if (shiftamt
+ * > 0) { // insert row i.e. shift ai location down if
+ * ((loc.length==2 &&
+ * loc[0]>=rownum) || (loc[0]>=rownum || loc[2]>=rownum)) {
+ * adjustAiLocation(ai,
+ * p[0].getIntLocation(), shiftamt); bMod= true; } } else {
+ * if ((loc.length==2
+ * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum))
+ * { // remove it ????
+ * this.removeSeries(i); bMod= true; } } } catch(Exception
+ * e) {
+ *
+ * } } catch (Exception e) {
+ *
+ * } try { // LEGEND Ai ai= s.getLegendAi(); Ptg[]
+ * p=ai.getCellRangePtgs();
+ * int[] loc= p[0].getIntLocation(); if (shiftamt > 0) { //
+ * insert row i.e.
+ * shift ai location down if ((loc.length==2 &&
+ * loc[0]>=rownum) ||
+ * (loc[0]>=rownum || loc[2]>=rownum)) {
+ * adjustAiLocation(ai,
+ * p[0].getIntLocation(), shiftamt); bMod= true; } } else {
+ * if ((loc.length==2
+ * && loc[0]==rownum) || (loc[0]>=rownum && loc[2]<=rownum))
+ * { // remove it
+ * this.removeSeries(i); bMod= true; } } } catch(Exception
+ * e) {
+ *
+ * } } if (bMod)// one or more series elements were modified
+ * setDimensionsRecord(); // update dimensions i.e. Data
+ * Range
+ *
+ * }
+ */
+
+ /*
+ * doesn't appear to be used right now move the ai location
+ * (row) according to
+ * shift amount
+ *
+ * @param ai
+ *
+ * @param loc
+ *
+ * @param shift
+ *
+ * private void adjustAiLocation(Ai ai, int[] loc, int
+ * shift) { String oldloc=
+ * ExcelTools.formatLocation(loc); if (loc.length>2) // get
+ * 2nd part of range
+ * oldloc += ":" + ExcelTools.formatLocation(new
+ * int[]{loc[2], loc[3]}); oldloc=
+ * this.getSheet().getSheetName() + "!" + oldloc; if
+ * (loc.length==2)// single
+ * cell loc[0]+=shift; else { // range loc[0]+=shift;
+ * loc[2]+=shift; } String
+ * newloc= ExcelTools.formatLocation(loc); if (loc.length>2)
+ * // get 2nd part of
+ * range newloc += ":" + ExcelTools.formatLocation(new
+ * int[]{loc[2], loc[3]});
+ * ai.changeAiLocation(oldloc, newloc); }
+ *
+ */
+
+ /**
+ * Get the Chart's bytes
+ *
+ *
+ * This is an internal method that is not useful to the end user.
+ */
+ val chartBytes: ByteArray?
+ get() = mychart!!.chartBytes
+
+ val serialBytes: ByteArray?
+ get() = mychart!!.serialBytes
+
+ /**
+ * get the chart-type-specific options in XML form
+ *
+ * @return String XML
+ */
+ private// 0 for default chart
+ val chartOptionsXML: String
+ get() = mychart!!.getChartOptionsXML(0)
+
+ /**
+ * returns an XML representation of this chart
+ *
+ * @return String XML
+ */
+ // Chart Name (=Title)
+ // Type
+ // Plot Area Background color 20080429 KSC
+ // Position
+ // Chart Fonts
+ // Format Chart Area
+ // KSC: TODO: BORDER
+ // TODO:
+ // Properties
+ // Source Data
+ // controls shape of complex datapoints such as pyramid,
+ // cylinder, cone +
+ // stacked 3d bars
+ // Chart Options
+ // Axis Options
+ // ThreeD rec opts
+ val xml: String
+ get() {
+ val sb = StringBuffer(t(1) + "\n")
+ sb.append(t(2) + "" + this.chartFontRecsXML)
+ sb.append("\n" + t(2) + " \n")
+ sb.append(t(2) + " \n")
+ sb.append(t(2) + "\n")
+ sb.append(t(3) + " \n")
+ sb.append(t(3) + " \n")
+ sb.append(t(2) + " \n")
+ sb.append(t(2) + "\n")
+ val series = this.allChartSeriesHandles
+ for (i in series.indices) {
+ sb.append(t(3) + " \n")
+ }
+ sb.append(t(2) + " \n")
+ sb.append(t(2) + " \n")
+ sb.append(t(2) + "\n")
+ sb.append(t(3) + " \n")
+ sb.append(t(3) + " \n")
+ sb.append(t(3) + " \n")
+ sb.append(t(2) + " \n")
+ if (this.isThreeD) {
+ sb.append(t(2) + " \n")
+ }
+
+ sb.append(t(1) + " \n")
+ return sb.toString()
+ }
+
+ /**
+ * return the Excel 7/OOXML-specific name for this chart
+ *
+ * @return String OOXML name
+ */
+ /**
+ * set the Excel 7/OOXML-specific name for this chart
+ *
+ * @param String name
+ */
+ private var ooxmlName: String?
+ get() = (mychart as OOXMLChart).ooxmlName
+ set(name) {
+ (mychart as OOXMLChart).ooxmlName = name
+ }
+
+ /**
+ * returns the drawingml file name which defines the userShape (if any)
+ * a userShape is a drawing or shape ontop of a chart associated with this chart
+ *
+ * @return
+ */
+ val chartEmbeds: ArrayList<*>?
+ get() = (mychart as OOXMLChart).chartEmbeds
+
+ /**
+ * @return true if Chart has 3D effects, false otherwise
+ */
+ // default chart
+ val isThreeD: Boolean
+ get() = mychart!!.isThreeD(0)
+
+ /**
+ * @return boolean true if Chart contains Stacked Series, false otherwise
+ */
+ // default chart
+ val isStacked: Boolean
+ get() = mychart!!.isStacked(0)
+
+ /**
+ * @return boolean true if Chart is of type 100% Stacked, false otherwise
+ */
+ // default chart
+ val is100PercentStacked: Boolean
+ get() = mychart!!.is100PercentStacked(0)
+
+ /**
+ * @return boolean true if Chart contains Clustered Bars or Columns, false
+ * otherwise
+ */
+ // default chart
+ val isClustered: Boolean
+ get() = mychart!!.isClustered(0)
+
+ /**
+ * @return String ThreeD options in XML form
+ */
+ // 0 for default chart
+ val threeDXML: String
+ get() = mychart!!.getThreeDXML(0)
+
+ /**
+ * returns Chart-specific Font Records in XML form
+ *
+ * @return String Chart Font information in XML format
+ */
+ val chartFontRecsXML: String
+ get() = mychart!!.chartFontRecsXML
+
+ /**
+ * Return non-axis Chart font ids in XML form
+ *
+ * @return String Font information in XML format
+ */
+ val chartFontsXML: String
+ get() = mychart!!.chartFontsXML
+
+ /**
+ * @return the WorkBook Object attached to this Chart
+ */
+ val workBook: io.starter.formats.XLS.WorkBook?
+ get() = mychart!!.workBook
+
+ // this should be impossible
+ val workSheetHandle: WorkSheetHandle
+ get() {
+ try {
+ return this.workBookHandle.getWorkSheet(mychart!!.sheet!!.sheetNum)
+ } catch (e: WorkSheetNotFoundException) {
+ throw RuntimeException(e)
+ }
+
+ }
+
+ /**
+ * returns the coordinates or bounds (position, width and height) of this chart
+ * in pixels
+ *
+ * @return short[4] bounds - left or x value, top or y value, width, height
+ * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
+ */
+ // NOTE: THIS SHOULD BE RENAMED TO setCoords as Bounds and
+ // Coords are very
+ // distinct
+ /**
+ * sets the coordinates or bounds (position, width and height) of this chart in
+ * pixels
+ *
+ * @param short[4] bounds - left or x value, top or y value, width, height
+ * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
+ */
+ // NOTE: THIS SHOULD BE RENAMED TO setCoords as Bounds and
+ // Coords are very
+ // distinct
+ var bounds: ShortArray
+ get() = mychart!!.coords
+ set(bounds) {
+ mychart!!.coords = bounds
+ }
+
+ /**
+ * returns the coordinates (position, width and height) of this chart in Excel
+ * size units
+ *
+ * @return short[4] pixel coords - left or x value, top or y value, width,
+ * height
+ * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
+ */
+ /**
+ * sets the coordinates (position, width and height) for this chart in Excel
+ * size units
+ *
+ * @return short[4] pixel coords - left or x value, top or y value, width,
+ * height
+ * @see ChartHandle.X, ChartHandle.Y, ChartHandle.WIDTH, ChartHandle.HEIGHT
+ */
+ var coords: ShortArray
+ get() {
+ mychart!!.getMetrics(this.workBookHandle)
+ return mychart!!.coords
+ }
+ set(coords) {
+ mychart!!.coords = coords
+ }
+
+ /**
+ * get the bounds of the chart using coordinates relative to row/cols and their
+ * offsets
+ *
+ * @return short[8] bounds - COL, COLOFFSET, ROW, ROWOFFST, COL1, COLOFFSET1,
+ * ROW1, ROWOFFSET1
+ */
+ /**
+ * sets the bounds of the chart using coordinates relative to row/cols and their
+ * offsets
+ *
+ * @param short[8] bounds - COL, COLOFFSET, ROW, ROWOFFST, COL1, COLOFFSET1, ROW1,
+ * ROWOFFSET1
+ */
+ var relativeBounds: ShortArray?
+ get() = mychart!!.bounds
+ set(bounds) {
+ mychart!!.bounds = bounds
+ }
+
+ /**
+ * returns the offset within the column in pixels
+ *
+ * @return
+ */
+ val colOffset: Short
+ get() = mychart!!.colOffset
+
+/**
+ * returs the JSON representation of this chart, based upon
+ * Dojo-charting-specifics
+ *
+ * @return String JSON representation of the chart
+ */
+// necessary for parsing AXIS
+// options: horizontal charts
+// "switch" axes ...
+// titles/labels
+// bar
+// axes
+// are
+// reversed
+// ...
+// Chart dimensions (width, height)
+// TODO: may not be
+// necessary, see usage ...
+// Plot Area Background color
+// it's possible to not have any series defined ...
+// 20080416 KSC: Save SeriesJSON for later comparisons
+// 20090729 KSC: capture
+// bar
+// colors or fills
+// Axes + Category Labels + Grid Lines
+// inputJSONObject(theChart, this.getAxis(YAXIS,
+// false).getJSON(this.wbh, type,
+// yMax, yMin, nSeries));
+// inputJSONObject(theChart, this.getAxis(XAXIS,
+// false).getJSON(this.wbh, type,
+// yMax, yMin, nSeries));
+// TODO: 3d Charts (z axis)
+/*
+ * /* Chart Fonts sb.append(t(2) + "" +
+ * this.getChartFontRecsXML()); sb.append("\n" + t(2) +
+ * " \n");
+ * sb.append(t(2) + " \n");
+ *//*
+ * Format Chart Area
+ *//* TODO: read in legend settings */// Chart Legend
+ // -1 is flag
+ // for all
+ // rather than
+ // for a
+ // specific
+ // chart
+ val json:String
+get() {
+val theChart = JSONObject()
+try
+{
+val titles = JSONObject()
+val type = this.chartType
+titles.put("title", this.title)
+titles.put("XAxis", if ((type != ChartConstants.BARCHART))
+(this.xAxisLabel)
+else
+this.yAxisLabel)
+titles.put("YAxis", if ((type != ChartConstants.BARCHART))
+(this.yAxisLabel)
+else
+this.xAxisLabel)
+try
+{
+titles.put("ZAxis", this.zAxisLabel)
+}
+catch (e:Exception) {
+Logger.logWarn(("ChartHandle.getJSON failed getting zaxislable:" + e.toString()))
+}
+
+theChart.put("titles", titles)
+val coords = mychart!!.coords
+theChart.put("width", coords[ChartHandle.WIDTH].toInt())
+theChart.put("height", coords[ChartHandle.HEIGHT].toInt())
+theChart.put("row", mychart!!.row0)
+theChart.put("col", mychart!!.col0)
+var plotAreabg = this.plotAreaBgColor
+if (plotAreabg == 0x4D || plotAreabg == 0x4E)
+plotAreabg = FormatConstants.COLOR_WHITE
+theChart.put("fill", FormatConstants.SVGCOLORSTRINGS[plotAreabg])
+
+val jMinMax = arrayOfNulls(3)
+val chartObjectJSON = this.mychart!!.chartObject
+.getJSON(this.mychart!!.chartSeries, this.workBookHandle, jMinMax)
+var yMax = 1.0
+var yMin = 0.0
+var nSeries = 0
+try
+{
+theChart.put("Series", chartObjectJSON.getJSONArray("Series"))
+mychart!!.seriesJSON = chartObjectJSON.getJSONArray("Series")
+theChart.put("SeriesFills", chartObjectJSON
+.getJSONArray("SeriesFills"))
+}
+catch (e:Exception) {}
+
+theChart.put("type", chartObjectJSON.getJSONObject("type"))
+yMin = jMinMax[0].toDouble()
+yMax = jMinMax[1].toDouble()
+nSeries = jMinMax[2].toInt()
+try
+{
+theChart.put("y", mychart!!.axes!!
+.getJSON(YAXIS, this.workBookHandle, type, yMax, yMin, nSeries)
+.getJSONObject("y"))
+theChart.put("back_grid", mychart!!.axes!!
+.getJSON(YAXIS, this.workBookHandle, type, yMax, yMin, nSeries)
+.getJSONObject("back_grid"))
+}
+catch (e:Exception) {}
+
+try
+{
+theChart.put("x", mychart!!.axes!!
+.getJSON(XAXIS, this.workBookHandle, type, yMax, yMin, nSeries)
+.getJSONObject("x"))
+theChart.put("back_grid", mychart!!.axes!!
+.getJSON(ChartConstants.YAXIS, this.workBookHandle, type, yMax, yMin, nSeries)
+.getJSONObject("back_grid"))
+}
+catch (e:Exception) {}
+
+if (this.hasDataLegend())
+{
+val s = this.mychart!!.legend!!.legendPosition
+val legends = this.mychart!!.getLegends(-1)
+var l = ""
+for (i in legends.indices)
+l += legends[i] + ","
+if (l.length > 0)
+l = l.substring(0, l.length - 1)
+theChart.put("legend", JSONObject(
+"{position:" + s + ",labels:[" + l + "]}"))
+}
+
+}
+catch (e:JSONException) {
+Logger.logErr("Error getting Chart JSON: " + e)
+}
+
+return theChart.toString()
+}
+
+/**
+ * retrieves the saved Series JSON for comparisons
+ * This is an internal method that is not useful to the end user.
+ *
+ * @return JSONArray
+ */
+ /**
+ * sets the saved Series JSON
+ * This is an internal method that is not useful to the end user.
+ *
+ * @param JSONArray s -
+ * @throws JSONException
+ */
+ var seriesJSON:JSONArray?
+get() {
+return mychart!!.seriesJSON
+}
+@Throws(JSONException::class)
+set(s) {
+mychart!!.seriesJSON = s
+}
+
+/**
+ * retrieves current series and axis scale info in JSONObject form used upon
+ * chart updating
+ * This is an internal method that is not useful to the end user.
+ *
+ * @return JSONObject series and axis info
+ */
+ // Retrieve series data + yMin yMax, nSeries
+ // Series Data
+ // 20080516 KSC: See above JSONObject chartObjectJSON=
+ // ((GenericChartObject)this.mychart.getChartObject()).getJSON(
+ // this.getAllChartSeriesHandles(), this.getCategories()[0],
+ // this.wbh, minMax);
+ // Retrieve Axis Scale info
+ // necessary for parsing AXIS
+ // options: horizontal charts
+ // "switch" axes ...
+ // Axes + Category Labels + Grid Lines
+ /*
+ * KSC: TAKE OUT JSON STUFF FOR NOW; WILL REFACTOR LATER try
+ * {
+ * inputJSONObject(retJSON,
+ * mychart.getAxes().getMinMaxJSON(YAXIS, this.wbh,
+ * type, yMax, yMin, nSeries)); } catch (Exception e) { }
+ * try {
+ * inputJSONObject(retJSON,
+ * mychart.getAxes().getMinMaxJSON(XAXIS, this.wbh,
+ * type, yMax, yMin, nSeries)); } catch (Exception e) { }
+ */// TODO: 3d Charts (z axis)
+ val currentSeries:JSONObject
+get() {
+val retJSON = JSONObject()
+val jMinMax = arrayOfNulls(3)
+try
+{
+val chartObjectJSON = this.mychart!!.chartObject
+.getJSON(this.mychart!!.chartSeries, this.workBookHandle, jMinMax)
+
+try
+{
+retJSON.put("Series", chartObjectJSON.getJSONArray("Series"))
+}
+catch (e:Exception) {
+Logger.logWarn(("ChartHandle.getCurrentSeries problem:" + e.toString()))
+}
+
+var yMax = 0.0
+var yMin = 0.0
+var nSeries = 0
+yMin = jMinMax[0].toDouble()
+yMax = jMinMax[1].toDouble()
+nSeries = jMinMax[2].toInt()
+
+val type = this.chartType
+}
+catch (e:JSONException) {
+Logger.logErr(("ChartHandle.getCurrentSeries: Error getting Series JSON: " + e))
+}
+
+return retJSON
+}
+
+/**
+ * returns a JSON representation of all Series Data (Legend, Categogies, Series
+ * Values) for the chart
+ * This is an internal method that is not useful to the end user.
+ *
+ * @return String JSON representation
+ */
+ // 1 per chart
+ val allSeriesDataJSON:String
+get() {
+val s = JSONArray()
+val series = this.allChartSeriesHandles
+try
+{
+for (i in series.indices)
+{
+val ser = JSONObject()
+ser.put("l", series[i].seriesLegendReference)
+ser.put("v", series[i].seriesRange)
+ser.put("b", series[i].bubbleSizes)
+if (i == 0)
+ser.put("c", series[i].categoryRange)
+s.put(ser)
+}
+}
+catch (e:JSONException) {
+Logger.logErr("ChartHandle.getAllSeriesDataJSON: " + e)
+}
+
+return s.toString()
+}
+
+/**
+ * Take current Chart object and return the SVG code necessary to define it.
+ */
+ /**
+ * TODO: Less Common Charts: STOCK RADAR SURFACE COLUMN- 3D, CONE, CYLINDER,
+ * PYRAMID BAR- 3D, CONE, CYLINDER, PYRAMID 3D PIE 3D LINE 3D AREA
+ *
+ *
+ * LINE CHART APPEARS THAT STARTS AND ENDS A BIT TOO EARLY ***************** Z
+ * Axis
+ *
+ *
+ * CHART OPTIONS: STACKED CLUSTERED
+ */
+ val svg:String
+get() {
+return getSVG(1.0)
+}
+
+/**
+ * returns the svg for javascript for highlight and restore
+ *
+ * @return
+ */
+ protected// rgb('+
+ // red
+ // +','+
+ // green+','+blue+')');");
+ // svg.append("evt.target.setAttributeNS(null,'stroke-color','white');");
+ // rgb('+
+ // red
+ // +','+
+ // green+','+blue+')');");
+ // svg.append("try{parent.parent.uiWindowing.getActiveSheet().book.handleMouseClick(evt);}catch(x){;}");
+ val javaScript:String
+get() {
+val svg = StringBuffer()
+svg.append("")
+return svg.toString()
+}
+
+init{
+workBookHandle = wb
+if (mychart!!.workBook == null)
+ // TODO: WHY IS THIS NULL????
+ mychart!!.workBook = wb.workBook
+}// super();
+
+/**
+ * returns the string representation of this ChartHandle
+ */
+ public override fun toString():String {
+return mychart!!.title
+}
+
+/**
+ * Returns an ordered array of strings representing all the category ranges in
+ * the chart.
+ * This vector corresponds to the getSeries() method so will often contain
+ * duplicates, as while the series data changes frequently, category data is the
+ * same throughout the chart.
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return String[] each item being a Cell Range representing the Category Data
+ * @see ChartHandle.getSeries
+ */
+ private fun getCategories(nChart:Int):Array {
+return mychart!!.getCategories(nChart)
+}
+
+/**
+ * Returns an array of ChartSeriesHandle Objects for the desired chart, one for
+ * each bar, line or wedge of data.
+ * A chart number of 0 means the default chart, 1-9 indicate series for overlay
+ * charts
+ * NOTE: using this method returns the series for the desired chart ONLY
+ * You MUST use the corresponding removeSeries(index, nChart) when removing
+ * series to properly match the series index. Otherwise a mismatch will occur.
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ChartSeriesHandle[] Array of ChartSeriesHandle Objects representing
+ * Chart Series Data (Series and Categories)
+ * @see ChartSeriesHandle
+ */
+ fun getAllChartSeriesHandles(nChart:Int):Array {
+val v = mychart!!.getAllSeries(nChart)
+val csh = arrayOfNulls(v.size)
+for (i in v.indices)
+{
+val s = v.get(i) as Series
+csh[i] = ChartSeriesHandle(s, this.workBookHandle)
+}
+return csh
+}
+
+/**
+ * Get the ChartSeriesHandle representing Chart Series Data (Series and
+ * Categories) for the specified Series range
+ *
+ * @param String seriesRange - For example, "Sheet1!A12:A21"
+ * @return ChartSeriesHandle
+ * @see ChartSeriesHandle
+ */
+ fun getChartSeriesHandle(seriesRange:String):ChartSeriesHandle? {
+val series = this.allChartSeriesHandles
+for (i in series.indices)
+{
+val sr = series[i].seriesRange
+if (seriesRange.equals(sr, ignoreCase = true))
+{
+return series[i]
+}
+}
+return null
+}
+
+/**
+ * Get the ChartSeriesHandle representing Chart Series Data (Series and
+ * Categories) for the specified Series index
+ *
+ * @param int idx - the index (0 based) of the series
+ * @return ChartSeriesHandle
+ * @see ChartSeriesHandle
+ */
+ fun getChartSeriesHandle(idx:Int):ChartSeriesHandle? {
+val series = this.allChartSeriesHandles
+if (series.size >= idx)
+return series[idx]
+return null
+}
+
+/**
+ * Get the ChartSeriesHandle representing Chart Series Data (Series and
+ * Categories) for the Series specified by label (legend)
+ *
+ * @param String legend - label for the desired series
+ * @return ChartSeriesHandle
+ * @see ChartSeriesHandle
+ */
+ fun getChartSeriesHandleByName(legend:String):ChartSeriesHandle {
+val s = mychart!!.getSeries(legend, -1) // -1 is flag for all rather
+ // than for a specific chart
+ return ChartSeriesHandle(s, this.workBookHandle)
+}
+
+/**
+ * sets or removes the axis title
+ *
+ * @param axisType one of: XAXIS, YAXIS, ZAXIS
+ * @param ttl String new title or null to remove
+ */
+ fun setAxisTitle(axisType:Int, ttl:String) {
+mychart!!.axes!!.setTitle(axisType, ttl)
+}
+
+/**
+ * Sets the automatic scale option on or off for the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ *
+ * Automatic Scaling automatically sets the scale maximum, minimum and tick
+ * units upon data changes, and is the default setting for charts
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @param boolean b - true if set Automatic scaling on, false otherwise
+ * @see setAxisAutomaticScale
+ */
+ fun setAxisAutomaticScale(axisType:Int, b:Boolean) {
+mychart!!.axes!!.setAxisAutomaticScale(axisType, b)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * Returns the minimum scale value of the the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @return int Miminum Scale value for the desired axis
+ * @see getAxisMinScale
+ */
+ fun getAxisMinScale(axisType:Int):Double {
+val minmax = mychart!!.getMinMax(this.workBookHandle)
+return mychart!!.axes!!.getMinMax(minmax[0], minmax[1], axisType)[0]
+}
+
+/**
+ * Returns the maximum scale value of the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @return int - Maximum Scale value for the desired axis
+ * @see getAxisMaxScale
+ */
+ fun getAxisMaxScale(axisType:Int):Double {
+val minmax = mychart!!.getMinMax(this.workBookHandle) // -1 is flag for all
+ // rather than for a
+ // specific chart
+ return mychart!!.axes!!.getMinMax(minmax[0], minmax[1], axisType)[1]
+}
+
+/**
+ * Returns the major tick unit of the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @return int major tick unit
+ * @see getAxisMajorUnit
+ */
+ fun getAxisMajorUnit(axisType:Int):Int {
+return mychart!!.axes!!.getAxisMajorUnit(axisType)
+}
+
+/**
+ * Returns the minor tick unit of the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @return int - minor tick unit of the desired axis
+ * @see getAxisMinorUnit
+ */
+ fun getAxisMinorUnit(axisType:Int):Int {
+return mychart!!.axes!!.getAxisMinorUnit(axisType)
+}
+
+/**
+ * Sets the maximum scale value of the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ *
+ * Note: The default scale setting for charts is known as Automatic Scaling
+ * When data changes, the chart automatically adjusts the scale as necessary
+ *
+ * Setting the scale manually (either Minimum or Maximum Value) removes
+ * Automatic Scaling
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @param int MaxValue - desired maximum value of the desired axis
+ * @see setAxisMax
+ */
+ fun setAxisMax(axisType:Int, MaxValue:Int) {
+mychart!!.axes!!.setAxisMax(axisType, MaxValue)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * Sets the minimum scale value of the desired Value axis
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ *
+ * Note: The default setting for charts is known as Automatic Scaling
+ * When data values change, the chart automatically adjusts the scale as
+ * necessary
+ * Setting the scale manually (either Minimum or Maximum Value) removes
+ * Automatic Scaling
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @param int MinValue - the desired Minimum scale value
+ * @see setAxisMin
+ */
+ fun setAxisMin(axisType:Int, MinValue:Int) {
+mychart!!.axes!!.setAxisMin(axisType, MinValue)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * Returns true if the desired Value axis is set to automatic scale
+ *
+ *
+ * The Value axis contains numbers rather than labels, and is normally the Y
+ * axis, but Scatter and Bubble charts may have a value axis on the X Axis as
+ * well
+ *
+ *
+ * Note: The default setting for charts is known as Automatic Scaling
+ * When data changes, the chart automatically adjusts the scale as necessary
+ *
+ * Setting the scale manually (either Minimum or Maximum Value) removes
+ * Automatic Scaling
+ *
+ * @param int axisType - one of ChartHandle.YAXIS, ChartHandle.XAXIS,
+ * ChartHandle.ZAXIS
+ * @return boolean true if Automatic Scaling is turned on
+ * @see getAxisAutomaticScale
+ */
+ fun getAxisAutomaticScale(axisType:Int):Boolean {
+return mychart!!.axes!!.getAxisAutomaticScale(axisType)
+}
+
+/**
+ * Sets the maximum value of the Y Axis (Value Axis) Scale
+ *
+ *
+ * Note: The default scale setting for charts is known as Automatic Scaling
+ * When data changes, the chart automatically adjusts the scale as necessary
+ *
+ * Setting the scale manually (either Minimum or Maximum Value) removes
+ * Automatic Scaling
+ *
+ * @param int MaxValue - the desired maximum scale value
+ * @see ChartHandle.setAxisMax
+ */
+ fun setAxisMax(MaxValue:Int) {
+mychart!!.axes!!.setAxisMax(MaxValue)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * Sets the minimum value of the Y Axis (Value Axis) Scale
+ *
+ *
+ * Note: The default setting for charts is known as Automatic Scaling
+ * When data changes, the chart automatically adjusts the scale as necessary
+ *
+ * Setting the scale manually (either Minimum or Maximum Value) removes
+ * Automatic Scaling
+ *
+ * @param int MinValue - the desired minimum scale value
+ * @see ChartHandle.setAxisMin
+ */
+ fun setAxisMin(MinValue:Int) {
+mychart!!.axes!!.setAxisMin(MinValue)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * sets an option for this axis
+ *
+ * @param axisType one of: XAXIS, YAXIS, ZAXIS
+ * @param op option name; one of: CatCross, LabelCross, Marks, CrossBetween,
+ * CrossMax, MajorGridLines, AddArea, AreaFg, AreaBg or Linked Text
+ * Display options: Label, ShowKey, ShowValue, ShowLabelPct, ShowPct,
+ * ShowCatLabel, ShowBubbleSizes, TextRotation, Font
+ * @param val option value
+ */
+ fun setAxisOption(axisType:Int, op:String, `val`:String) {
+mychart!!.axes!!.setChartOption(axisType, op, `val`)
+
+}
+
+/**
+ * set the font for the chart title
+ *
+ * @param String name - font name
+ * @param int height - font height in 1/20 point units
+ * @param boolean bold - true if bold
+ * @param boolean italic - true if italic
+ * @param boolean underline - true if underlined
+ */
+ fun setTitleFont(name:String, height:Int, bold:Boolean, italic:Boolean, underline:Boolean) {
+val f = Font(name, 200, height)
+f.bold = bold
+f.italic = italic
+f.underlined = underline
+var idx = workBookHandle.workBook!!.getFontIdx(f)
+if (idx == -1)
+{ // font doesn't exist yet, add to streamer
+f.idx = -1 // flag to insert
+idx = workBookHandle.workBook!!.insertFont(f) + 1
+}
+mychart!!.setTitleFont(idx)
+}
+
+/**
+ * set the font for all axes on the chart
+ *
+ * @param String name - font name
+ * @param int height - font height in 1/20 point units
+ * @param boolean bold - true if bold
+ * @param boolean italic - true if italic
+ * @param boolean underline - true if underlined
+ */
+ fun setAxisFont(name:String, height:Int, bold:Boolean, italic:Boolean, underline:Boolean) {
+val f = Font(name, 200, height)
+f.bold = bold
+f.italic = italic
+f.underlined = underline
+var idx = workBookHandle.workBook!!.getFontIdx(f)
+if (idx == -1)
+{ // font doesn't exist yet, add to streamer
+f.idx = -1 // flag to insert
+idx = workBookHandle.workBook!!.insertFont(f) + 1
+}
+mychart!!.axes!!.setTitleFont(XAXIS, idx)
+mychart!!.axes!!.setTitleFont(YAXIS, idx)
+mychart!!.axes!!.setTitleFont(ZAXIS, idx)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * resets all fonts in the chart to the default font of the workbook
+ */
+ fun resetFonts() {
+mychart!!.resetFonts()
+}
+
+/**
+ * Change the value of a Chart object.
+ * **NOTE: THIS HAS NOT BEEN 100% IMPLEMENTED YET**
+ * You can use this method to change:
+ *
+ *
+ * - the Title of the Chart
+ * - the Text Labels of Categories and Values (X and Y)
+ *
+ *
+ * eg:
+ *
+ *
+ * To change the value of the Chart title
+ * chart.changeObjectValue("Template Chart Title", "Widget Sales By Quarter");
+ *
+ *
+ * To change the text label of the categories
+ * chart.changeObjectValue("Category X", "Fiscal Year");
+ *
+ *
+ * To change the text label of the values
+ * chart.changeObjectValue("Value Y", "Sales in US$");
+ *
+ * @param String originalval - One of: "Template Chart Title", "Category X" or
+ * "Value Y"
+ * @param Sring newval - the new setting
+ * @return whether the change was successful
+ */
+ fun changeTextValue(originalval:String, newval:String):Boolean {
+ /*
+ * KSC: TODO: Refactor *** for(int
+ * x=0;x
+ * Use these chart options when creating new charts
+ * A chart may have multiple chart options e.g. 3D Exploded pie chart
+ *
+ * @see ChartHandle.createNewChart
+ */
+ // need: hasMarkers ****
+ enum class ChartOptions {
+CLUSTERED,
+/**
+ * bar, col charts only
+ */
+ STACKED,
+PERCENTSTACKED,
+/**
+ * 100% stacked
+ */
+ THREED,
+/**
+ * 3d Effect
+ */
+ EXPLODED,
+/**
+ * Pie, Donut
+ */
+ HASLINES,
+/**
+ * Scatter, Line
+ */
+ SMOOTHLINES,
+/**
+ * Scatter, Line, Radar
+ */
+ WIREFRAME,
+/**
+ * Surface
+ */
+ DROPLINES,
+/**
+ * line, area, stock charts
+ */
+ UPDOWNBARS,
+/**
+ * line, stock
+ */
+ SERLINES,
+/**
+ * bar, ofpie
+ */
+ HILOWLINES,
+/**
+ * line, stock charts
+ */
+ FILLED /** radar */
+}
+
+/**
+ * Sets the Chart type to the specified type (no 3d, no stacked ...)
+ * To see possible Chart Types, view the public static int's in ChartHandle.
+ *
+ * Possible Chart Types:
+ * BARCHART
+ * COLCHART
+ * LINECHART
+ * PIECHART
+ * AREACHART
+ * SCATTERCHART
+ * RADARCHART
+ * SURFACECHART
+ * DOUGHNUTCHART
+ * BUBBLECHART
+ * RADARAREACHART
+ * PYRAMIDCHART
+ * CYLINDERCHART
+ * CONECHART
+ * PYRAMIDBARCHART
+ * CYLINDERBARCHART
+ * CONEBARCHART
+ *
+ * @param int chartType - representing the chart type
+ * @param nChart - 0 (default) or 1-9 for complex overlay charts
+ * @param EnumSet 0 or more chart options (Such as Stacked, Exploded ...)
+ * @see ChartHandle.ChartOptions
+ */
+ fun setChartType(chartType:Int, nChart:Int, options:EnumSet) {
+mychart!!.setChartType(chartType, nChart, options)
+}
+
+/**
+ * Sets the basic chart type (no 3d, stacked...) for multiple or overlay Charts.
+ *
+ * You can specify the drawing order of the Chart, where 0 is the default chart,
+ * and 1-9 are overlay charts.
+ * The default chart (chart 0) is always present; however, using this method,
+ * you can create a new overlay chart (up to 9 maximum).
+ * NOTE: The chart number must be **unique** and **in order**
+ * If the desired chart number is not present in the chart, a new overlay chart
+ * will be created.
+ * **To set explicit chart options, @see setChartType(chartType, nChart, is3d,
+ * isStacked, is100PercentStacked)**
+ *
+ * To see possible Chart Types, view the public static int's in ChartHandle.
+ *
+ * Possible Chart Types:
+ * BARCHART
+ * COLCHART
+ * LINECHART
+ * PIECHART
+ * AREACHART
+ * SCATTERCHART
+ * RADARCHART
+ * SURFACECHART
+ * DOUGHNUTCHART
+ * BUBBLECHART
+ * RADARAREACHART
+ * PYRAMIDCHART
+ * CYLINDERCHART
+ * CONECHART
+ * PYRAMIDBARCHART
+ * CYLINDERBARCHART
+ * CONEBARCHART
+ *
+ * @param int chartType - representing the chart type
+ * @param chartType
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ fun setChartType(chartType:Int, nChart:Int) {
+mychart!!.setChartType(chartType, nChart, EnumSet
+.noneOf(ChartOptions::class.java)) // no specific options
+}
+
+/**
+ * Return an int corresponding to this ChartHandle's Chart Type for the
+ * specified chart
+ * To see possible Chart Types, view the public static int's in ChartHandle.
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return int chart type
+ * @see ChartHandle static Chart Type Constants
+ *
+ * @see ChartHandle.setChartType
+ */
+ fun getChartType(nChart:Int):Int {
+return mychart!!.getChartType(nChart)
+}
+
+/**
+ * Sets the location lock on the Cell Reference at the specified location
+ *
+ * Used to prevent updating of the Cell Reference when Cells are moved.
+ *
+ * @param location
+ * of the Cell Reference to be locked/unlocked
+ * @param lock
+ * status setting
+ * @return boolean whether the Cell Reference was found and modified
+ */
+ /*
+ * TODO: NEEDED?? public boolean setLocationLocked(String
+ * loc, boolean l){ int x
+ * = Ptg.PTG_LOCATION_POLICY_UNLOCKED; if(l)x =
+ * Ptg.PTG_LOCATION_POLICY_LOCKED;
+ * return setLocationPolicy(loc, x); }
+ */
+
+ /**
+ * Change the Cell Range referenced by one of the Series (a bar, line or wedge
+ * of data) in the Chart.
+ *
+ * For Example, if the data values for one of the Series in the Chart are
+ * obtained from the range Sheet1!A1:A10 and we want to add 5 more values to
+ * that Series, use:
+ *
+ *
+ * boolean changedOK =
+ * charthandle.changeSeriesRange("Sheet1!A1:A10","Sheet1!A1:A15");
+ *
+ * Please keep in mind this is only the data range; it does not include labels
+ * that may have been automatically created when you chose the chart range.
+ *
+ * To illustrate this, if A1 = "label" A2 = "data" A3 = "data", and we want to
+ * add 2 more data points, we would use: changeSeriesRange("Sheet1!A2:A3",
+ * "Sheet1!A2:A5");
+ *
+ * Series are always expressed as one single line of data. If your chart
+ * encompasses a range of rows and columns you will need to modify each of the
+ * series in the chart handle. To determine the series that already exist in
+ * your chart, utilize the String[] getSeries() method.
+ *
+ * @param String originalrange - the original Series (bar, line or wedge of data)
+ * to alter
+ * @param String newrange -the new data range
+ * @return whether the change was successful
+ */
+ fun changeSeriesRange(originalrange:String, newrange:String):Boolean {
+return mychart!!.changeSeriesRange(originalrange, newrange)
+}
+
+/**
+ * Change the Cell Range representing the Categories in the Chart.
+ * Categories usually appear on the X Axis and are textual, not numeric
+ * For example: the Category values in the Chart are obtained from the range
+ * Sheet1!A1:A10 and we want to add 5 more categories to the chart:
+ * boolean changedOK =
+ * chart.changeCategoryRange("Sheet1!A1:A10","Sheet1!A1:A15");
+ * Note that Category Range is the same for each Series (bar, line or wedge of
+ * data)
+ * i.e. there is only one Category Range for the Chart, but there may be many
+ * Series Ranges
+ *
+ * @param String originalrange - Original Category Range
+ * @param String newrange - New Category Range
+ * @return true if the change was successful
+ */
+ fun changeCategoryRange(originalrange:String, newrange:String):Boolean {
+return mychart!!.changeCategoryRange(originalrange, newrange)
+}
+
+/**
+ * Changes or adds a Series to the chart via Series Index. Each bar, line or
+ * wedge in a chart represents a Series.
+ * If the Series index is greater than the number of series already present in
+ * the chart, the series will be added to the end.
+ * Otherwise the Series at the index position will be altered.
+ * This method allows altering of every aspect of the Series: Data (Series)
+ * Range, Legend Cell Address, Category Range and/or Bubble Range.
+ *
+ * @param int index - the series index. If greater than the number of series
+ * already present in the chart, the series will be added to the end
+ * @param String legendCell - String representation of Legend Cell Address
+ * @param String categoryRange - String representation of Category Range (should be
+ * same for all series)
+ * @param String seriesRange - String representation of the Series Data Range for
+ * this series
+ * @param String bubbleRange - String representation of Bubble Range (representing
+ * bubble sizes), if bubble chart. null if not
+ * @return a ChartSeriesHandle representing the new or altered Series
+ * @throws CellNotFoundException
+ */
+ @Throws(CellNotFoundException::class)
+ fun setSeries(index:Int, legendCell:String?, categoryRange:String, seriesRange:String, bubbleRange:String):ChartSeriesHandle {
+var legendText:String? = ""
+try
+{
+var ICell:CellHandle? = null
+if (legendCell != null && legendCell != "")
+{
+ // 20070707 KSC: allow addition of new cell ranges for
+ // legendCell (see
+ // OpenXLS.handleChartElement)
+ try
+{
+ICell = workBookHandle.getCell(legendCell!!)
+}
+catch (c:CellNotFoundException) {
+val shtpos = legendCell!!.indexOf("!")
+if (shtpos > 0)
+{
+val sheetstr = legendCell!!.substring(0, shtpos)
+val sht = workBookHandle.getWorkSheet(sheetstr)
+val celstr = legendCell!!.substring(shtpos + 1)
+ICell = sht!!.add("", celstr)
+}
+}
+
+legendText = ICell!!.stringVal
+}
+return setSeries(index, legendCell, legendText, categoryRange, seriesRange, bubbleRange)
+}
+catch (e:WorkSheetNotFoundException) {
+throw CellNotFoundException(
+("Error locating cell for adding series range: " + legendCell!!))
+}
+
+}
+
+/**
+ * Changes or adds a Series to the desired Chart (either default or overlay) via
+ * Series Index. Each bar, line or wedge in a chart represents a Series.
+ * If the Series index is greater than the number of series already present in
+ * the chart, the series will be added to the end.
+ * Otherwise the Series at the index position will be altered.
+ * This method allows altering of every aspect of the Series: Data (Series)
+ * Range, Legend Text, Legend Cell Address, Category Range and/or Bubble Range.
+ *
+ * @param int index - the series index. If greater than the number of series
+ * already present in the chart, the series will be added to the end
+ * @param String legendCell - String representation of Legend Cell Address
+ * @param String legendText - String Legend text
+ * @param String categoryRange - String representation of Category Range (should be
+ * same for all series)
+ * @param String seriesRange - String representation of the Series Data Range for
+ * this series
+ * @param String bubbleRange - String representation of Bubble Range (representing
+ * bubble sizes), if bubble chart. null if not
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return a ChartSeriesHandle representing the new or altered Series
+ * @throws CellNotFoundException
+ */
+ @Throws(CellNotFoundException::class)
+@JvmOverloads fun setSeries(index:Int, legendCell:String?, legendText:String, categoryRange:String, seriesRange:String, bubbleRange:String, nChart:Int = 0):ChartSeriesHandle {
+ // if (index < mychart.getAllSeries(nChart).size() && index
+ // >= 0) {
+ try
+{
+val s = mychart!!.getAllSeries(nChart).get(index) as Series
+val csh = ChartSeriesHandle(s, this.workBookHandle)
+csh.setSeries(legendCell, categoryRange, seriesRange, bubbleRange)
+setDimensionsRecord()
+return csh
+}
+catch (ae:ArrayIndexOutOfBoundsException) { // not found - add
+return addSeriesRange(legendCell, legendText, categoryRange, seriesRange, bubbleRange, nChart)
+}
+
+}
+
+/**
+ * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
+ * a Series.
+ *
+ * @param String legendAddress - The cell address defining the legend for the
+ * series
+ * @param Srring legendText - Text of the legend
+ * @param String categoryRange - Cell Range defining the category (normally will be
+ * the same range for all series)
+ * @param String seriesRange - Cell range defining the data points of the series
+ * @param String bubbleRange - Cell range defining the bubble sizes for this series
+ * (bubble charts only)
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ChartSeriesHandle representing the new series
+ * @throws CellNotFoundException
+ */
+ @Throws(CellNotFoundException::class)
+private fun addSeriesRange(legendAddress:String?, legendText:String, categoryRange:String, seriesRange:String, bubbleRange:String?, nChart:Int = 0):ChartSeriesHandle {
+var s:Series? = null
+if (bubbleRange == null || bubbleRange == "")
+s = mychart!!
+.addSeries(seriesRange, categoryRange, "", legendAddress, legendText, nChart)
+else
+s = mychart!!
+.addSeries(seriesRange, categoryRange, bubbleRange, legendAddress, legendText, nChart)
+if (nChart > 0)
+{ // must update SeriesList record for overlay charts
+ // TODO: FINISH
+ }
+setDimensionsRecord()
+return ChartSeriesHandle(s, workBookHandle)
+}
+
+/**
+ * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
+ * a Series.
+ * An Example of adding multiple series to a chart:
+ *
+ *
+ * ChartHandle.addSeriesRange("Sheet1!A3", "Sheet1!B1:E1", "Sheet1:B3:E3",
+ * null);
+ * ChartHandle.addSeriesRange("Sheet1!A4", "Sheet1!B1:E1", "Sheet1:B4:E4",
+ * null);
+ * ChartHandle.addSeriesRange("Sheet1!A5", "Sheet1!B1:E1", "Sheet1:B5:E5",
+ * null);
+ * etc...
+ *
+ *
+ * Note that the category does not change, it is usually constant through
+ * series.
+ * Also note that the example above is for a non-bubble-type chart.
+ *
+ * @param String legendCell - Cell reference for the legend cell (e.g. Sheet1!A1)
+ * @param String categoryRange - Category Cell range (e.g. Sheet1!B1:B1);
+ * @param String seriesRange - Series Data range (e.g. Sheet1!B3:E3);
+ * @param String bubbleRange - Cell Range representing Bubble sizes (e.g.
+ * Sheet1!A2:A5); or null if chart is not of type Bubble.
+ * @return ChartSeriesHandle referencing the newly added series
+ */
+ @Throws(CellNotFoundException::class)
+ fun addSeriesRange(legendCell:String, categoryRange:String, seriesRange:String, bubbleRange:String):ChartSeriesHandle {
+return this
+.addSeriesRange(legendCell, categoryRange, seriesRange, bubbleRange, 0) // target
+ // default
+ // chart
+ }
+
+/**
+ * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
+ * a Series.
+ * An Example of adding multiple series to a chart:
+ *
+ *
+ * ChartHandle.addSeriesRange("Sheet1!A3", "Sheet1!B1:E1", "Sheet1:B3:E3",
+ * null);
+ * ChartHandle.addSeriesRange("Sheet1!A4", "Sheet1!B1:E1", "Sheet1:B4:E4",
+ * null);
+ * ChartHandle.addSeriesRange("Sheet1!A5", "Sheet1!B1:E1", "Sheet1:B5:E5",
+ * null);
+ * etc...
+ *
+ *
+ * Note that the category does not change, it is usually constant through
+ * series.
+ * Also note that the example above is for a non-bubble-type chart.
+ *
+ * @param String legendCell - Cell reference for the legend cell (e.g. Sheet1!A1)
+ * @param String categoryRange - Category Cell range (e.g. Sheet1!B1:B1);
+ * @param String seriesRange - Series Data range (e.g. Sheet1!B3:E3);
+ * @param String bubbleRange - Cell Range representing Bubble sizes (e.g.
+ * Sheet1!A2:A5); or null if chart is not of type Bubble.
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ChartSeriesHandle referencing the newly added series
+ */
+ @Throws(CellNotFoundException::class)
+ fun addSeriesRange(legendCell:String?, categoryRange:String, seriesRange:String, bubbleRange:String?, nChart:Int):ChartSeriesHandle {
+var legendText:String? = ""
+var legendAddr = ""
+try
+{
+var ICell:CellHandle? = null
+if (legendCell != null && legendCell != "")
+{
+try
+{
+ICell = workBookHandle.getCell(legendCell!!)
+if (legendCell!!.indexOf("!") == -1)
+legendAddr = (ICell!!.workSheetName + "!"
++ ICell!!.cellAddress)
+else
+legendAddr = legendCell
+}
+catch (c:CellNotFoundException) {
+val shtpos = legendCell!!.indexOf("!")
+if (shtpos > 0)
+{
+val sheetstr = legendCell!!.substring(0, shtpos)
+val sht = workBookHandle.getWorkSheet(sheetstr)
+val celstr = legendCell!!.substring(shtpos + 1)
+ICell = sht!!.add("", celstr) // TODO: Why is this being
+ // added?
+ legendAddr = celstr
+}
+}
+
+if (ICell != null)
+legendText = ICell!!.stringVal
+else
+legendText = legendCell
+}
+var s:Series? = null
+if (bubbleRange == null)
+s = mychart!!
+.addSeries(seriesRange, categoryRange, "", legendAddr, legendText, nChart)
+else
+s = mychart!!
+.addSeries(seriesRange, categoryRange, bubbleRange, legendAddr, legendText, nChart)
+setDimensionsRecord() // update chart DIMENSIONS record upon update
+ // of series
+ return ChartSeriesHandle(s, workBookHandle)
+}
+catch (e:WorkSheetNotFoundException) {
+throw CellNotFoundException(
+("Error locating cell for adding series range: " + legendCell!!))
+}
+
+}
+
+/**
+ * Adds a new Series to the chart via CellHandles and CellRange Objects. Each
+ * bar, line or wedge in a chart represents a Series.
+ *
+ * @param CellHandle legendCell - references the legend cell for this series
+ * @param CellRange categoryRange - The CellRange referencing the category (should be
+ * the same for all Series)
+ * @param CelLRange seriesRange - The CellRange referencing the data points for one
+ * bar, line or wedge in the chart
+ * @param CellRange bubbleRange -The CellRange referencing bubble sizes for this
+ * series, or null if chart is not of type BUBBLE
+ * @return ChartSeriesHandle referencing the newly added series
+ * @see ChartHandle.addSeriesRange
+ */
+ fun addSeriesRange(legendCell:CellHandle, categoryRange:CellRange, seriesRange:CellRange, bubbleRange:CellRange):ChartSeriesHandle {
+return this
+.addSeriesRange(legendCell, categoryRange, seriesRange, bubbleRange, 0) // 0=default
+ // chart
+ }
+
+/**
+ * Adds a new Series to the chart via CellHandles and CellRange Objects. Each
+ * bar, line or wedge in a chart represents a Series.
+ * This method can update the default chart (nChart==0) or overlay charts
+ * (nChart 1-9)
+ *
+ * @param CellHandle legendCell - references the legend cell for this series
+ * @param CellRange categoryRange - The CellRange referencing the category (should be
+ * the same for all Series)
+ * @param CelLRange seriesRange - The CellRange referencing the data points for one
+ * bar, line or wedge in the chart
+ * @param CellRange bubbleRange -The CellRange referencing bubble sizes for this
+ * series, or null if chart is not of type BUBBLE
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ChartSeriesHandle referencing the newly added series
+ * @see ChartHandle.addSeriesRange
+ */
+ fun addSeriesRange(legendCell:CellHandle, categoryRange:CellRange, seriesRange:CellRange, bubbleRange:CellRange?, nChart:Int):ChartSeriesHandle {
+var s:Series? = null
+if (bubbleRange == null)
+s = mychart!!.addSeries(seriesRange.toString(), categoryRange
+.toString(), "", (legendCell.workSheetName + "!"
++ legendCell.cellAddress), legendCell
+.stringVal, nChart)
+else
+s = mychart!!.addSeries(seriesRange.toString(), categoryRange
+.toString(), bubbleRange!!
+.toString(), (legendCell.workSheetName + "!"
++ legendCell.cellAddress), legendCell
+.stringVal, nChart)
+setDimensionsRecord() // 20080417 KSC: update chart DIMENSIONS record
+ // upon update of series
+ return ChartSeriesHandle(s, workBookHandle)
+}
+
+/**
+ * remove the Series (bar, line or wedge) at the desired index
+ *
+ * @param int index - series index (valid values: 0 to
+ * getAllChartSeriesHandles().length-1)
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @see getAllChartSeriesHandles
+ */
+ @JvmOverloads fun removeSeries(index:Int, nChart:Int = -1) {
+val seriesperchart = mychart!!.getAllSeries(nChart)
+val seriestodelete = seriesperchart.get(index) as Series // series to
+ // delete
+ mychart!!.removeSeries(seriestodelete)
+setDimensionsRecord()
+}
+
+/**
+ * updates (replaces) every Chart Series (bar, line or wedge on the Chart) with
+ * the data from the array of values, legends, bubble sizes (optional) and
+ * category range.
+ * NOTE: all arrays must be the same size (the exception is the bubleSizeRanges
+ * array, which may be null)
+ *
+ *
+ * NOTE: String arrays come in reverse order from plugins, so this method adds
+ * series LIFO i.e. reversed
+ *
+ * @param String[] valueRanges - Array of Cell Ranges representing the Values or Data
+ * points for each series (bar, line or wedge) on the Chart
+ * @param String[] legendCells - Array of Cell Addresses representing the legends for
+ * each Series
+ * @param String[] bubbleSizeRanges - Array of Cell ranges representing the bubble
+ * sizes for the Chart, or null if chart is not of type BUBBLE
+ * @param String categoryRange - The Cell Range representing the categories (X
+ * Axis) for the entire Chart
+ */
+ fun addAllSeries(valueRanges:Array, legendCells:Array, bubbleSizeRanges:Array, categoryRange:String) {
+addAllSeries(valueRanges, legendCells, bubbleSizeRanges, categoryRange, 0) // do
+ // for
+ // default
+ // chart
+ }
+
+/**
+ * updates (replaces) every Chart Series (bar, line or wedge on the Chart) with
+ * the data from the array of values, legends, bubble sizes (optional) and
+ * category range For the desired chart (0=default 1-9=overlay charts)
+ * NOTE: all arrays must be the same size (the exception is the bubleSizeRanges
+ * array, which may be null)
+ *
+ *
+ * NOTE: String arrays come in reverse order from plugins, so this method adds
+ * series LIFO i.e. reversed
+ *
+ * @param String[] valueRanges - Array of Cell Ranges representing the Values or Data
+ * points for each series (bar, line or wedge) on the Chart
+ * @param String[] legendCells - Array of Cell Addresses representing the legends for
+ * each Series
+ * @param String[] bubbleSizeRanges - Array of Cell ranges representing the bubble
+ * sizes for the Chart, or null if chart is not of type BUBBLE
+ * @param String categoryRange - The Cell Range representing the categories (X
+ * Axis) for the entire Chart
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ private fun addAllSeries(valueRanges:Array, legendCells:Array, bubbleSizeRanges:Array?, categoryRange:String, nChart:Int) {
+ // first, remove all existing series
+ val v = mychart!!.allSeries
+for (i in v.indices)
+{
+mychart!!.removeSeries(v.get(i) as Series)
+}
+try
+{
+val chartMetrics = mychart!!.getMetrics(workBookHandle) // build
+ // or
+ // retrieve
+ // Chart
+ // Metrics
+ // -->
+ // dimensions
+ // +
+ // series
+ // data
+ // ...
+ this.mychart!!.legend!!
+.resetPos(chartMetrics.get("y"), chartMetrics
+.get("h"), chartMetrics
+.get("canvash"), legendCells.size)
+}
+catch (e:Exception) {}
+
+setDimensionsRecord()
+ // now add series
+ val hasBubbles = (((bubbleSizeRanges != null && bubbleSizeRanges!!.size == valueRanges.size)))
+for (i in valueRanges.indices.reversed())
+{
+try
+{
+if (!hasBubbles)
+ // usual case
+ this.addSeriesRange(legendCells[i], categoryRange, valueRanges[i], null, nChart)
+else
+this.addSeriesRange(legendCells[i], categoryRange, valueRanges[i], bubbleSizeRanges!![i], nChart)
+}
+catch (e:Exception) {
+Logger.logErr("Error adding series: " + e.toString())
+}
+
+}
+}
+
+/**
+ * Appends a series one row below the last series in the chart for the desired
+ * chart
+ *
+ *
+ * This can be utilized when programmatically adding rows of data that should be
+ * reflected in the chart.
+ * Legend cell will be incremented by one row if a reference. Category range
+ * will stay the same.
+ *
+ *
+ * In order for this method to work properly the chart must have row-based
+ * series. If your chart utilizes column-based series, then you need to append a
+ * category.
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ChartSeriesHandle representing newly added series
+ * @see ChartHandle.appendRowCategoryToChart
+ */
+ @JvmOverloads fun appendRowSeriesToChart(nChart:Int = 0):ChartSeriesHandle? {
+val handles = this.getAllChartSeriesHandles(nChart)
+val theHandle = handles[handles.size - 1]
+var legendRef = theHandle.seriesLegendReference
+if (legendRef != null && legendRef != "")
+{
+val sheetnm = legendRef!!.substring(0, legendRef!!.indexOf("!"))
+legendRef = legendRef!!
+.substring(legendRef!!.indexOf("!") + 1)
+val rc = ExcelTools.getRowColFromString(legendRef!!)
+rc[0] = rc[0] + 1
+legendRef = sheetnm + "!" + ExcelTools.formatLocation(rc)
+}
+else if (legendRef == null)
+{
+legendRef = theHandle.seriesLegend
+}
+else
+{
+legendRef = ""
+}
+val categoryRange = theHandle.categoryRange
+var seriesRange = theHandle.seriesRange
+val sheetnm = seriesRange.substring(0, seriesRange.indexOf("!"))
+seriesRange = seriesRange
+.substring(seriesRange.indexOf("!") + 1)
+val rc = ExcelTools.getRangeRowCol(seriesRange)
+ // fiddle it, since exceltools doesn't translate back/forth
+ val newRc = IntArray(4)
+newRc[0] = rc[1]
+newRc[1] = rc[0] + 1
+newRc[2] = rc[3]
+newRc[3] = rc[2] + 1
+seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc)
+try
+{
+return this
+.addSeriesRange(legendRef, "", categoryRange, seriesRange, "", nChart)
+}
+catch (e:CellNotFoundException) {
+Logger.logErr(("ChartHandle.appendRowSeriesToChart: Unable to append series to chart: " + e))
+}
+
+return null
+}
+
+/**
+ * Append a row of categories to the bottom of the chart.
+ * Expands all Series to include the new bottom row.
+ * To be utilized when expanding a chart to encompass more data that has a
+ * col-based series.
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @see ChartHandle.appendRowSeriesToChart
+ */
+ @JvmOverloads fun appendRowCategoryToChart(nChart:Int = 0) {
+val handles = this.getAllChartSeriesHandles(nChart)
+
+for (i in handles.indices)
+{
+val theHandle = handles[i]
+ // update the series
+ var seriesRange = theHandle.seriesRange
+var s = ExcelTools.stripSheetNameFromRange(seriesRange)
+var sheetnm = s[0]
+seriesRange = s[1]
+ // String sheetnm = seriesRange.substring(0,
+ // seriesRange.indexOf("!"));
+ // seriesRange = seriesRange.substring(
+ // seriesRange.indexOf("!")+1,
+ // seriesRange.length());
+ // Strip 2nd sheet ref, if any 20080213 KSC
+ // int n= seriesRange.indexOf('!');
+ // int m= seriesRange.indexOf(':');
+ // seriesRange= seriesRange.substring(0, m+1) +
+ // seriesRange.substring(n+1);
+
+ var rc = ExcelTools.getRangeRowCol(seriesRange)
+var newRc = IntArray(4)
+newRc[0] = rc[1]
+newRc[1] = rc[0]
+newRc[2] = rc[3]
+newRc[3] = rc[2] + 1
+seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc)
+theHandle.seriesRange = seriesRange
+ // update the category
+ seriesRange = theHandle.categoryRange
+s = ExcelTools.stripSheetNameFromRange(seriesRange)
+sheetnm = s[0]
+seriesRange = s[1]
+ /*
+ * sheetnm = seriesRange.substring(0,
+ * seriesRange.indexOf("!")); seriesRange =
+ * seriesRange.substring( seriesRange.indexOf("!")+1,
+ * seriesRange.length()); //
+ * Strip 2nd sheet ref, if any 20080213 KSC n=
+ * seriesRange.indexOf('!'); m=
+ * seriesRange.indexOf(':'); seriesRange=
+ * seriesRange.substring(0, m+1) +
+ * seriesRange.substring(n+1);
+ */
+ rc = ExcelTools.getRangeRowCol(seriesRange)
+newRc = IntArray(4)
+newRc[0] = rc[1]
+newRc[1] = rc[0]
+newRc[2] = rc[3]
+newRc[3] = rc[2] + 1
+seriesRange = sheetnm + "!" + ExcelTools.formatRange(newRc)
+theHandle.categoryRange = seriesRange
+}
+}
+
+private fun t(n:Int):String {
+val tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t"
+return (tabs.substring(0, n))
+}
+
+/**
+ * given a XmlPullParser positioned at the chart element, parse all chart
+ * elements to create desired chart
+ *
+ * @param sht WorkSheetHandle
+ * @param xpp XmlPullParser
+ */
+ fun parseXML(sht:WorkSheetHandle, xpp:XmlPullParser, maps:HashMap<*, *>) {
+try
+{
+var eventType = xpp.getEventType()
+while (eventType != XmlPullParser.END_DOCUMENT)
+{
+if (eventType == XmlPullParser.START_TAG)
+{
+val tnm = xpp.getName()
+if (tnm == "ChartFonts")
+{
+for (x in 0 until xpp.getAttributeCount())
+{
+this.setChartFont(xpp.getAttributeName(x), xpp
+.getAttributeValue(x))
+}
+}
+else if (tnm == "ChartFontRec")
+{
+var fName = ""
+var fontId = 0
+var fSize = 0
+var fWeight = 0
+var fColor = 0
+var fUnderline = 0
+var bIsBold = false
+for (x in 0 until xpp.getAttributeCount())
+{
+val attr = xpp.getAttributeName(x)
+val `val` = xpp.getAttributeValue(x)
+if (attr == "name")
+{
+fName = `val`
+}
+else if (attr == "id")
+{
+fontId = Integer.parseInt(`val`)
+}
+else if (attr == "size")
+{
+fSize = Font.PointsToFontHeight(java.lang.Double
+.parseDouble(`val`))
+}
+else if (attr == "color")
+{
+fColor = FormatHandle
+.HexStringToColorInt(`val`, FormatHandle.colorFONT)
+if (fColor == 0)
+fColor = 32767 // necessary?
+}
+else if (attr == "weight")
+{
+fWeight = Integer.parseInt(`val`)
+}
+else if (attr == "bold")
+{
+bIsBold = true
+}
+else if (attr == "underline")
+{
+fUnderline = Integer.parseInt(`val`)
+}
+}
+while (this.workBook!!.numFonts < fontId - 1)
+{
+this.workBook!!.insertFont(Font("Arial",
+FormatConstants.PLAIN, 10))
+}
+if (this.workBook!!.numFonts < fontId)
+{
+val f = Font(fName, fWeight, fSize)
+f.color = fColor
+f.bold = bIsBold
+f.setUnderlineStyle(fUnderline.toByte())
+this.workBook!!.insertFont(f)
+}
+else
+{ // TODO: this will screw up linked fonts,
+ // perhaps, so what to do?
+ val f = this.workBook!!.getFont(fontId)
+f.fontWeight = fWeight
+f.setFontName(fName)
+f.fontHeight = fSize
+f.color = fColor
+f.bold = bIsBold
+f.setUnderlineStyle(fUnderline.toByte())
+}
+}
+else if (tnm == "FormatChartArea")
+{ // TODO:
+ // something!
+ // ChartBorder
+ // ChartProperties
+ }
+else if (tnm == "Series")
+{ // series -->
+ // Legend Range Category shape typex typey
+ var legend = ""
+var series = ""
+var category = ""
+var bubble = ""
+var dataTypeX = ""
+var dataTypeY = ""
+var shape = ""
+for (x in 0 until xpp.getAttributeCount())
+{
+if (xpp.getAttributeName(x)
+.equals("Legend", ignoreCase = true))
+legend = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Range", ignoreCase = true))
+series = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Category", ignoreCase = true))
+category = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Bubbles", ignoreCase = true))
+bubble = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("TypeX", ignoreCase = true))
+dataTypeX = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("TypeY", ignoreCase = true))
+dataTypeY = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Shape", ignoreCase = true))
+shape = xpp.getAttributeValue(x)
+}
+ // 20070709 KSC: can't add until all cells are added
+ // ch.addSeriesRange(legend, category, series);
+ val s = arrayOf(legend, series, category, bubble, dataTypeX, dataTypeY, shape)
+val map = maps
+.get("chartseries") as HashMap, ChartHandle>
+map.put(s, this)
+}
+else if (tnm == "ChartOptions")
+{ // handle
+ // chart-type-specific
+ // options such
+ // as legend
+ // options
+ // 20070716 KSC: handle chart-type-specific options in a
+ // very generic way ...
+ for (x in 0 until xpp.getAttributeCount())
+{
+this.setChartOption(xpp.getAttributeName(x), xpp
+.getAttributeValue(x))
+}
+}
+else if (tnm == "ThreeD")
+{ // handle three-d options
+ // handle threeD record options in a very generic way
+ // ...
+ this.make3D() // default chart - TODO; if mutliple
+ // charts, handle
+ for (x in 0 until xpp.getAttributeCount())
+{ // now
+ // add
+ // threed
+ // rec
+ // options
+ this.setChartOption(xpp.getAttributeName(x), xpp
+.getAttributeValue(x))
+}
+}
+else if (tnm.endsWith("Axis"))
+{ // handle axis specs
+ // (Label + options ...)
+ // 20070720 KSC: handle Axis record options ...
+ var type = 0
+val axis = xpp.getName()
+if (axis.equals("XAxis", ignoreCase = true))
+type = XAXIS
+else if (axis.equals("YAxis", ignoreCase = true))
+type = YAXIS
+else if (axis.equals("ZAxis", ignoreCase = true))
+type = ZAXIS
+if (xpp.getAttributeCount() > 0)
+{ // then has axis
+ // options
+ for (x in 0 until xpp.getAttributeCount())
+{
+this.setAxisOption(type, xpp
+.getAttributeName(x), xpp
+.getAttributeValue(x))
+}
+}
+else
+{ // no axis options means no axis present;
+ // remove
+ this.removeAxis(type)
+}
+}
+else if (tnm == "Series")
+{ // handle series data
+ // Legend Range Category
+ var legend = ""
+var series = ""
+var category = ""
+var bubble = ""
+var dataTypeX = ""
+var dataTypeY = ""
+var shape = ""
+for (x in 0 until xpp.getAttributeCount())
+{
+if (xpp.getAttributeName(x)
+.equals("Legend", ignoreCase = true))
+legend = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Range", ignoreCase = true))
+series = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Category", ignoreCase = true))
+category = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Bubbles", ignoreCase = true))
+bubble = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("TypeX", ignoreCase = true))
+dataTypeX = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("TypeY", ignoreCase = true))
+dataTypeY = xpp.getAttributeValue(x)
+else if (xpp.getAttributeName(x)
+.equals("Shape", ignoreCase = true))
+shape = xpp.getAttributeValue(x)
+}
+ // 20070709 KSC: can't add until all cells are added
+ // ch.addSeriesRange(legend, category, series);
+ val s = arrayOf(legend, series, category, bubble, dataTypeX, dataTypeY, shape)
+val map = maps
+.get("chartseries") as HashMap, ChartHandle>
+map.put(s, this)
+}
+}
+else if (eventType == XmlPullParser.END_TAG)
+{
+if (xpp.getName() == "Chart")
+break
+}
+eventType = xpp.next()
+}
+}
+catch (e:Exception) {
+Logger.logWarn(("ChartHandle.parseXML <" + xpp.getName() + ">: "
++ e.toString()))
+ // TODO: propogate Exception???
+ }
+
+}
+
+/********************************************************************
+ * OOXML Generation Methods
+ */
+ /**
+ * Generates OOXML (chartML) for this chart object.
+ *
+ *
+ * NOTE: necessary root chartSpace element + namespaces are not set here
+ *
+ * @param int rId -reference ID for this chart
+ * @return String representing the OOXML describing this Chart
+ */
+ fun getOOXML(rId:Int):String {
+ // TODO: finish 3d options- floor, sideWall, backWall
+ // TODO: finish axis options
+ // TODO: printSettings
+
+ // generate OOXML (chartML)
+ val cooxml = StringBuffer()
+try
+{
+mychart!!.chartSeries.resetSeriesNumber() // reset series idx
+ // retrieve pertinent chart data
+ // axes id's TODO: HANDLE MULTIPLE AXES per chart ...
+ val catAxisId = Integer
+.toString((Math.random() * 1000000).toInt())
+val valAxisId = Integer
+.toString((Math.random() * 1000000).toInt())
+val serAxisId = Integer
+.toString((Math.random() * 1000000).toInt())
+val thischart:OOXMLChart
+if ((mychart is OOXMLChart))
+thischart = mychart as OOXMLChart?
+else
+{ // XLS->XLSX
+thischart = OOXMLChart(mychart!!, workBookHandle)
+mychart = thischart
+thischart.chartSeries.setParentChart(thischart)
+}
+thischart.wbh = this.workBookHandle
+
+cooxml.append(thischart.getOOXML(catAxisId, valAxisId, serAxisId))
+
+ // TODO:
+ val chartEmbeds = thischart.chartEmbeds
+if (chartEmbeds != null)
+{
+var j = 0
+for (i in chartEmbeds!!.indices)
+{
+if ((chartEmbeds!!.get(i) as Array)[0] == "userShape")
+{
+j++
+cooxml.append(" ")
+}
+}
+}
+}
+catch (e:Exception) {
+Logger.logErr(("ChartHandle.getOOXML: error generating OOXML. Chart not created: " + e.toString()))
+}
+
+return cooxml.toString()
+}
+
+/**
+ * generates the OOXML specific for DrawingML, specifying offsets and
+ * identifying the chart object.
+ * this Drawing ML (OOXML) is distinct from Chart ML (OOXML) which actually
+ * defines the chart object including series, categories and axes
+ * This is an internal method that is not useful to the end user.
+ *
+ * @param int id - the reference id for this chart
+ * @return String OOXML
+ */
+ fun getChartDrawingOOXML(id:Int):String {
+val t = TwoCellAnchor(
+(mychart as OOXMLChart).editMovement)
+t.setAsChart(id, OOXMLAdapter.stripNonAscii(this.ooxmlName)
+.toString(), TwoCellAnchor.convertBoundsFromBIFF8(this
+.sheet, mychart!!.bounds!!)) // adjust BIFF8
+ // bounds to
+ // OOXML units
+ return t.ooxml
+}
+
+/********************************************************************************
+ * Parsing OOXML Methods
+ */
+ /**
+ * defines this chart object based on a Chart ML (OOXML) input Stream (root
+ * element=c:chartSpace)
+ * This is an internal method that is not useful to the end user.
+ *
+ * @param inputStream ii - representing chart OOXML
+ */
+ fun parseOOXML(ii:java.io.InputStream) {
+ // overlay in title, after layout
+ // varyColors val= "0" -- after grouping and before ser
+
+ // series colors by theme:
+ /*
+ * accent1 - 6
+ */
+ /**
+ * chartSpace: chart (Chart) §5.7.2.27 clrMapOvr (Color Map Override) §5.7.2.30
+ * date1904 (1904 Date System) §5.7.2.38 externalData (External Data
+ * Relationship) §5.7.2.63 extLst (Chart Extensibility) §5.7.2.64 lang (Editing
+ * Language) §5.7.2.87 pivotSource (Pivot Source) §5.7.2.145 printSettings
+ * (Print Settings) §5.7.2.149 protection (Protection) §5.7.2.150 roundedCorners
+ * (Rounded Corners) §5.7.2.160 spPr (Shape Properties) §5.7.2.198 style (Style)
+ * §5.7.2.203 txPr (Text Properties) §5.7.2.217 userShapes (Reference to Chart
+ * Drawing Part) §5.7.2.222
+ */
+ try
+{
+val thischart = mychart as OOXMLChart?
+var drawingOrder = 0 // drawing order of the chart (0=default, 1-9
+ // for multiple charts in 1)
+ var hasPivotTableSource = false
+
+ // remove any undesired formatting from default chart:
+ this.title = "" // clear any previously set
+mychart!!.axes!!.setPlotAreaBgColor(FormatConstants.COLOR_WHITE)
+mychart!!.axes!!.setPlotAreaBorder(-1, -1) // remove plot area
+ // border
+
+ val lastTag = java.util.Stack() // keep
+ // track
+ // of
+ // element
+ // hierarchy
+
+ val factory = XmlPullParserFactory.newInstance()
+factory.setNamespaceAware(true)
+val xpp = factory.newPullParser()
+
+xpp.setInput(ii, null) // using XML 1.0 specification
+var eventType = xpp.getEventType()
+while (eventType != XmlPullParser.END_DOCUMENT)
+{
+if (eventType == XmlPullParser.START_TAG)
+{
+val tnm = xpp.getName() // main entry= chartSpace,
+ // children: lang, chart
+ lastTag.push(tnm) // keep track of element hierarchy
+if (tnm == "chart")
+{ // beginning of DrawingML for a
+ // single image or chart;
+ // children: title,
+ // plotArea, legend,
+ /**
+ * 5
+ * 6
+ * 7
+ * 8
+ * 9
+ * 10
+ * 11
+ * 12
+ *
+ * plotArea contains layout, , serAx, valAx, catAx, dateAx, spPr,
+ * dTable 13
+ * 14
+ *
+ * 15
+ * 16
+ * 17
+ *
+ * 18
+ */
+ }
+else if (tnm == "lang")
+{
+thischart!!.lang = xpp.getAttributeValue(0)
+}
+else if (tnm == "roundedCorners")
+{
+thischart!!.roundedCorners = xpp.getAttributeValue(0) == "1"
+}
+else if (tnm == "pivotSource")
+{ // has a pivot table
+hasPivotTableSource = true
+}
+else if (tnm == "view3D")
+{
+ThreeD.parseOOXML(xpp, lastTag, thischart!!)
+}
+else if (tnm == "layout")
+{
+thischart!!.plotAreaLayout = Layout
+.parseOOXML(xpp, lastTag).cloneElement() as Layout
+}
+else if (tnm == "legend")
+{
+thischart!!.showLegend(true, false)
+thischart!!.ooxmlLegend = io.starter.formats.OOXML.Legend
+.parseOOXML(xpp, lastTag, this.workBookHandle)
+.cloneElement() as io.starter.formats.OOXML.Legend
+thischart!!.ooxmlLegend!!
+.fill2003Legend(thischart!!.legend)
+ // Parse actual CHART TYPE element (barChart, pieChart,
+ // etc.)
+ }
+else if ((tnm == OOXMLConstants.twoDchartTypes[ChartHandle.BARCHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.LINECHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.PIECHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.AREACHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.SCATTERCHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.RADARCHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.SURFACECHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.DOUGHNUTCHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.BUBBLECHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.OFPIECHART]
+|| tnm == OOXMLConstants.twoDchartTypes[ChartHandle.STOCKCHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.BARCHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.LINECHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.PIECHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.AREACHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.SCATTERCHART]
+|| tnm == OOXMLConstants.threeDchartTypes[ChartHandle.SURFACECHART]))
+{ // specific
+ // chart
+ // type-
+ ChartType
+.parseOOXML(xpp, this.workBookHandle, mychart, drawingOrder++)
+lastTag.pop()
+}
+else if (tnm == "title")
+{
+thischart!!.setOOXMLTitle(Title
+.parseOOXML(xpp, lastTag, this.workBookHandle)
+.cloneElement() as Title, this.workBookHandle)
+this.title = thischart!!.ooxmlTitle!!.title
+}
+else if (tnm == "spPr")
+{ // shape properties -- can
+ // be for plot area or
+ // chart space
+ val parent = lastTag.get(lastTag.size - 2)
+if (parent == "plotArea")
+{
+thischart!!.setSpPr(0, SpPr
+.parseOOXML(xpp, lastTag, this.workBookHandle)
+.cloneElement() as SpPr)
+}
+else if (parent == "chartSpace")
+{
+thischart!!.setSpPr(1, SpPr
+.parseOOXML(xpp, lastTag, this.workBookHandle)
+.cloneElement() as SpPr)
+}
+}
+else if (tnm == "txPr")
+{ // text formatting
+thischart!!.txPr = TxPr
+.parseOOXML(xpp, lastTag, this.workBookHandle)
+.cloneElement() as TxPr
+}
+else if (tnm == "catAx")
+{ // child of plotArea
+mychart!!.axes!!
+.parseOOXML(XAXIS, xpp, tnm, lastTag, this.workBookHandle)
+}
+else if (tnm == "valAx")
+{ // child of plotArea
+if (mychart!!.axes!!.hasAxis(ChartConstants.XAXIS))
+ // usual,
+ // have
+ // a
+ // catAx
+ // then
+ // a
+ // valAx
+ mychart!!.axes!!
+.parseOOXML(ChartConstants.YAXIS, xpp, tnm, lastTag, this.workBookHandle)
+else if (mychart!!.axes!!
+.hasAxis(ChartConstants.YAXIS))
+ // for bubble
+ // charts, has
+ // two valAxes
+ // and no
+ // catAx
+ mychart!!.axes!!
+.parseOOXML(ChartConstants.XVALAXIS, xpp, tnm, lastTag, this.workBookHandle)
+else
+ // 2nd val axis is Y axis
+ mychart!!.axes!!
+.parseOOXML(ChartConstants.YAXIS, xpp, tnm, lastTag, this.workBookHandle)
+}
+else if (tnm == "serAx")
+{ // series axis - 3d charts
+mychart!!.axes!!
+.parseOOXML(ZAXIS, xpp, tnm, lastTag, this.workBookHandle)
+}
+else if (tnm == "dateAx")
+{ // TODO: not finished:
+ // figure out!
+ // ??
+ }
+
+}
+else if (eventType == XmlPullParser.END_TAG)
+{
+lastTag.pop()
+val endTag = xpp.getName()
+if (endTag == "chartSpace")
+{
+setDimensionsRecord()
+break // done processing
+}
+}
+if (xpp.getEventType() != XmlPullParser.END_DOCUMENT)
+eventType = xpp.next()
+else
+eventType = XmlPullParser.END_DOCUMENT
+}
+}
+catch (e:Exception) {
+Logger.logErr("ChartHandle.parseChartOOXML: " + e.toString())
+}
+
+}
+
+/**
+ * Specifies how to resize or move this Chart upon edit
+ * This is an internal method that is not useful to the end user.
+ * Excel 7/OOXML specific
+ *
+ * @param editMovement String OOXML-specific edit movement setting
+ */
+ fun setEditMovement(editMovement:String) {
+(mychart as OOXMLChart).editMovement = editMovement
+}
+
+/**
+ * sets external information linked to or "embedded" in this OOXML chart; can be
+ * a chart user shape, an image ...
+ * NOTE: a userShape is a drawingml file name which defines the userShape (if
+ * any)
+ * a userShape is a drawing or shape ontop of a chart
+ *
+ * @param String[] embedType, filename e.g. {"userShape", "userShape file name"}
+ */
+ fun addChartEmbed(ce:Array) {
+(mychart as OOXMLChart).addChartEmbed(ce)
+}
+
+/**
+ * set the chart DIMENSIONS record based on the series ranges in the chart
+ * APPEARS THAT for charts, the DIMENSIONS record merely notes the range of
+ * values: 0, #points in series, 0, #series
+ */
+ protected fun setDimensionsRecord() {
+val series = this.allChartSeriesHandles
+val nSeries = series.size
+var nPoints = 0
+for (i in series.indices)
+{
+try
+{
+val coords = ExcelTools
+.getRangeCoords(series[i].seriesRange)
+if (coords[3] > coords[1])
+nPoints = Math.max(nPoints, coords[3] - coords[1] + 1) // c1-c0
+else
+nPoints = Math.max(nPoints, coords[2] - coords[0] + 1) // r1-r0
+}
+catch (e:Exception) {}
+
+}
+mychart!!.setDimensionsRecord(0, nPoints, 0, nSeries)
+}
+
+/**
+ * Method for setting Chart-Type-specific options in a generic fashion e.g.
+ * charthandle.setChartOption("Stacked", "true");
+ *
+ *
+ * Note: since most Chart Type Options are interdependent, there are several
+ * makeXX methods that set the desired group of options e.g. makeStacked(); use
+ * setChartOption with care
+ *
+ *
+ * Note that not all Chart Types will have every option available
+ *
+ *
+ * Possible Options:
+ *
+ *
+ * "Stacked" - true or false - set Chart Series to be Stacked
+ * "Cluster" - true or false - set Clustered for Column and Bar Chart Types
+ * "PercentageDisplay" - true or false - Each Category is broken down as a
+ * percentge
+ * "Percentage" - Distance of pie slice from center of pie as % for Pie Charts
+ * (0 for all others)
+ * "donutSize" - Donut size for Donut Charts Only
+ * "Overlap" - Space between bars (default= 0%)
+ * "Gap" - Space between categories (%) (default=50%)
+ * "SmoothedLine" - true or false - the Line series has a smoothed line
+ * "AnRot" - Rotation Angle (0 to 360 degrees), usually 0 for pie, 20 for others
+ * (3D option)
+ * "AnElev" - Elevation Angle (-90 to 90 degrees) (15 is default) (3D option)
+ *
+ * "ThreeDScaling" - true or false - 3d effect
+ * "TwoDWalls" - true if 2D walls (3D option)
+ * "PcDist" - Distance from eye to chart (0 to 100) (30 is default) (3D option)
+ *
+ * "ThreeDBubbles" - true or false - Draw bubbles with a 3d effect
+ * "ShowLdrLines" - true or false - Show Pie and Donut charts Leader Lines
+ * "MarkerFormat" - "0" thru "9" for various marker options @see
+ * ChartHandle.setMarkerFormat
+ * "ShowLabel" - true or false - show Series/Data Label
+ * "ShowCatLabel" - true or false - show Category Label
+ * "ShowLabelPct" - true or false - show percentage labels for Pie charts
+ * "ShowBubbleSizes" - true or false - show bubble sizes for Bubble charts
+ *
+ *
+ * NOTE: all values must be in String form
+ *
+ * @see ChartHandle.getXML
+ */
+ fun setChartOption(op:String, `val`:String) {
+mychart!!.setChartOption(op, `val`)
+}
+
+/**
+ * Method for setting Chart-Type-specific options in a generic fashion e.g.
+ * charthandle.setChartOption("Stacked", "true");
+ *
+ * @param op
+ * @param val
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ private fun setChartOption(op:String, `val`:String, nChart:Int) {
+mychart!!.setChartOption(op, `val`, nChart)
+}
+
+/**
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return true if Chart has 3D effects, false otherwise
+ */
+ fun isThreeD(nChart:Int):Boolean {
+return mychart!!.isThreeD(nChart)
+}
+
+/**
+ * Make chart 3D if not already
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ * @return ThreeD rec
+ */
+ internal fun initThreeD(nChart:Int):ThreeD {
+return mychart!!.initThreeD(nChart, this.getChartType(nChart))
+}
+
+/**
+ * @param int Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
+ * @return String XML representation of the desired Axis
+ */
+ private fun getAxisOptionsXML(Axis:Int):String {
+return mychart!!.axes!!.getAxisOptionsXML(Axis)
+}
+
+/**
+ * Returns the Axis Label Placement or position as an int
+ *
+ *
+ * One of:
+ * Axis.INVISIBLE - axis is hidden
+ * Axis.LOW - low end of plot area
+ * Axis.HIGH - high end of plot area
+ * Axis.NEXTTO- next to axis (default)
+ *
+ * @param int Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
+ * @return int - one of the Axis Label placement constants above
+ */
+ fun getAxisPlacement(Axis:Int):Int {
+return mychart!!.axes!!.getAxisPlacement(Axis)
+}
+
+/**
+ * Sets the Axis labels position or placement to the desired value (these match
+ * Excel placement options)
+ *
+ *
+ * Possible options:
+ * Axis.INVISIBLE - hides the axis
+ * Axis.LOW - low end of plot area
+ * Axis.HIGH - high end of plot area
+ * Axis.NEXTTO- next to axis (default)
+ *
+ * @param int Axis - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
+ * @param Placement - int one of the Axis placement constants listed above
+ */
+ fun setAxisPlacement(Axis:Int, Placement:Int) {
+mychart!!.axes!!.setAxisPlacement(Axis, Placement)
+mychart!!.setDirtyFlag(true)
+}
+
+ /*
+ * returns the desired axis If bCreateIfNecessary, will
+ * creates if doesn't exist
+ *
+ * @return Axis Object / private Axis getAxis(int axisType,
+ * boolean
+ * bCreateIfNecessary) { return mychart.getAxis(axisType,
+ * bCreateIfNecessary); }
+ */
+
+ /**
+ * removes the desired Axis from the Chart
+ *
+ * @param int axisType - one of the Axis constants (XAXIS, YAXIS or ZAXIS)
+ */
+ fun removeAxis(axisType:Int) {
+mychart!!.axes!!.removeAxis(axisType)
+mychart!!.setDirtyFlag(true)
+}
+
+/**
+ * Set non-axis chart font id for title, default, etc
+ * For Internal Use Only
+ *
+ * @param String type - font type
+ * @param String val - font id
+ */
+ fun setChartFont(type:String, `val`:String) {
+mychart!!.setChartFont(type, `val`)
+}
+
+ // 20070802 KSC: Debug uility to write out chartrecs
+ /*
+ * For internal debugging use only
+ *
+ * public void writeChartRecs(String fName) {
+ * mychart.writeChartRecs(fName); }
+ *
+ * /** set DataLabels option for this chart
+ *
+ * @param String type - see below
+ *
+ * @param boolean bShowLegendKey - true if show legend key,
+ * false otherwise
+ * possible String type values: Series Category
+ * Value
+ * Percentage (Only for Pie Charts) Bubble (Only for
+ * Bubble Charts)
+ * X Value (Only for Bubble Charts) Y Value (Only
+ * for Bubble Charts)
+ * CandP
+ *
+ * NOTE: not 100% implemented at this time
+ */
+ fun setDataLabel(/* [] */ type:String, bShowLegendKey:Boolean) {
+ /*
+ * for now, only 1 option is valid - multiple legend
+ * settings e.g. Category and
+ * Value are not figured out yet for (int i= 0; i <
+ * type.length; i++)
+ * mychart.setChartOption("DataLabel", type[i]);
+ */
+ if (!bShowLegendKey)
+mychart!!.setChartOption("DataLabel", type)
+else
+mychart!!.setChartOption("DataLabelWithLegendKey", type)
+}
+
+/**
+ * shows or removes the Data Table for this chart
+ *
+ * @param boolean bShow - true if show data table
+ */
+ fun showDataTable(bShow:Boolean) {
+mychart!!.showDataTable(bShow)
+}
+
+/**
+ * shows or hides the Chart legend key
+ *
+ * @param booean bShow - true if show legend, false to hide
+ * @param boolean vertical - true if show vertically, false for horizontal
+ */
+ fun showLegend(bShow:Boolean, vertical:Boolean) {
+mychart!!.showLegend(bShow, vertical)
+}
+
+/**
+ * returns true if Chart has a Data Legend Key showing
+ *
+ * @return true if Chart has a Data Legend Key showing
+ */
+ fun hasDataLegend():Boolean {
+return mychart!!.hasDataLegend()
+}
+
+ fun removeLegend() {
+mychart!!.removeLegend()
+}
+
+ // 20070905 KSC: Group chart options for ease of setting
+ // almost all charts have these specific ChartTypes:
+
+ /**
+ * makes this Chart Stacked
+ * sets the group of options necessary to create a stacked chart
+ * For Chart Types:
+ * BAR, COL, LINE, AREA, PYRAMID, PYRAMIDBAR, CYLINDER, CYLINDERBAR, CONE,
+ * CONEBAR
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("")
+ fun makeStacked(nChart:Int) { // bar, col, line, area, pyramid col +
+ // bar, cone col + bar, cylinder col
+ // + bar
+ val chartType = this.getChartType(nChart)
+this.setChartOption("Stacked", "true", nChart)
+when (chartType) {
+ChartConstants.BARCHART, ChartConstants.COLCHART -> this.setChartOption("Overlap", "-100", nChart)
+ChartConstants.CYLINDERCHART, ChartConstants.CYLINDERBARCHART, ChartConstants.CONECHART, ChartConstants.CONEBARCHART, ChartConstants.PYRAMIDCHART, ChartConstants.PYRAMIDBARCHART -> {
+this.setChartOption("Overlap", "-100", nChart)
+val td = this.initThreeD(nChart)
+td.setChartOption("Cluster", "false")
+}
+ChartConstants.LINECHART -> this.setChartOption("Percentage", "0", nChart)
+ChartConstants.AREACHART -> {
+this.setChartOption("Overlap", "-100", nChart)
+this.setChartOption("Percentage", "25", nChart)
+this.setChartOption("SmoothedLine", "true", nChart)
+}
+}
+}
+
+/**
+ * makes this Chart 100% Stacked
+ * sets the group of options necessary to create a 100% stacked chart
+ * For Chart Types:
+ * BAR, COL, LINE, PYRAMID, PYRAMIDBAR, CYLINDER, CYLINDERBAR, CONE, CONEBAR
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("")
+ fun make100PercentStacked(nChart:Int) { // bar, col, line, pyramid
+ // col + bar, cone col +
+ // bar, cylinder col +
+ // bar
+ val chartType = this.getChartType(nChart)
+this.setChartOption("Stacked", "true", nChart)
+this.setChartOption("PercentageDisplay", "true", nChart)
+when (chartType) {
+ChartConstants.COLCHART // + pyramid
+, ChartConstants.BARCHART -> this.setChartOption("Overlap", "-100", nChart)
+ChartConstants.CYLINDERCHART, ChartConstants.CYLINDERBARCHART, ChartConstants.CONECHART, ChartConstants.CONEBARCHART, ChartConstants.PYRAMIDCHART, ChartConstants.PYRAMIDBARCHART -> {
+this.setChartOption("Overlap", "-100", nChart)
+val td = this.initThreeD(nChart)
+td.setChartOption("Cluster", "false")
+}
+ChartConstants.LINECHART -> {}
+}
+}
+
+/**
+ * makes this Chart Stacked with a 3D Effect
+ * sets the group of options necessary to create a Stacked 3D chart
+ * For Chart Types:
+ * BAR, COL, AREA
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ fun makeStacked3D(nChart:Int) { // bar, col, area
+val chartType = this.getChartType(nChart)
+this.setChartOption("Stacked", "true", nChart)
+val td = this.initThreeD(nChart)
+td.setChartOption("AnRot", "20")
+td.setChartOption("ThreeDScaling", "true")
+td.setChartOption("TwoDWalls", "true")
+when (chartType) {
+ChartConstants.COLCHART, ChartConstants.BARCHART -> this.setChartOption("Overlap", "-100", nChart)
+ChartConstants.AREACHART -> {
+this.setChartOption("Percentage", "25", nChart)
+this.setChartOption("SmoothedLine", "true", nChart)
+}
+}
+}
+
+/**
+ * makes this Chart 100% Stacked with a 3D Effect
+ * sets the group of options necessary to create a 100% Stacked 3D chart
+ * For Chart Types:
+ * BAR, COL, AREA
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("")
+ fun make100PercentStacked3D(nChart:Int) { // bar, col, area
+val chartType = this.getChartType(nChart)
+this.setChartOption("Stacked", "true", nChart)
+this.setChartOption("PercentageDisplay", "true", nChart)
+when (chartType) {
+ChartConstants.COLCHART // + pyramid
+, ChartConstants.BARCHART -> {
+this.setChartOption("Overlap", "-100", nChart)
+val td = this.initThreeD(nChart)
+td.setChartOption("AnRot", "20")
+td.setChartOption("ThreeDScaling", "true")
+td.setChartOption("TwoDWalls", "true")
+}
+ChartConstants.AREACHART -> {
+this.setChartOption("Percentage", "25", nChart)
+this.setChartOption("SmoothedLine", "true", nChart)
+}
+}
+}
+
+/**
+ * makes the desired Chart hava a 3D effect
+ * where nChart 0= default, 1-9=multiple charts in one
+ * sets the group of options necessary to create a 3D chart
+ * For Chart Types:
+ * BARCHART, COLCHART, LINECHART, PIECHART, AREACHART, BUBBLECHART,
+ * PYRAMIDCHART, CYLINDERCHART, CONECHART
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("use setChartType(chartType, nChart, is3d, isStacked,\n"+
+" is100%Stacked) instead")
+@JvmOverloads fun make3D(nChart:Int = 0) { // bar, col, line, pie, area, bubble,
+ // pyramid, cone, cylinder
+ val chartType = this.getChartType(nChart)
+var td:ThreeD? = null
+when (chartType) {
+ChartConstants.COLCHART, ChartConstants.BARCHART -> {
+td = this.initThreeD(nChart)
+td!!.setChartOption("AnRot", "20")
+td!!.setChartOption("ThreeDScaling", "true")
+td!!.setChartOption("TwoDWalls", "true")
+}
+ChartConstants.CYLINDERCHART, ChartConstants.CONECHART, ChartConstants.PYRAMIDCHART -> {
+td = this.initThreeD(nChart)
+td!!.setChartOption("Cluster", "false")
+}
+ChartConstants.AREACHART -> {
+this.setChartOption("Percentage", "25", nChart)
+this.setChartOption("SmoothedLine", "true", nChart)
+td = this.initThreeD(nChart)
+td!!.setChartOption("AnRot", "20")
+td!!.setChartOption("ThreeDScaling", "true")
+td!!.setChartOption("TwoDWalls", "true")
+td!!.setChartOption("Perspective", "true")
+}
+ChartConstants.PIECHART, ChartConstants.LINECHART -> this.initThreeD(nChart) // just create a threeD rec w/ no extra
+ChartConstants.BUBBLECHART -> {
+this.setChartOption("Percentage", "25", nChart)
+this.setChartOption("SmoothedLine", "true", nChart)
+this.setChartOption("ThreeDBubbles", "true", nChart)
+td = this.initThreeD(nChart) // 20081228 KSC
+}
+}// options
+}
+
+ // more specialized option sets
+
+ /**
+ * makes this Chart Clusted with a 3D effect
+ * sets the group of options necessary to create a Clusted 3D chart
+ * For Chart Types:
+ * BAR, COL
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("")
+ fun makeClustered3D(nChart:Int) { // only for Column and Bar (?)
+val chartType = this.getChartType(nChart)
+when (chartType) {
+ChartConstants.BARCHART, ChartConstants.COLCHART -> {
+val td = this.initThreeD(nChart)
+td.setChartOption("AnRot", "20")
+td.setChartOption("Cluster", "true")
+td.setChartOption("ThreeDScaling", "true")
+td.setChartOption("TwoDWalls", "true")
+}
+}
+}
+
+/**
+ * makes this chart's wedges exploded i.e. separated
+ * For Chart Types:
+ * PIECHART, DOUGHNUTCHART
+ *
+ */
+ @Deprecated("")
+ fun makeExploded() { // pie, donut
+val chartType = this.chartType
+when (chartType) {
+ChartConstants.DOUGHNUTCHART -> {
+this.setChartOption("SmoothedLine", "true")
+this.setChartOption("ShowLdrLines", "true")
+this.setChartOption("Percentage", "25")
+}
+ChartConstants.PIECHART -> {
+this.setChartOption("ShowLdrLines", "true")
+this.setChartOption("Percentage", "25")
+}
+}// ShowLdrLines="true" Percentage="25"/>
+ // exploded donut: ShowLdrLines="true" Donut="50"
+ // Percentage="25"
+ // SmoothedLine="true"/>
+}
+
+/**
+ * makes this chart's wedges exploded 3D i.e. separated with a 3D effect
+ * For Chart Types:
+ * PIECHART, DOUGHNUTCHART
+ *
+ * @param nChart number and drawing order of the desired chart (default= 0 max=9
+ * where 1-9 indicate an overlay chart)
+ */
+ @Deprecated("")
+ fun makeExploded3D(nChart:Int) { // pie
+ // ShowLdrLines="true" Percentage="25"
+ // AnRot="236"
+ val chartType = this.getChartType(nChart)
+when (chartType) {
+ChartConstants.DOUGHNUTCHART, ChartConstants.PIECHART -> {
+this.setChartOption("ShowLdrLines", "true", nChart)
+this.setChartOption("Percentage", "25", nChart)
+val td = this.initThreeD(nChart)
+td.setChartOption("AnRot", "236")
+}
+}
+}
+
+ /*
+ * NOT IMPLEMENTED YET TODO: IMPLEMENT Make this Chart have
+ * smoothed lines
+ * (Scatter only)
+ *
+ * public void makeSmoothedLines() { // scatter
+ * //Percentage="25"
+ * SmoothedLine="true }
+ *
+ * public void makeWireFrame() { // surface // NO ColorFill,
+ * only //
+ * Percentage="25" SmoothedLine="true" // AnRot="20"
+ * Perspective="true"
+ * ThreeDScaling="true" TwoDWalls="true"/> // all else
+ * should be default for
+ * surface charts } public void makeContour() { // surface
+ * -- for wireframe
+ * surface, no ColorFill //ColorFill="true" Percentage="25"
+ * SmoothedLine="true"/> // AnElev="90" pcDist="0"
+ * Perspective="true"
+ * ThreeDScaling="true" TwoDWalls="true" }
+ */
+
+ /**
+ * set the marker format style for this chart
+ * one of:
+ * 0 = no marker
+ * 1 = square
+ * 2 = diamond
+ * 3 = triangle
+ * 4 = X
+ * 5 = star
+ * 6 = Dow-Jones
+ * 7 = standard deviation
+ * 8 = circle
+ * 9 = plus sign
+ * For Chart Types:
+ * LINE, SCATTER
+ *
+ * @param int imf - marker format constant from list above
+ */
+ fun setMarkerFormat(imf:Int) { // line, scatter ...
+this.setChartOption("MarkerFormat", (imf).toString())
+}
+
+/**
+ * utility to add a JSON object
+ * This is an internal method that is not useful to the end user.
+ *
+ * @param source
+ * @param input
+ */
+ protected fun inputJSONObject(source:JSONObject?, input:JSONObject) {
+if (source != null)
+{
+try
+{
+for (j in 0 until input.names().length())
+{
+source!!.put(input.names().getString(j), input
+.get(input.names().getString(j)))
+}
+}
+catch (e:JSONException) {
+Logger.logErr("Error inputting JSON Object: " + e)
+}
+
+}
+}
+
+/**
+ * /** Take current Chart object and return the SVG code necessary to define it,
+ * scaled to the desired percentage e.g. 0.75= 75%
+ *
+ * @param scale double scale factor
+ * @return String SVG
+ */
+ fun getSVG(scale:Double):String {
+val chartMetrics = mychart!!.getMetrics(workBookHandle) // build
+ // or
+ // retrieve
+ // Chart
+ // Metrics
+ // -->
+ // dimensions
+ // +
+ // series
+ // data
+ // ...
+
+ val svg = StringBuffer()
+ // required header
+ // svg.append("\r\n"); // referneces
+ // the DTD
+ // svg.append("\r\n");
+
+ // Define SVG Canvas:
+ svg.append(("\r\n"))
+svg.append(("")) // scale
+ // chart
+ // -default
+ // scale=1
+ // == 100%
+ // JavaScript hooks
+ svg.append(javaScript)
+
+ // Data Legend Box -- do before drawing plot area as legends
+ // box may change plot
+ // area coordinates
+ val legendSVG = getLegendSVG(chartMetrics) // but have to append it
+ // after because should
+ // overlap the
+ // plotarea
+
+ val bgclr = this.mychart!!.plotAreaBgColor
+ // setup gradients
+ svg.append("")
+svg.append("")
+svg.append((" "))
+svg.append((" "))
+svg.append(" ")
+svg.append(" ")
+
+ // PLOT AREA BG + RECT
+ // rectangle around entire chart canvas
+ if ((!(mychart is OOXMLChart) || !(mychart as OOXMLChart).roundedCorners))
+svg.append((" \r\n"))
+else
+ // OOXML rounded corners
+ svg.append((" \r\n"))
+
+ // actual plot area
+ svg.append((" \r\n"))
+
+ // AXES, IF PRESENT - DO BEFORE ACTUAL SERIES DATA SO DRAWS
+ // CORRECTLY + ADJUST
+ // CHART DIMENSIONS
+ svg.append(mychart!!.axes!!.getSVG(XAXIS, chartMetrics, mychart!!
+.chartSeries.getCategories()))
+svg.append(mychart!!.axes!!.getSVG(YAXIS, chartMetrics, mychart!!
+.chartSeries.getCategories()))
+ // TODO: Z Axis
+
+ // After Axes and gridlines (if present),
+ // ACTUAL bar/series/area/etc. svg generated from series and
+ // scale data
+ svg.append(this.mychart!!.chartObject.getSVG(chartMetrics, mychart!!
+.axes!!.metrics, mychart!!.chartSeries))
+
+svg.append(legendSVG) // append legend SVG obtained above
+
+ // CHART TITLE
+
+ if (mychart!!.titleTd != null)
+svg.append(mychart!!.titleTd!!.getSVG(chartMetrics))
+
+svg.append(" ")
+svg.append(" ")
+ /*
+ * //KSC: TESTING: REMOVE WHEN DONE if
+ * (WorkBookFactory.PID==WorkBookFactory.E360) { // save svg
+ * for testing
+ * purposes try { java.io.File f= new java.io.File(
+ * "c:/eclipse/workspace/testfiles/io.starter.OpenXLS/output/charts/FromSheetster.svg"
+ * ); java.io.FileOutputStream fos= new
+ * java.io.FileOutputStream(f);
+ * fos.write(svg.toString().getBytes()); fos.flush();
+ * fos.close(); } catch
+ * (Exception e) {} }
+ */
+ return svg.toString()
+}
+
+private fun getLegendSVG(chartMetrics:HashMap):String? {
+try
+{
+return mychart!!.legend!!.getSVG(chartMetrics, mychart!!
+.chartObject, mychart!!.chartSeries)
+}
+catch (ne:NullPointerException) { // no legend??
+return null
+}
+
+}
+
+/**
+ * debugging utility remove when done
+ */
+ fun WriteMainChartRecs(fName:String) {
+mychart!!.chartObject.WriteMainChartRecs(fName)
+}
+
+ fun getAxis(type:Int):Axis? {
+ // TODO Auto-generated method stub
+ return null
+}
+
+companion object {
+ // 20080114 KSC: delegate so visible
+ val BARCHART = ChartConstants.BARCHART
+ val COLCHART = ChartConstants.COLCHART
+ val LINECHART = ChartConstants.LINECHART
+ val PIECHART = ChartConstants.PIECHART
+ val AREACHART = ChartConstants.AREACHART
+ val SCATTERCHART = ChartConstants.SCATTERCHART
+ val RADARCHART = ChartConstants.RADARCHART
+ val SURFACECHART = ChartConstants.SURFACECHART
+ val DOUGHNUTCHART = ChartConstants.DOUGHNUTCHART
+ val BUBBLECHART = ChartConstants.BUBBLECHART
+ val OFPIECHART = ChartConstants.OFPIECHART
+ val PYRAMIDCHART = ChartConstants.PYRAMIDCHART
+ val CYLINDERCHART = ChartConstants.CYLINDERCHART
+ val CONECHART = ChartConstants.CONECHART
+ val PYRAMIDBARCHART = ChartConstants.PYRAMIDBARCHART
+ val CYLINDERBARCHART = ChartConstants.CYLINDERBARCHART
+ val CONEBARCHART = ChartConstants.CONEBARCHART
+ val RADARAREACHART = ChartConstants.RADARAREACHART
+ val STOCKCHART = ChartConstants.STOCKCHART
+
+ // legacy
+ val BAR = BARCHART
+ val COL = COLCHART
+ val LINE = LINECHART
+ val PIE = PIECHART
+ val AREA = AREACHART
+ val SCATTER = SCATTERCHART
+ val RADAR = RADARCHART
+ val SURFACE = SURFACECHART
+ val DOUGHNUT = DOUGHNUTCHART
+ val BUBBLE = BUBBLECHART
+ val RADARAREA = RADARAREACHART
+ val PYRAMID = PYRAMIDCHART
+ val CYLINDER = CYLINDERCHART
+ val CONE = CONECHART
+ val PYRAMIDBAR = PYRAMIDBARCHART
+ val CYLINDERBAR = CYLINDERBARCHART
+ val CONEBAR = CONEBARCHART
+ // axis types
+ val XAXIS = ChartConstants.XAXIS
+ val YAXIS = ChartConstants.YAXIS
+ val ZAXIS = ChartConstants.ZAXIS
+ val XVALAXIS = ChartConstants.XVALAXIS // an
+ // X
+ // axis
+ // type
+ // but
+ // VAL
+ // records
+ // coordinates
+ val X = 0
+ val Y = 1
+ val WIDTH = 2
+ val HEIGHT = 3
+
+/**
+ * returns the encompassing range for this chart, or null if the chart data is
+ * too complex to represent
+ *
+ * @param jsonDataRange
+ * @return
+ */
+ fun getEncompassingDataRange(jsonDataRange:JSONObject):IntArray? {
+try
+{
+val catrange = jsonDataRange.get("c").toString()
+val sheet = catrange.substring(0, catrange.indexOf('!'))
+val retVals = ExcelTools.getRangeRowCol(catrange)
+val nSeries = jsonDataRange.getJSONArray("Series").length()
+for (i in 0 until nSeries)
+{
+val series = jsonDataRange
+.getJSONArray("Series").get(i) as JSONObject
+val serrange = series.get("v").toString()
+if (!serrange.startsWith(sheet))
+continue
+var locs = ExcelTools.getRangeRowCol(serrange)
+try
+{
+if (locs[0] < retVals[0])
+retVals[0] = locs[0]
+if (locs[1] < retVals[1])
+retVals[1] = locs[1]
+if (locs[2] > retVals[2])
+retVals[2] = locs[2]
+if (locs[3] > retVals[3])
+retVals[3] = locs[3]
+
+val legendrange = series.get("l").toString()
+locs = ExcelTools.getRowColFromString(legendrange)
+if (locs[0] < retVals[0])
+retVals[0] = locs[0]
+if (locs[1] < retVals[1])
+retVals[1] = locs[1]
+if (locs[0] > retVals[2])
+retVals[2] = locs[0]
+if (locs[1] > retVals[3])
+retVals[3] = locs[1]
+
+if (series.has("b"))
+{
+val bubblerange = series.get("b").toString()
+locs = ExcelTools.getRangeRowCol(serrange)
+if (locs[0] < retVals[0])
+retVals[0] = locs[0]
+if (locs[1] < retVals[1])
+retVals[1] = locs[1]
+if (locs[2] > retVals[2])
+retVals[2] = locs[2]
+if (locs[3] > retVals[3])
+retVals[3] = locs[3]
+}
+}
+catch (e:Exception) {
+ // just continue
+ }
+
+}
+return retVals
+}
+catch (e:Exception) {}
+
+return null
+ /*
+ * while (ptgs.hasNext()) { PtgRef pr= (PtgRef) ptgs.next();
+ * // PtgRef pr=
+ * (PtgRef)refs[i]; int[] locs = pr.getIntLocation(); for
+ * (int x=0;x<2;x++) {
+ * if((locs[x]retValues[x]))retValues[x]=locs[x]; } i++; }
+ */
+ }
+
+/**
+ * Static method to create a new chart on WorkSheet sheet of type chartType with
+ * chart Options options
+ * After creating, you can set the chart title via ChartHandle.setTitle
+ * and Position via ChartHandle.setRelativeBounds (row/col-based) or
+ * ChartHandle.setCoords (pixel-based)
+ * as well as several other customizations possible
+ *
+ * @param book WorkBookHandle
+ * @param sheet WorkSheetHandle
+ * @param chartType one of:
+ * BARCHART
+ * COLCHART
+ * LINECHART
+ * PIECHART
+ * AREACHART
+ * SCATTERCHART
+ * RADARCHART
+ * SURFACECHART
+ * DOUGHNUTCHART
+ * BUBBLECHART
+ * RADARAREACHART
+ * PYRAMIDCHART
+ * CYLINDERCHART
+ * CONECHART
+ * PYRAMIDBARCHART
+ * CYLINDERBARCHART
+ * CONEBARCHART
+ * @param options EnumSet
+ * @return
+ * @see ChartHandle.ChartOptions
+ *
+ * @see setChartType
+ */
+ fun createNewChart(sheet:WorkSheetHandle, chartType:Int, options:EnumSet):ChartHandle {
+ // Create Initial Basic Chart
+ val cht = sheet.workBook!!.createChart("", sheet)
+ // Change Chart Type with Desired Options:
+ cht!!.setChartType(chartType, 0, options)
+return cht
+}
+}
+}/**
+ * Changes or adds a Series to the chart via Series Index. Each bar, line or
+ * wedge in a chart represents a Series.
+ * If the Series index is greater than the number of series already present in
+ * the chart, the series will be added to the end.
+ * Otherwise the Series at the index position will be altered.
+ * This method allows altering of every aspect of the Series: Data (Series)
+ * Range, Legend Text, Legend Cell Address, Category Range and/or Bubble Range.
+ *
+ * @param int index - the series index. If greater than the number of series
+ * already present in the chart, the series will be added to the end
+ * @param String legendCell - String representation of Legend Cell Address
+ * @param String legendText - String Legend text
+ * @param String categoryRange - String representation of Category Range (should be
+ * same for all series)
+ * @param String seriesRange - String representation of the Series Data Range for
+ * this series
+ * @param String bubbleRange - String representation of Bubble Range (representing
+ * bubble sizes), if bubble chart. null if not
+ * @return a ChartSeriesHandle representing the new or altered Series
+ * @throws CellNotFoundException
+ */// for
+ // default
+ // chart
+/**
+ * Adds a new Series to the chart. Each bar, line or wedge in a chart represents
+ * a Series.
+ *
+ * @param String legendAddress - The cell address defining the legend for the
+ * series
+ * @param Srring legendText - Text of the legend
+ * @param String categoryRange - Cell Range defining the category (normally will be
+ * the same range for all series)
+ * @param String seriesRange - Cell range defining the data points of the series
+ * @param String bubbleRange - Cell range defining the bubble sizes for this series
+ * (bubble charts only)
+ * @return ChartSeriesHandle representing the new series
+ * @throws CellNotFoundException
+ */// for
+ // default
+ // chart
+/**
+ * remove the Series (bar, line or wedge) at the desired index
+ *
+ * @param int index - series index (valid values: 0 to
+ * getAllChartSeriesHandles().length-1)
+ * @see getAllChartSeriesHandles
+ */// -1 flag for all series
+/**
+ * Appends a series one row below the last series in the chart.
+ *
+ *
+ * This can be utilized when programmatically adding rows of data that should be
+ * reflected in the chart.
+ * Legend cell will be incremented by one row if a reference. Category range
+ * will stay the same.
+ *
+ *
+ * In order for this method to work properly the chart must have row-based
+ * series. If your chart utilizes column-based series, then you need to append a
+ * category.
+ *
+ * @return ChartSeriesHandle representing newly added series
+ * @see ChartHandle.appendRowCategoryToChart
+ */// do for default chart (0)
+/**
+ * Append a row of categories to the bottom of the chart.
+ * Expands all Series to include the new bottom row.
+ * To be utilized when expanding a chart to encompass more data that has a
+ * col-based series.
+ *
+ * @see ChartHandle.appendRowSeriesToChart
+ */// default chart
+/**
+ * makes the default Chart hava a 3D effect
+ * sets the group of options necessary to create a 3D chart
+ * For Chart Types:
+ * BARCHART, COLCHART, LINECHART, PIECHART, AREACHART, BUBBLECHART,
+ * PYRAMIDCHART, CYLINDERCHART, CONECHART
+ *
+ */// bar, col, line, pie, area, bubble, pyramid, cone,
+ // cylinder
diff --git a/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.java b/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.java
deleted file mode 100644
index d381e57..0000000
--- a/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.java
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-//IMPORT OOXML-specific items
-import io.starter.formats.OOXML.DLbls;
-import io.starter.formats.OOXML.DPt;
-import io.starter.formats.OOXML.Marker;
-import io.starter.formats.OOXML.SpPr;
-
-import io.starter.formats.XLS.charts.*;
-
-
-/** Chart Series Handle allows for manipulation of Chart Series within a Chart Handle.
-
- Charts are typically made up of two data elements, series data and category data.
- When Microsoft Excel creates a chart, it assigns either the worksheet rows as series data (and the
- columns as category data), or the worksheet columns as the series data (and the rows as categories).
-
- Excel tries to minimize the number of series by default, unless both rows and columns are equal, in which case
- the default is to have the rows as series.
-
- Typically there will be one series object per row (or column if that is the series) of data. In most cases, the categories
- will be the same for every series.
-
- As there are series for every row of data, when performing actions such as adding a column to a chart that has it's series
- arranged by row, it will be necessary to modify every series within the chart. ChartSeriesHandle is available to
- make this process easier.
-
- @see ChartHandle
-
-*/
-
-public class ChartSeriesHandle {
- private Series myseries;
- private WorkBookHandle wbh;
-
- /**
- * Constructor, used internally. For public use get series from a ChartHandle
- * @param Series series
- * @param WorkBook wbk - WorkBook the Chart is attached to
- */
- public ChartSeriesHandle(Series series, WorkBookHandle wbk) {
- myseries = series;
- wbh = wbk;
- }
-
- /**
- * returns the Cell Range String representing the Data in this Series Object.
- * @return String Cell Range representing Series Data e.g. Sheet1!A1:A12
- */
- public String getSeriesRange() {
- return myseries.getSeriesValueAi().toString();
- }
-
- /**
- * returns the Cell Range String representing the Categories (usually the X Axis) for the Chart
- * Note that Category typically stays constant for all Series in the Chart
- * @return String Category Cell Range e.g. Sheet1!A1:C1
- */
- public String getCategoryRange() {
- return myseries.getCategoryValueAi().toString();
- }
-
- /**
- * returns the Cell Range String representing Bubble Size for this Series (Bubble Charts only)
- * @return String Bubble Sizes Cell Range e.g. Sheet1!A1:C1
- */
- public String getBubbleSizes() {
- return myseries.getBubbleValueAi().toString();
- }
- /**
- * returns true if this chart has Bubble Sizes
- * @return
- */
- public boolean hasBubbleSizes(){
- return myseries.hasBubbleSizes();
- }
- /**
- * sets the data for this Series to be obtained from a new Cell Range.
- *
- * Note that if you set the size of this series to a different amount of data than other Series
- * in the chart you could have unexpected results.
- *
- *@param String seriesRange - a Cell Range representing Series Data e.g. Sheet1!A1:A12
- *
- */
- public void setSeriesRange(String seriesRange) {
- myseries.getParentChart().setMetricsDirty();
- Ai ai = myseries.getSeriesValueAi();
- ai.setParentChart(myseries.getParentChart()); // 20080215 KSC: Added
- ai.setSheet(myseries.getParentChart().getSheet());// ""
- if (ai.getWorkBook()==null)ai.setWorkBook(wbh.getWorkBook());
- ai.changeAiLocation(ai.toString(), seriesRange);
- try { // 20070711 KSC: update value (series) count for series
- int coords[]= io.starter.OpenXLS.ExcelTools.getRangeCoords(seriesRange);
- myseries.setValueCount(coords[4]);
- myseries.getParentChart().setMetricsDirty();
- } catch(Exception e) {
-
- }
- }
-
- /**
- * sets the Category from a new Cell Range.
- *
- * IMPORTANT! In most cases, the category should be set to the same Cell Range for all Series in the chart.
- * This method is available for complex charts, but in most cases the ideal way to handle this call is through
- * chartHandle.changeCategoryRange.
- * @param String categoryRange - new Category Cell Range
- */
- public void setCategoryRange(String categoryRange) {
- myseries.getParentChart().setMetricsDirty();
- Ai ai = myseries.getCategoryValueAi();
- if (ai.getWorkBook()==null)ai.setWorkBook(wbh.getWorkBook());
- ai.changeAiLocation(ai.toString(), categoryRange);
- try { // 20070711 KSC: update Category Count for this series
- int coords[]= io.starter.OpenXLS.ExcelTools.getRangeCoords(categoryRange);
- myseries.setCategoryCount(coords[4]);
- myseries.getParentChart().setMetricsDirty();
- } catch(Exception e) {
-
- }
- }
-
- /**
- * set the Cell Range for the Bubbles in this Seeries (Bubble Chart Only)
- * @param String bubbleSizes - Cell Range for Bubble Sizes
- */
- public void setBubbleRange(String bubbleSizes) {
- if (bubbleSizes!=null && !bubbleSizes.equals("")) {
- myseries.getParentChart().setMetricsDirty();
- Ai ai = myseries.getBubbleValueAi();
- if (ai.getWorkBook()==null)ai.setWorkBook(wbh.getWorkBook());
- ai.changeAiLocation(ai.toString(), bubbleSizes);
- ai.setRt(2);
- try { // also update Bubble Count for this series
- int coords[]= io.starter.OpenXLS.ExcelTools.getRangeCoords(bubbleSizes);
- myseries.setBubbleCount(coords[4]);
- myseries.getParentChart().setMetricsDirty();
- } catch(Exception e) {
-
- }
- }
- }
-
- /**
- * Set the Legend text for this Series
- * note: series legend will then not be linked to a particular cell. if you want to change the legend
- * reference, use setSeriesLegendRef
- * @param String legend - Legend Text
- * @see setSeriesLegendRef
- */
- public void setSeriesLegend(String legend) {
- myseries.setLegend(legend, this.wbh);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * returns the Legend text for this Series
- * @return String Legend text for this Series
- * @see getSeriesLegendReference
- */
- public String getSeriesLegend() {
- return myseries.getLegendText();
- }
-
- /**
- * returns the Legend Cell Reference, if any
- * @return String Cell Address representing the Legend for this Series
- */
- public String getSeriesLegendReference() {
- Ai ai = myseries.getLegendAi();
- if (ai!=null)return ai.getDefinition();
- return null;
- }
-
- /**
- * sets Cell Address for the Series Legend
- * @param String legendCell - Cell Address for Legend
- */
- public void setSeriesLegendRef(String legendCell) {
- myseries.setLegendRef(legendCell);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * gets the Chart Category Data Type
- * @return int Data Type of the Category
- */
- public int getCategoryDataType() {
- return myseries.getCategoryDataType();
- }
-
- /**
- * gets the Series Data Type
- * @return int Data Type of this Series
- */
- public int getSeriesDataType() {
- return myseries.getValueDataType();
- }
- /**
- * sets the Chart Category Data Type
- * @param int i - Category Data Type
- */
- public void setCategoryDataType(int i) {
- myseries.setCategoryDataType(i);
- myseries.getParentChart().setMetricsDirty();
- }
- /**
- * sets the Series Data Type
- * @param int i - Series Data Type
- */
- public void setSeriesDataType(int i) {
- myseries.setValueDataType(i);
- }
-
- /**
- * returns a constant that represents the bar shape for this Series
- * This is an internal method that is not useful to the end user.
- * @return int DataPoint shape for this Series (3d Bar, Pyramid ...)
- */
- public int getShape() {
- return myseries.getShape();
- }
- /**
- * sets the constant that represents the bar shape for this Series
- * This is an internal method that is not useful to the end user.
- * @param int shape - DataPoint shape for this Series (3d Bar, Pyramid ...)
- */
- public void setShape(int shape) {
- myseries.setShape(shape);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * defines this Series with Cell References for the Legend, Data Points, Category and Bubble Sizes,
- * if applicable.
- * @param String legendRef - Cell Address representing the Legend for this Series
- * @param String series - Cell Range representing the Data Points for this Series
- * @param String cat - Cell Range representing the Category for this Series
- * (NOTE: The Category Cell Range is typically the same for every Series in the Chart)
- * @param String bubble - Cell Range representing the Bubble Sizes for this Series (Bubble Chart only) or null if none
- */
- public void setSeries(String legendRef, String series, String cat, String bubble) {
- this.setSeriesLegendRef(legendRef);
- this.setSeriesRange(series);
- this.setCategoryRange(cat);
- this.setBubbleRange(bubble);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * sets the color for this series
- * @param int seriesNumber - series index
- * @param int clr - color constant
- * @deprecated use setSeriesColor(int clr) instead
- * @see setSeriesColor(int clr)
- */
- public void setSeriesColor(int seriesNumber, int clr) {
- myseries.setColor(clr);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * sets the color for this Series (bar or line)
- * NOTE: for Pie Charts, use setPieChartSliceColor
- * @param int clr - color constant
- * @see setPieChartSliceColor
- * @see FormatHandle.COLOR_* constants
- */
- public void setSeriesColor(int clr) {
- myseries.setColor(clr);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * sets the color for this Series (bar or line)
- * NOTE: for Pie Charts, use setPieChartSliceColor
- * @param String color hex string
- * @see setPieChartSliceColor
- * @see FormatHandle.COLOR_* constants
- */
- public void setSeriesColor(String clr) {
- myseries.setColor(clr);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * sets the color for a particular Pie Chart slice or wedge
- * @param int clr - color constant
- * @param int slice - 0-based slice or point number
- * @see FormatHandle.COLOR_* constants
- */
- public void setPieChartSliceColor(int clr, int slice) {
- myseries.setPieSliceColor(clr, slice);
- myseries.getParentChart().setMetricsDirty();
- }
-
- /**
- * returns the Series (bar or line) color
- * NOTE: for Pie charts, use getPieChartSliceColor
- * @return int color constant representing the Series color
- * @see FormatHandle.COLOR_* constants
- * @deprecated
- * @see getSeriesColorStr
- */
- public int getSeriesColor() {
- return FormatHandle.HexStringToColorInt(myseries.getSeriesColor(), FormatHandle.colorBACKGROUND) ;
- }
-
- /**
- * returns the Series (bar or line) color hex string
- * NOTE: for Pie charts, use getPieChartSliceColor
- * @return int color constant representing the Series color
- * @see FormatHandle.COLOR_* constants
- * @see getPieChartSliceColor
- */
- public String getSeriesColorStr() {
- return myseries.getSeriesColor();
- }
-
- /**
- * returns the desired Pie chart slice color
- * @param int slice - 0-based slice or wedge index
- * @return int color constant repressenting the color for the desired pie slice
- * @see FormatHandle.COLOR_* constants
- * @deprecated See getPieChartSliceColorStr
- */
- public int getPieChartSliceColor(int slice) {
- return FormatHandle.HexStringToColorInt(myseries.getPieSliceColor(slice), FormatHandle.colorBACKGROUND) ;
- }
-
- /**
- * returns the desired Pie chart slice color hex string
- * @param int slice - 0-based slice or wedge index
- * @return String color hex string representing the color for the desired pie slice
- */
- public String getPieChartSliceColorStr(int slice) {
- return myseries.getPieSliceColor(slice);
- }
-
- /*
- * returns the OOXML (Open Office XML) Shape Properties Object for this Series
- * @return SpPr OOXML Shape Properties Object
- * @see SpPr
- *
- public SpPr getSpPr() { return myseries.getSpPr(); }
- */
-
- /*
- * sets the OOXML (Open Office XML) Shape Properties Object for this Series
- * @param SpPr sp - OOXML Shape Properties Object
- * @see SpPr
- *
- public void setSpPr(SpPr sp) {
- myseries.setSpPr(sp);
- }*/
-
- /*
- * returns the OOXML (Open Office XML) Marker Properties Object for this Series
- * @return Marker -OOXML Marker Properties Object
- * @see Marker
- *
- public Marker getMarker() { return myseries.getMarker(); }
- */
- /*
- * sets the OOXML (Open Office XML) Marker Properties Object for this Series
- * @param Marker m - the OOXML Marker Properties Object
- * @see Marker
- *
- public void setMarker(Marker m) {
- myseries.setMarker(m);
- }*/
-
- /*
- * returns the OOXML (Open Office XML) Data Label Properties Object for this Series
- * @return DLbls - OOXML Data Label Properties Object
- *
- public DLbls getDLbls() { return myseries.getDLbls(); }
- */
-
- /*
- * sets the OOXML (Open Office XML) Data Label Properties Object for this Series
- * @param Dlbls d- OOXML Data Label Properties Object
- * @see DLbls
- *
- public void setDLbls(DLbls d) {
- myseries.setDLbls(d);
- }*/
-
- /*
- * returns an array of OOXML (Open Office XML) Data Point Properties Objects defining this Series
- * @return DPt[] - Array of OOXML Data Point Properties Objects
- * @see Dpt
- *
- public DPt[] getDPt() { return myseries.getDPt(); }*/
- /*
- * adds an OOXML (Open Office XML) Data Point Property Element to this Series
- * @param DPt d- Data Point Properties Object
- * @see DPt
- *
- public void addDpt(DPt d) {
- myseries.addDpt(d);
- }*/
-}
diff --git a/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.kt b/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.kt
new file mode 100644
index 0000000..0d211de
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ChartSeriesHandle.kt
@@ -0,0 +1,445 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+//IMPORT OOXML-specific items
+
+import io.starter.formats.XLS.charts.Ai
+import io.starter.formats.XLS.charts.Series
+
+
+/**
+ * Chart Series Handle allows for manipulation of Chart Series within a Chart Handle.
+ *
+ * Charts are typically made up of two data elements, series data and category data.
+ * When Microsoft Excel creates a chart, it assigns either the worksheet rows as series data (and the
+ * columns as category data), or the worksheet columns as the series data (and the rows as categories).
+ *
+ * Excel tries to minimize the number of series by default, unless both rows and columns are equal, in which case
+ * the default is to have the rows as series.
+ *
+ * Typically there will be one series object per row (or column if that is the series) of data. In most cases, the categories
+ * will be the same for every series.
+ *
+ * As there are series for every row of data, when performing actions such as adding a column to a chart that has it's series
+ * arranged by row, it will be necessary to modify every series within the chart. ChartSeriesHandle is available to
+ * make this process easier.
+ *
+ * @see ChartHandle
+ */
+
+class ChartSeriesHandle
+/**
+ * Constructor, used internally. For public use get series from a ChartHandle
+ *
+ * @param Series series
+ * @param WorkBook wbk - WorkBook the Chart is attached to
+ */
+(private val myseries: Series, private val wbh: WorkBookHandle) {
+
+ /**
+ * returns the Cell Range String representing the Data in this Series Object.
+ *
+ * @return String Cell Range representing Series Data e.g. Sheet1!A1:A12
+ */
+ /**
+ * sets the data for this Series to be obtained from a new Cell Range.
+ *
+ * Note that if you set the size of this series to a different amount of data than other Series
+ * in the chart you could have unexpected results.
+ *
+ * @param String seriesRange - a Cell Range representing Series Data e.g. Sheet1!A1:A12
+ */
+ // 20080215 KSC: Added
+ // ""
+ // 20070711 KSC: update value (series) count for series
+ var seriesRange: String
+ get() = myseries.seriesValueAi!!.toString()
+ set(seriesRange) {
+ myseries.parentChart!!.setMetricsDirty()
+ val ai = myseries.seriesValueAi
+ ai!!.parentChart = myseries.parentChart
+ ai.setSheet(myseries.parentChart!!.sheet)
+ if (ai.workBook == null) ai.workBook = wbh.workBook
+ ai.changeAiLocation(ai.toString(), seriesRange)
+ try {
+ val coords = io.starter.OpenXLS.ExcelTools.getRangeCoords(seriesRange)
+ myseries.valueCount = coords[4]
+ myseries.parentChart!!.setMetricsDirty()
+ } catch (e: Exception) {
+
+ }
+
+ }
+
+ /**
+ * returns the Cell Range String representing the Categories (usually the X Axis) for the Chart
+ * Note that Category typically stays constant for all Series in the Chart
+ *
+ * @return String Category Cell Range e.g. Sheet1!A1:C1
+ */
+ /**
+ * sets the Category from a new Cell Range.
+ *
+ *
+ * IMPORTANT! In most cases, the category should be set to the same Cell Range for all Series in the chart.
+ * This method is available for complex charts, but in most cases the ideal way to handle this call is through
+ * chartHandle.changeCategoryRange.
+ *
+ * @param String categoryRange - new Category Cell Range
+ */
+ // 20070711 KSC: update Category Count for this series
+ var categoryRange: String
+ get() = myseries.categoryValueAi!!.toString()
+ set(categoryRange) {
+ myseries.parentChart!!.setMetricsDirty()
+ val ai = myseries.categoryValueAi
+ if (ai!!.workBook == null) ai.workBook = wbh.workBook
+ ai.changeAiLocation(ai.toString(), categoryRange)
+ try {
+ val coords = io.starter.OpenXLS.ExcelTools.getRangeCoords(categoryRange)
+ myseries.categoryCount = coords[4]
+ myseries.parentChart!!.setMetricsDirty()
+ } catch (e: Exception) {
+
+ }
+
+ }
+
+ /**
+ * returns the Cell Range String representing Bubble Size for this Series (Bubble Charts only)
+ *
+ * @return String Bubble Sizes Cell Range e.g. Sheet1!A1:C1
+ */
+ val bubbleSizes: String
+ get() = myseries.bubbleValueAi!!.toString()
+
+ /**
+ * returns the Legend text for this Series
+ *
+ * @return String Legend text for this Series
+ * @see getSeriesLegendReference
+ */
+ /**
+ * Set the Legend text for this Series
+ * note: series legend will then not be linked to a particular cell. if you want to change the legend
+ * reference, use setSeriesLegendRef
+ *
+ * @param String legend - Legend Text
+ * @see setSeriesLegendRef
+ */
+ var seriesLegend: String
+ get() = myseries.legendText
+ set(legend) {
+ myseries.setLegend(legend, this.wbh)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * returns the Legend Cell Reference, if any
+ *
+ * @return String Cell Address representing the Legend for this Series
+ */
+ val seriesLegendReference: String?
+ get() {
+ val ai = myseries.legendAi
+ return ai?.definition
+ }
+
+ /**
+ * gets the Chart Category Data Type
+ *
+ * @return int Data Type of the Category
+ */
+ /**
+ * sets the Chart Category Data Type
+ *
+ * @param int i - Category Data Type
+ */
+ var categoryDataType: Int
+ get() = myseries.categoryDataType
+ set(i) {
+ myseries.categoryDataType = i
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * gets the Series Data Type
+ *
+ * @return int Data Type of this Series
+ */
+ /**
+ * sets the Series Data Type
+ *
+ * @param int i - Series Data Type
+ */
+ var seriesDataType: Int
+ get() = myseries.valueDataType
+ set(i) {
+ myseries.valueDataType = i
+ }
+
+ /**
+ * returns a constant that represents the bar shape for this Series
+ * This is an internal method that is not useful to the end user.
+ *
+ * @return int DataPoint shape for this Series (3d Bar, Pyramid ...)
+ */
+ /**
+ * sets the constant that represents the bar shape for this Series
+ * This is an internal method that is not useful to the end user.
+ *
+ * @param int shape - DataPoint shape for this Series (3d Bar, Pyramid ...)
+ */
+ var shape: Int
+ get() = myseries.shape
+ set(shape) {
+ myseries.shape = shape
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * returns the Series (bar or line) color
+ * NOTE: for Pie charts, use getPieChartSliceColor
+ *
+ * @return int color constant representing the Series color
+ * @see FormatHandle.COLOR_* constants
+ *
+ * @see getSeriesColorStr
+ *
+ */
+ /**
+ * sets the color for this Series (bar or line)
+ * NOTE: for Pie Charts, use setPieChartSliceColor
+ *
+ * @param int clr - color constant
+ * @see setPieChartSliceColor
+ *
+ * @see FormatHandle.COLOR_* constants
+ */
+ var seriesColor: Int
+ @Deprecated("")
+ get() = FormatHandle.HexStringToColorInt(myseries.seriesColor, FormatHandle.colorBACKGROUND)
+ set(clr) {
+ myseries.setColor(clr)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * returns the Series (bar or line) color hex string
+ * NOTE: for Pie charts, use getPieChartSliceColor
+ *
+ * @return int color constant representing the Series color
+ * @see FormatHandle.COLOR_* constants
+ *
+ * @see getPieChartSliceColor
+ */
+ val seriesColorStr: String
+ get() = myseries.seriesColor
+
+ /**
+ * returns true if this chart has Bubble Sizes
+ *
+ * @return
+ */
+ fun hasBubbleSizes(): Boolean {
+ return myseries.hasBubbleSizes()
+ }
+
+ /**
+ * set the Cell Range for the Bubbles in this Seeries (Bubble Chart Only)
+ *
+ * @param String bubbleSizes - Cell Range for Bubble Sizes
+ */
+ fun setBubbleRange(bubbleSizes: String?) {
+ if (bubbleSizes != null && bubbleSizes != "") {
+ myseries.parentChart!!.setMetricsDirty()
+ val ai = myseries.bubbleValueAi
+ if (ai!!.workBook == null) ai.workBook = wbh.workBook
+ ai.changeAiLocation(ai.toString(), bubbleSizes)
+ ai.setRt(2)
+ try { // also update Bubble Count for this series
+ val coords = io.starter.OpenXLS.ExcelTools.getRangeCoords(bubbleSizes)
+ myseries.bubbleCount = coords[4]
+ myseries.parentChart!!.setMetricsDirty()
+ } catch (e: Exception) {
+
+ }
+
+ }
+ }
+
+ /**
+ * sets Cell Address for the Series Legend
+ *
+ * @param String legendCell - Cell Address for Legend
+ */
+ fun setSeriesLegendRef(legendCell: String) {
+ myseries.legendRef = legendCell
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * defines this Series with Cell References for the Legend, Data Points, Category and Bubble Sizes,
+ * if applicable.
+ *
+ * @param String legendRef - Cell Address representing the Legend for this Series
+ * @param String series - Cell Range representing the Data Points for this Series
+ * @param String cat - Cell Range representing the Category for this Series
+ * (NOTE: The Category Cell Range is typically the same for every Series in the Chart)
+ * @param String bubble - Cell Range representing the Bubble Sizes for this Series (Bubble Chart only) or null if none
+ */
+ fun setSeries(legendRef: String, series: String, cat: String, bubble: String) {
+ this.setSeriesLegendRef(legendRef)
+ this.seriesRange = series
+ this.categoryRange = cat
+ this.setBubbleRange(bubble)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * sets the color for this series
+ *
+ * @param int seriesNumber - series index
+ * @param int clr - color constant
+ * @see setSeriesColor
+ */
+ @Deprecated("use setSeriesColor(int clr) instead")
+ fun setSeriesColor(seriesNumber: Int, clr: Int) {
+ myseries.setColor(clr)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * sets the color for this Series (bar or line)
+ * NOTE: for Pie Charts, use setPieChartSliceColor
+ *
+ * @param String color hex string
+ * @see setPieChartSliceColor
+ *
+ * @see FormatHandle.COLOR_* constants
+ */
+ fun setSeriesColor(clr: String) {
+ myseries.setColor(clr)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * sets the color for a particular Pie Chart slice or wedge
+ *
+ * @param int clr - color constant
+ * @param int slice - 0-based slice or point number
+ * @see FormatHandle.COLOR_* constants
+ */
+ fun setPieChartSliceColor(clr: Int, slice: Int) {
+ myseries.setPieSliceColor(clr, slice)
+ myseries.parentChart!!.setMetricsDirty()
+ }
+
+ /**
+ * returns the desired Pie chart slice color
+ *
+ * @param int slice - 0-based slice or wedge index
+ * @return int color constant repressenting the color for the desired pie slice
+ * @see FormatHandle.COLOR_* constants
+ *
+ */
+ @Deprecated("See getPieChartSliceColorStr")
+ fun getPieChartSliceColor(slice: Int): Int {
+ return FormatHandle.HexStringToColorInt(myseries.getPieSliceColor(slice)!!, FormatHandle.colorBACKGROUND)
+ }
+
+ /**
+ * returns the desired Pie chart slice color hex string
+ *
+ * @param int slice - 0-based slice or wedge index
+ * @return String color hex string representing the color for the desired pie slice
+ */
+ fun getPieChartSliceColorStr(slice: Int): String? {
+ return myseries.getPieSliceColor(slice)
+ }
+
+ /*
+ * returns the OOXML (Open Office XML) Shape Properties Object for this Series
+ * @return SpPr OOXML Shape Properties Object
+ * @see SpPr
+ *
+ public SpPr getSpPr() { return myseries.getSpPr(); }
+ */
+
+ /*
+ * sets the OOXML (Open Office XML) Shape Properties Object for this Series
+ * @param SpPr sp - OOXML Shape Properties Object
+ * @see SpPr
+ *
+ public void setSpPr(SpPr sp) {
+ myseries.setSpPr(sp);
+ }*/
+
+ /*
+ * returns the OOXML (Open Office XML) Marker Properties Object for this Series
+ * @return Marker -OOXML Marker Properties Object
+ * @see Marker
+ *
+ public Marker getMarker() { return myseries.getMarker(); }
+ */
+ /*
+ * sets the OOXML (Open Office XML) Marker Properties Object for this Series
+ * @param Marker m - the OOXML Marker Properties Object
+ * @see Marker
+ *
+ public void setMarker(Marker m) {
+ myseries.setMarker(m);
+ }*/
+
+ /*
+ * returns the OOXML (Open Office XML) Data Label Properties Object for this Series
+ * @return DLbls - OOXML Data Label Properties Object
+ *
+ public DLbls getDLbls() { return myseries.getDLbls(); }
+ */
+
+ /*
+ * sets the OOXML (Open Office XML) Data Label Properties Object for this Series
+ * @param Dlbls d- OOXML Data Label Properties Object
+ * @see DLbls
+ *
+ public void setDLbls(DLbls d) {
+ myseries.setDLbls(d);
+ }*/
+
+ /*
+ * returns an array of OOXML (Open Office XML) Data Point Properties Objects defining this Series
+ * @return DPt[] - Array of OOXML Data Point Properties Objects
+ * @see Dpt
+ *
+ public DPt[] getDPt() { return myseries.getDPt(); }*/
+ /*
+ * adds an OOXML (Open Office XML) Data Point Property Element to this Series
+ * @param DPt d- Data Point Properties Object
+ * @see DPt
+ *
+ public void addDpt(DPt d) {
+ myseries.addDpt(d);
+ }*/
+}
diff --git a/src/main/java/io/starter/OpenXLS/ColHandle.java b/src/main/java/io/starter/OpenXLS/ColHandle.java
deleted file mode 100644
index 571de60..0000000
--- a/src/main/java/io/starter/OpenXLS/ColHandle.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import io.starter.formats.XLS.*;
-import io.starter.toolkit.StringTool;
-
-import java.util.*;
-
-
-/** The ColHandle provides access to an Worksheet Column and its Cells.
-
- Use the ColHandle to work with individual Columns in an XLS file.
-
- With a ColHandle you can:
-
- get a handle to the Cells in a column
- set the default formatting for a column
-
-
- Note: for a discussion of Column widths see:
- http://support.microsoft.com/?kbid=214123
-
- @see WorkBookHandle
- @see WorkSheetHandle
- @see FormulaHandle
-*/
-public class ColHandle {
-
- // TODO: read 1st font in file to set DEFAULT_ZERO_CHAR_WIDTH ... eventually ...
- public static final double DEFAULT_ZERO_CHAR_WIDTH= 7.0; // width of '0' char in default font + conversion 1.3
- public static final int COL_UNITS_TO_PIXELS =(int) (256/DEFAULT_ZERO_CHAR_WIDTH); // = 36.57
- public static final int DEFAULT_COLWIDTH = Colinfo.DEFAULT_COLWIDTH;
-
- private Colinfo myCol;
- private FormatHandle formatter;
- private WorkBook wbh;
- private WorkSheetHandle mySheet;
-
- /**
- * creates a new ColHandle from a Colinfo Object and reference to a worksheet (WorkSheetHandle Object)
- * @param c
- * @param sheet
- */
- protected ColHandle(Colinfo c, WorkSheetHandle sheet){
- myCol = c;
- wbh = sheet.getWorkBook();
- mySheet = sheet;
- }
-
- private int lastsz = 0; // the last checked col width
-
- /** resizes this column to fit the width of all displayed, non-wrapped text.
- * NOTE: as the Excel autofit implementation is undocumented, this is an approximation
- *
- */
- public void autoFit() {
- // KSC: make more betta :)
- double w= 0;
- CellHandle[] cxt = this.getCells();
- for(int t=0;tlastsz)
- this.setWidth(csz*factor);
- */
- }
- if (w==0)
- return; // keep original width ... that's what Excel does for blank columns ...
- // convert pixels to excel column units basically OpenXLS.COLUNITSTOPIXELS in double form
- this.setWidth((int)Math.floor((w/DEFAULT_ZERO_CHAR_WIDTH)*256.0));
- }
-
-
- /** sets the width of this Column in Characters or Excel units.
- *
- The default Excel column width is set to 8.43 Characters,
- based on the default font and font size,
-
- NOTE: The last Cell in the column having its width
- set will be the resulting width of the column
- @param int i - desired Column width in Characters (Excel units)
- */
- public void setWidthInChars(int newWidth){
- /* if an image falls upon this column,
- * adjust image width so that it does not change
- */
- ArrayList iAdjust= new ArrayList();
- ImageHandle[] images= myCol.getSheet().getImages();
- if(images!=null) {
- // for each image that falls over this column, trap index + original width -- to be reset after setting col width
- for (int z= 0; z < images.length; z++) {
- ImageHandle ih= images[z];
- int c0= ih.getCol();
- int c1= ih.getCol1();
- int col= myCol.getColFirst(); // should only be one, right?
- if (col>=c0 && col<=c1) {
- int w= ih.getWidth();
- iAdjust.add(new int[]{z,w});
- }
- }
- }
-
- myCol.setColWidthInChars(newWidth);
- for (int z= 0; z < iAdjust.size(); z++) {
- ImageHandle ih= images[((int[]) iAdjust.get(z))[0]];
- ih.setWidth(((int[]) iAdjust.get(z))[1]);
- }
- }
-
- /** sets the width of this Column in internal units, described as follows:
- *
- * default width of the columns in 1/256 of the width of the zero character,
- * using default font.
- The Default Excel Column, whose width in Characters or Excel Units, is 8.43, has a width in these units of 2300.
- NOTE:
- The last Cell in the column having its width
- set will be the resulting width of the column
- @param int i - desired Column width in internal units
- */
- public void setWidth(int newWidth){
- /* if an image falls upon this column,
- * adjust image width so that it does not change
- */
- ArrayList iAdjust= new ArrayList();
- ImageHandle[] images= myCol.getSheet().getImages();
- if(images!=null) {
- // for each image that falls over this column, trap index + original width -- to be reset after setting col width
- for (int z= 0; z < images.length; z++) {
- ImageHandle ih= images[z];
- int c0= ih.getCol();
- int c1= ih.getCol1();
- int col= myCol.getColFirst(); // should only be one, right?
- if (col>=c0 && col<=c1) {
- int w= ih.getWidth();
- iAdjust.add(new int[]{z,w});
- }
- }
- }
- lastsz = newWidth;
- myCol.setColWidth(newWidth);
- // now adjust any of the images that we noted above
- for (int z= 0; z < iAdjust.size(); z++) {
- ImageHandle ih= images[((int[]) iAdjust.get(z))[0]];
- ih.setWidth(((int[]) iAdjust.get(z))[1]);
- }
- }
-
- /** returns the width of this Column in internal units
- defined as follows:
- *
- * default width of the columns in 1/256 of the width of the zero character,
- * using default font.
- The Default Excel Column, whose width in Excel Units or Characters is 8.43, has a width in these units of 2300.
- @return int Column width in internal units
- */
- public int getWidth(){
- return myCol.getColWidth();
- }
-
-
- /**
- * returns the width of this Column in Characters or regular Excel units
- * NOTE: this value is a calculated value that should be close but still is an approximation of Excel units
- * @return int Column width in Excel units
- */
- public int getWidthInChars() {
- return myCol.getColWidthInChars();
- }
- /**
- * static utility method to return the Column width of an existing column
- in the units as follows:
- *
- * default width of the columns in 1/256 of the width of the zero character,
- * using default font.
- * For Arial 10 point, the default width of the zero character = 7
- The Default Excel Column, whose width in Characters or Excel Units is 8.43, has a width in these units of 2300.
- * @param Boundsheet sheet - source Worksheet
- * @param int col - 0-based Column number
- * @return int - Column width in internal units
- */
- public static int getWidth(Boundsheet sheet, int col) {
- int w= Colinfo.DEFAULT_COLWIDTH;
- try {
- Colinfo c = sheet.getColInfo(col);
- if(c!=null)
- w= (int) c.getColWidth();
- } catch (Exception e) { // exception if no col defined
- }
- return w;
- }
-
-
- /** sets the format id (an index to a Format record) for this Column
- * This sets the default formatting for the Column
- * such that any cell that does not specifically set it's own formatting
- * will display this Column formatting
- @param int i - ID representing the Format to set this Column
- @see FormatHandle
- */
- public void setFormatId(int i){
- myCol.setIxfe(i);
- }
-
- /**
- * returns the format ID (the index to the format record) for this Column
- * The Column format is the default formatting for each cell contained
- * within the column
- * @return int formatId - the index of the format record for this Column
- @see FormatHandle
- */
- public int getFormatId() {
- return myCol.getIxfe();
- }
-
- /** returns the FormatHandle (a Format Object describing visual properties) for this Column
- * NOTE: The Column format record describes the default formatting for each cell contained
- * within the column
- @return FormatHandle - a Format object to apply to this Col
-*/
- public FormatHandle getFormatHandle(){
- if(this.formatter==null)this.setFormatHandle();
- return this.formatter;
- }
-
- /**
- * sets the FormatHandle (a Format Object describing visual properties) for this Column
- * NOTE: The Column format record describes the default formatting for each cell contained
- * within the column
- */
- private void setFormatHandle() {
- if(formatter!=null)return;
- formatter = new FormatHandle(wbh, this.getFormatId());
- formatter.setColHandle(this);
- }
-
- /** returns the first Column referenced by this column handle
- * NOTE: A Column handle may in some circumstances refer to a range of columns
- *
- * @return int first column number referenced by this Column handle
- */
- public int getColFirst() {
- return myCol.getColFirst();
- }
-
- /** returns the last Column referenced by this column handle
- * NOTE: A Column handle may in some circumstances refer to a range of columns
- *
- * @return int last column number referenced by this Column handle
- */
- public int getColLast() {
- return myCol.getColLast();
- }
-
-
- /** returns the array of Cells in this Column
- * @return CellHandle array
- */
- public CellHandle[] getCells(){
- List> mycells;
- try {
- mycells = this.mySheet.getBoundsheet().getCellsByCol(this.getColFirst());
- } catch (CellNotFoundException e) {
- return new CellHandle[0];
- }
- CellHandle[] ch = new CellHandle[mycells.size()];
- for(int t = 0;t .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.*
+import io.starter.toolkit.StringTool
+
+import java.util.ArrayList
+
+
+/**
+ * The ColHandle provides access to an Worksheet Column and its Cells.
+ *
+ * Use the ColHandle to work with individual Columns in an XLS file.
+ *
+ * With a ColHandle you can:
+ *
+ * get a handle to the Cells in a column
+ * set the default formatting for a column
+ *
+ *
+ *
+ * Note: for a discussion of Column widths see:
+ * http://support.microsoft.com/?kbid=214123
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see FormulaHandle
+ */
+class ColHandle
+/**
+ * creates a new ColHandle from a Colinfo Object and reference to a worksheet (WorkSheetHandle Object)
+ *
+ * @param c
+ * @param sheet
+ */
+(private val myCol: Colinfo, private val mySheet: WorkSheetHandle) {
+ private var formatter: FormatHandle? = null
+ private val wbh: WorkBook?
+
+ private var lastsz = 0 // the last checked col width
+
+ /**
+ * returns the width of this Column in internal units
+ * defined as follows:
+ *
+ * default width of the columns in 1/256 of the width of the zero character,
+ * using default font.
+ * The Default Excel Column, whose width in Excel Units or Characters is 8.43, has a width in these units of 2300.
+ *
+ * @return int Column width in internal units
+ */
+ /**
+ * sets the width of this Column in internal units, described as follows:
+ *
+ * default width of the columns in 1/256 of the width of the zero character,
+ * using default font.
+ * The Default Excel Column, whose width in Characters or Excel Units, is 8.43, has a width in these units of 2300.
+ *
+ * NOTE:
+ * The last Cell in the column having its width
+ * set will be the resulting width of the column
+ *
+ * @param int i - desired Column width in internal units
+ */
+ /* if an image falls upon this column,
+ * adjust image width so that it does not change
+ */// for each image that falls over this column, trap index + original width -- to be reset after setting col width
+ // should only be one, right?
+ // now adjust any of the images that we noted above
+ var width: Int
+ get() = myCol.colWidth
+ set(newWidth) {
+ val iAdjust = ArrayList()
+ val images = myCol.sheet!!.images
+ if (images != null) {
+ for (z in images.indices) {
+ val ih = images[z]
+ val c0 = ih.col
+ val c1 = ih.col1
+ val col = myCol.colFirst
+ if (col >= c0 && col <= c1) {
+ val w = ih.width.toInt()
+ iAdjust.add(intArrayOf(z, w))
+ }
+ }
+ }
+ lastsz = newWidth
+ myCol.colWidth = newWidth
+ for (z in iAdjust.indices) {
+ val ih = images!![iAdjust[z][0]]
+ ih.setWidth(iAdjust[z][1])
+ }
+ }
+
+
+ /**
+ * returns the width of this Column in Characters or regular Excel units
+ * NOTE: this value is a calculated value that should be close but still is an approximation of Excel units
+ *
+ * @return int Column width in Excel units
+ */
+ /**
+ * sets the width of this Column in Characters or Excel units.
+ *
+ * The default Excel column width is set to 8.43 Characters,
+ * based on the default font and font size,
+ *
+ * NOTE: The last Cell in the column having its width
+ * set will be the resulting width of the column
+ *
+ * @param int i - desired Column width in Characters (Excel units)
+ */
+ /* if an image falls upon this column,
+ * adjust image width so that it does not change
+ */// for each image that falls over this column, trap index + original width -- to be reset after setting col width
+ // should only be one, right?
+ var widthInChars: Int
+ get() = myCol.colWidthInChars
+ set(newWidth) {
+ val iAdjust = ArrayList()
+ val images = myCol.sheet!!.images
+ if (images != null) {
+ for (z in images.indices) {
+ val ih = images[z]
+ val c0 = ih.col
+ val c1 = ih.col1
+ val col = myCol.colFirst
+ if (col >= c0 && col <= c1) {
+ val w = ih.width.toInt()
+ iAdjust.add(intArrayOf(z, w))
+ }
+ }
+ }
+
+ myCol.setColWidthInChars(newWidth.toDouble())
+ for (z in iAdjust.indices) {
+ val ih = images!![iAdjust[z][0]]
+ ih.setWidth(iAdjust[z][1])
+ }
+ }
+
+ /**
+ * returns the format ID (the index to the format record) for this Column
+ * The Column format is the default formatting for each cell contained
+ * within the column
+ *
+ * @return int formatId - the index of the format record for this Column
+ * @see FormatHandle
+ */
+ /**
+ * sets the format id (an index to a Format record) for this Column
+ * This sets the default formatting for the Column
+ * such that any cell that does not specifically set it's own formatting
+ * will display this Column formatting
+ *
+ * @param int i - ID representing the Format to set this Column
+ * @see FormatHandle
+ */
+ var formatId: Int
+ get() = myCol.ixfe
+ set(i) {
+ myCol.ixfe = i
+ }
+
+ /**
+ * returns the FormatHandle (a Format Object describing visual properties) for this Column
+ * NOTE: The Column format record describes the default formatting for each cell contained
+ * within the column
+ *
+ * @return FormatHandle - a Format object to apply to this Col
+ */
+ val formatHandle: FormatHandle?
+ get() {
+ if (this.formatter == null) this.setFormatHandle()
+ return this.formatter
+ }
+
+ /**
+ * returns the first Column referenced by this column handle
+ * NOTE: A Column handle may in some circumstances refer to a range of columns
+ *
+ * @return int first column number referenced by this Column handle
+ */
+ val colFirst: Int
+ get() = myCol.colFirst
+
+ /**
+ * returns the last Column referenced by this column handle
+ * NOTE: A Column handle may in some circumstances refer to a range of columns
+ *
+ * @return int last column number referenced by this Column handle
+ */
+ val colLast: Int
+ get() = myCol.colLast
+
+
+ /**
+ * returns the array of Cells in this Column
+ *
+ * @return CellHandle array
+ */
+ val cells: Array
+ get() {
+ val mycells: List<*>
+ try {
+ mycells = this.mySheet.boundsheet!!.getCellsByCol(this.colFirst)
+ } catch (e: CellNotFoundException) {
+ return arrayOfNulls(0)
+ }
+
+ val ch = arrayOfNulls(mycells.size)
+ for (t in ch.indices) {
+ ch[t] = CellHandle(mycells[t] as BiffRec, null)
+ ch[t].workSheetHandle = null
+ }
+ return ch
+ }
+
+ /**
+ * Returns the Outline level (depth) of this Column
+ *
+ * @return int outline level
+ */
+ /**
+ * Set the Outline level (depth) of this Column
+ *
+ * @param int x - outline level
+ */
+ var outlineLevel: Int
+ get() = myCol.outlineLevel
+ set(x) {
+ this.myCol.outlineLevel = x
+ }
+
+ /**
+ * returns true if this Column is collapsed
+ *
+ * @return true if ths Column is collapsed, false otherwise
+ */
+ /**
+ * sets whether to collapse this Column
+ *
+ * @param boolean b - true to collapse this Column
+ */
+ var isCollapsed: Boolean
+ get() = myCol.isCollapsed
+ set(b) {
+ this.myCol.isCollapsed = b
+ }
+
+ /**
+ * returns true if this Column is hidden
+ *
+ * @return true if this Column is hidden, false if not
+ */
+ /**
+ * sets whether to hide or show this Column
+ *
+ * @param boolean b - true to hide this Column, false to show
+ */
+ var isHidden: Boolean
+ get() = myCol.isHidden
+ set(b) {
+ this.myCol.isHidden = b
+ }
+
+ init {
+ wbh = mySheet.workBook
+ }
+
+ /**
+ * resizes this column to fit the width of all displayed, non-wrapped text.
+ * NOTE: as the Excel autofit implementation is undocumented, this is an approximation
+ */
+ fun autoFit() {
+ // KSC: make more betta :)
+ var w = 0.0
+ val cxt = this.cells
+ for (t in cxt.indices) {
+ val s = cxt[t].formattedStringVal //StringVal();
+ val fh = cxt[t].formatHandle
+ val ef = fh!!.font
+ var style = java.awt.Font.PLAIN
+ if (ef!!.bold) style = style or java.awt.Font.BOLD
+ if (ef.italic) style = style or java.awt.Font.ITALIC
+ val h = ef.fontHeightInPoints.toInt()
+ val f = java.awt.Font(ef.fontName, style, h)
+ var newW = 0.0
+ if (!cxt[t].formatHandle!!.wrapText)
+ // normal case, no wrap
+ newW = StringTool.getApproximateStringWidth(f, s)
+ else
+ // wrap - use current column width?????
+ newW = (this.width / COL_UNITS_TO_PIXELS).toDouble()
+ w = Math.max(w, newW)
+ /*
+ int strlen = cstr.length();
+ int csz = strlen *= cxt[t].getFontSize();
+ int factor= 28; // KSC: was 50 + added factor to guard below
+ if((csz*factor)>lastsz)
+ this.setWidth(csz*factor);
+ */
+ }
+ if (w == 0.0)
+ return // keep original width ... that's what Excel does for blank columns ...
+ // convert pixels to excel column units basically OpenXLS.COLUNITSTOPIXELS in double form
+ this.width = Math.floor(w / DEFAULT_ZERO_CHAR_WIDTH * 256.0).toInt()
+ }
+
+ /**
+ * sets the FormatHandle (a Format Object describing visual properties) for this Column
+ * NOTE: The Column format record describes the default formatting for each cell contained
+ * within the column
+ */
+ private fun setFormatHandle() {
+ if (formatter != null) return
+ formatter = FormatHandle(wbh!!, this.formatId)
+ formatter!!.setColHandle(this)
+ }
+
+ /**
+ * determines if this Column passes through i.e. contains a
+ * horizontal merge range
+ *
+ * @return true if this Column is part of any merge (horizontally merged cells)
+ */
+ fun containsMergeRange(): Boolean {
+ val r = mySheet.rows
+ for (i in r.indices) {
+ val b: BiffRec?
+ try {
+ b = r[i].myRow.getCell(this.colFirst.toShort())
+ if (b != null && b.mergeRange != null) return true
+ } catch (e: CellNotFoundException) {
+ }
+
+ }
+ return false
+ }
+
+ companion object {
+
+ // TODO: read 1st font in file to set DEFAULT_ZERO_CHAR_WIDTH ... eventually ...
+ val DEFAULT_ZERO_CHAR_WIDTH = 7.0 // width of '0' char in default font + conversion 1.3
+ val COL_UNITS_TO_PIXELS = (256 / DEFAULT_ZERO_CHAR_WIDTH).toInt() // = 36.57
+ val DEFAULT_COLWIDTH = Colinfo.DEFAULT_COLWIDTH
+
+ /**
+ * static utility method to return the Column width of an existing column
+ * in the units as follows:
+ *
+ * default width of the columns in 1/256 of the width of the zero character,
+ * using default font.
+ * For Arial 10 point, the default width of the zero character = 7
+ * The Default Excel Column, whose width in Characters or Excel Units is 8.43, has a width in these units of 2300.
+ *
+ * @param Boundsheet sheet - source Worksheet
+ * @param int col - 0-based Column number
+ * @return int - Column width in internal units
+ */
+ fun getWidth(sheet: Boundsheet, col: Int): Int {
+ var w = Colinfo.DEFAULT_COLWIDTH
+ try {
+ val c = sheet.getColInfo(col)
+ if (c != null)
+ w = c.colWidth
+ } catch (e: Exception) { // exception if no col defined
+ }
+
+ return w
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/CommentHandle.java b/src/main/java/io/starter/OpenXLS/CommentHandle.java
deleted file mode 100644
index 585df67..0000000
--- a/src/main/java/io/starter/OpenXLS/CommentHandle.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import io.starter.formats.XLS.Note;
-import io.starter.toolkit.Logger;
-
-/**
- * CommentHandle allows for manipulation of the Note or Comment feature of Excel
- *
- * In order to create CommentHandles programatically use the methods in WorkSheetHandle or CellHandle
- *
- *
- *
- */
-public class CommentHandle implements Handle {
-
- private Note note;
-
- /**
- * Creates a new CommentHandle object
- * For internal use only
- * @param n
- */
- protected CommentHandle(Note n) {
- this.note= n;
- }
-
- /**
- * Returns the text of the Note (Comment)
- * @return String value or text of Note
- */
- public String getCommentText() {
- if (note!=null)
- return note.getText();
- return null;
- }
-
- /**
- * Sets the text of the Note (Comment).
- * The text may contain embedded formatting information as follows:
- * < font specifics>text segment< font specifics for next segment>text segment...
- * where font specifics can be one or more of (all are optional):
- * b - bold
- * i - italic
- * s - strikethru
- * u - underlined
- * f="" - font name surrounded by quotes e.g. "Tahoma"
- * sz="" - font size in points surrounded by quotes e.g. "10"
- * Each option must be delimited by ;'s
- * For Example:
- * "<f=\"Tahoma\";b;sz=\"16\">Note: <f=\"Cambria\";sz=\"12\">This is an important point"
- * To reset to the default font, input an empty format: <> e.g.:
- * "<b;i;sz=\"8\">Note:<>This is an important comment"
- * @param text - String text of Note
- */
- public void setCommentText(String text) {
- if (note!=null) {
- try {
- note.setText(text);
- } catch (IllegalArgumentException e) {
- Logger.logErr(e.toString());
- }
- }
- }
-
- /** returns the author of this Note (Comment) if set
- * @return String author
- */
- public String getAuthor() {
- if (note!=null)
- return note.getAuthor();
- return null;
- }
- /**
- * sets the author of this Note (Comment)
- * @param author
- */
- public void setAuthor(String author) {
- if (note!=null) note.setAuthor(author);
- }
-
- /**
- * Removes or deletes this Note (Comment) from the worksheet
- */
- public void remove() {
- note.getSheet().removeNote(note);
- note= null;
- }
-
- /**
- * Sets this Note (Comment) to always show, even when the attached cell loses focus
- */
- public void show() {
- if (note!=null) note.setHidden(false);
- }
-
- /**
- * Sets this Note (Comment) to be hidden until the attached cell has focus
- *
- * This is the default state of note records
- */
- public void hide() {
- if (note!=null) note.setHidden(true);
- }
-
- /**
- * Returns true if this Note (Comment) is hidden until focus
- * @return
- */
- public boolean getIsHidden() {
- if (note!=null)
- return note.getHidden();
- return false;
- }
-
- /**
- * Sets this Note (Comment) to be attached to a cell at [row, col]
- * @param row int row number (0-based)
- * @param col int column number (0-based)
- */
- public void setRowCol(int row, int col) {
- if (note!=null)
- note.setRowCol(row, col);
- }
-
- /**
- * Returns the address this Note (Comment) is attached to
- * @return String Cell Address
- */
- public String getAddress() {
- if (note!=null)
- return note.getCellAddressWithSheet();
- return null;
- }
-
- /**
- * return the String representation of this CommentHandle
- */
- public String toString() {
- if (note!=null)
- return note.toString();
- return "Not initialized";
- }
-
- /**
- * return the Row number (0-based) this Note is attached to
- * @return 0-based row number
- */
- public int getRowNum() {
- if (note!=null)
- return note.getRowNumber();
- return -1;
- }
-
- /**
- * return the Column this note is attached to
- * @return Column number as an integer e.g. A=0, B=1 ...
- */
- public int getColNum() {
- if (note!=null)
- return note.getColNumber();
- return -1;
- }
-
- /**
- * Sets the width and height of the bounding text box of the note
- * Units are in pixels
- * NOTE: the height algorithm w.r.t. varying row heights is not 100%
- * @param width short desired text box width in pixels
- * @param height short desired text box height in pixels
- *
- */
- public void setTextBoxSize(int width, int height) {
- if (note!=null) {
- note.setTextBoxWidth((short) width);
- note.setTextBoxHeight((short) height);
- }
- }
-
- /**
- * returns the bounds (size and position) of the Text Box for this Note
- * bounds are relative and based upon rows, columns and offsets within
- * bounds are as follows:
- bounds[0]= column # of top left position (0-based) of the shape
- bounds[1]= x offset within the top-left column (0-1023)
- bounds[2]= row # for top left corner
- bounds[3]= y offset within the top-left corner (0-1023)
- bounds[4]= column # of the bottom right corner of the shape
- bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
- bounds[6]= row # for bottom-right corner of the shape
- bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
- * @return
- */
- public short[] getTextBoxBounds() {
- if (note!=null)
- return note.getTextBoxBounds();
- return null;
- }
-
- /**
- * Sets the bounds (size and position) of the Text Box for this Note
- * bounds are relative and based upon rows, columns and offsets within
- * bounds are as follows:
- bounds[0]= column # of top left position (0-based) of the shape
- bounds[1]= x offset within the top-left column (0-1023)
- bounds[2]= row # for top left corner
- bounds[3]= y offset within the top-left corner (0-1023)
- bounds[4]= column # of the bottom right corner of the shape
- bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
- bounds[6]= row # for bottom-right corner of the shape
- bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
- */
- public void setTextBoxBounds(short[] bounds) {
- if (note!=null)
- note.setTextBoxBounds(bounds);
- }
-
-
-
- /**
- * Returns the internal note record for this CommentHandle.
- *
- * Be aware that this note record should not be modified directly, and that this
- * method is only for internal application use.
- *
- * @return Name record
- */
- public Note getInternalNoteRec() {
- return note;
- }
- /**
- * Returns the OOXML representation of this Note object
- * @param authId 0-based author index for the author linked to this Note
- * @return String OOMXL representation
- */
- public String getOOXML(int authId) {
- StringBuffer ooxml= new StringBuffer();
- // TODO: Handle FORMATS
- ooxml.append("");
- ooxml.append(note.getOOXML());
- ooxml.append(" ");
- return ooxml.toString();
- }
-
-}
-
diff --git a/src/main/java/io/starter/OpenXLS/CommentHandle.kt b/src/main/java/io/starter/OpenXLS/CommentHandle.kt
new file mode 100644
index 0000000..020e9e6
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/CommentHandle.kt
@@ -0,0 +1,256 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.Note
+import io.starter.toolkit.Logger
+
+/**
+ *
+ * CommentHandle allows for manipulation of the Note or Comment feature of Excel
+ *
+ * In order to create CommentHandles programatically use the methods in WorkSheetHandle or CellHandle
+ *
+ *
+ */
+class CommentHandle
+/**
+ * Creates a new CommentHandle object
+ * For internal use only
+ *
+ * @param n
+ */
+(n: Note) : Handle {
+
+ /**
+ * Returns the internal note record for this CommentHandle.
+ *
+ *
+ * Be aware that this note record should not be modified directly, and that this
+ * method is only for internal application use.
+ *
+ * @return Name record
+ */
+ var internalNoteRec: Note? = null
+ private set
+
+ /**
+ * Returns the text of the Note (Comment)
+ *
+ * @return String value or text of Note
+ */
+ /**
+ * Sets the text of the Note (Comment).
+ *
+ * The text may contain embedded formatting information as follows:
+ * < font specifics>text segment< font specifics for next segment>text segment...
+ * where font specifics can be one or more of (all are optional):
+ * b - bold
+ * i - italic
+ * s - strikethru
+ * u - underlined
+ * f="" - font name surrounded by quotes e.g. "Tahoma"
+ * sz="" - font size in points surrounded by quotes e.g. "10"
+ * Each option must be delimited by ;'s
+ * For Example:
+ * "<f=\"Tahoma\";b;sz=\"16\">Note: <f=\"Cambria\";sz=\"12\">This is an important point"
+ * To reset to the default font, input an empty format: <> e.g.:
+ * "<b;i;sz=\"8\">Note:<>This is an important comment"
+ *
+ * @param text - String text of Note
+ */
+ var commentText: String?
+ get() = if (internalNoteRec != null) internalNoteRec!!.text else null
+ set(text) {
+ if (internalNoteRec != null) {
+ try {
+ internalNoteRec!!.text = text
+ } catch (e: IllegalArgumentException) {
+ Logger.logErr(e.toString())
+ }
+
+ }
+ }
+
+ /**
+ * returns the author of this Note (Comment) if set
+ *
+ * @return String author
+ */
+ /**
+ * sets the author of this Note (Comment)
+ *
+ * @param author
+ */
+ var author: String?
+ get() = if (internalNoteRec != null) internalNoteRec!!.author else null
+ set(author) {
+ if (internalNoteRec != null) internalNoteRec!!.author = author
+ }
+
+ /**
+ * Returns true if this Note (Comment) is hidden until focus
+ *
+ * @return
+ */
+ val isHidden: Boolean
+ get() = if (internalNoteRec != null) internalNoteRec!!.hidden else false
+
+ /**
+ * Returns the address this Note (Comment) is attached to
+ *
+ * @return String Cell Address
+ */
+ val address: String?
+ get() = if (internalNoteRec != null) internalNoteRec!!.cellAddressWithSheet else null
+
+ /**
+ * return the Row number (0-based) this Note is attached to
+ *
+ * @return 0-based row number
+ */
+ val rowNum: Int
+ get() = if (internalNoteRec != null) internalNoteRec!!.rowNumber else -1
+
+ /**
+ * return the Column this note is attached to
+ *
+ * @return Column number as an integer e.g. A=0, B=1 ...
+ */
+ val colNum: Int
+ get() = if (internalNoteRec != null) internalNoteRec!!.colNumber.toInt() else -1
+
+ /**
+ * returns the bounds (size and position) of the Text Box for this Note
+ * bounds are relative and based upon rows, columns and offsets within
+ * bounds are as follows:
+ * bounds[0]= column # of top left position (0-based) of the shape
+ * bounds[1]= x offset within the top-left column (0-1023)
+ * bounds[2]= row # for top left corner
+ * bounds[3]= y offset within the top-left corner (0-1023)
+ * bounds[4]= column # of the bottom right corner of the shape
+ * bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
+ * bounds[6]= row # for bottom-right corner of the shape
+ * bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
+ *
+ * @return
+ */
+ /**
+ * Sets the bounds (size and position) of the Text Box for this Note
+ * bounds are relative and based upon rows, columns and offsets within
+ * bounds are as follows:
+ * bounds[0]= column # of top left position (0-based) of the shape
+ * bounds[1]= x offset within the top-left column (0-1023)
+ * bounds[2]= row # for top left corner
+ * bounds[3]= y offset within the top-left corner (0-1023)
+ * bounds[4]= column # of the bottom right corner of the shape
+ * bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
+ * bounds[6]= row # for bottom-right corner of the shape
+ * bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
+ */
+ var textBoxBounds: ShortArray?
+ get() = if (internalNoteRec != null) internalNoteRec!!.textBoxBounds else null
+ set(bounds) {
+ if (internalNoteRec != null)
+ internalNoteRec!!.textBoxBounds = bounds
+ }
+
+ init {
+ this.internalNoteRec = n
+ }
+
+ /**
+ * Removes or deletes this Note (Comment) from the worksheet
+ */
+ fun remove() {
+ internalNoteRec!!.sheet!!.removeNote(internalNoteRec!!)
+ internalNoteRec = null
+ }
+
+ /**
+ * Sets this Note (Comment) to always show, even when the attached cell loses focus
+ */
+ fun show() {
+ if (internalNoteRec != null) internalNoteRec!!.hidden = false
+ }
+
+ /**
+ * Sets this Note (Comment) to be hidden until the attached cell has focus
+ *
+ *
+ * This is the default state of note records
+ */
+ fun hide() {
+ if (internalNoteRec != null) internalNoteRec!!.hidden = true
+ }
+
+ /**
+ * Sets this Note (Comment) to be attached to a cell at [row, col]
+ *
+ * @param row int row number (0-based)
+ * @param col int column number (0-based)
+ */
+ fun setRowCol(row: Int, col: Int) {
+ if (internalNoteRec != null)
+ internalNoteRec!!.setRowCol(row, col)
+ }
+
+ /**
+ * return the String representation of this CommentHandle
+ */
+ override fun toString(): String {
+ return if (internalNoteRec != null) internalNoteRec!!.toString() else "Not initialized"
+ }
+
+ /**
+ * Sets the width and height of the bounding text box of the note
+ * Units are in pixels
+ * NOTE: the height algorithm w.r.t. varying row heights is not 100%
+ *
+ * @param width short desired text box width in pixels
+ * @param height short desired text box height in pixels
+ */
+ fun setTextBoxSize(width: Int, height: Int) {
+ if (internalNoteRec != null) {
+ internalNoteRec!!.setTextBoxWidth(width.toShort())
+ internalNoteRec!!.setTextBoxHeight(height.toShort())
+ }
+ }
+
+ /**
+ * Returns the OOXML representation of this Note object
+ *
+ * @param authId 0-based author index for the author linked to this Note
+ * @return String OOMXL representation
+ */
+ fun getOOXML(authId: Int): String {
+ val ooxml = StringBuffer()
+ // TODO: Handle FORMATS
+ ooxml.append("")
+ ooxml.append(internalNoteRec!!.ooxml)
+ ooxml.append(" ")
+ return ooxml.toString()
+ }
+
+}
+
diff --git a/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.java b/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.java
deleted file mode 100644
index 3de56ba..0000000
--- a/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-import java.util.ArrayList;
-
-import io.starter.formats.XLS.Cf;
-import io.starter.formats.XLS.Condfmt;
-import io.starter.toolkit.Logger;
-/**
- * ConditionalFormatHandle allows for manipulation of the ConditionalFormat cells in Excel
- *
- * Using the ConditionalFormatHandle, the affected range of ConditionalFormats can be modified,
- * along with the formatting applied to the cells when the condition is true.
- *
- * Each ConditionalFormatHandle represents a range of cells and can have a number
- * of formatting rules and formats (ConditionalFormatRule) applied.
- *
- * The ConditionalFormatHandle affected range can either be a contiguous range, or a series of cells and ranges.
- *
- * Each ConditionalFormatRule contains one rule and corresponding format data.
- *
- *
- * Many of these calls are very self-explanatory and can be found in the api.
- *
- *
- */
-public class ConditionalFormatHandle implements Handle {
-
-
- private Condfmt cndfmt = null;
- private WorkSheetHandle worksheet;
-
-
- /**
- * evaluates the criteria for this Conditional Format
- * if the criteria involves a comparison i.e. equals, less than, etc., it uses the
- * value from the passed in referenced cell to compare with
- *
- * If there are multiple rules in the ConditionalFormat then the first rule that passes will be returned.
- *
- * If no valid rules pass then a null result is given
- *
- * @return the ConditionalFormatRule that passes.
- * @param CellHandle refcell - the cell to obtain a value from in order for evaluation to occur
- * @see io.starter.formats.XLS.Cf#evaluate(io.starter.formats.XLS.formulas.Ptg)
- */
- public ConditionalFormatRule evaluate(CellHandle refcell) {
- ConditionalFormatRule[] rules = this.getRules();
- for (int i=0;i cfs = this.cndfmt.getRules();
- ConditionalFormatRule[] rules = new ConditionalFormatRule[cfs.size()];
- for(int i=0;i" );
- if(rules[0].getFirstCondition()!=null) {
- xml.append("" );
- xml.append(rules[0].getFirstCondition());
- xml.append(" " );
- }
- if(rules[0].getSecondCondition()!=null) {
- xml.append("" );
- xml.append(rules[0].getSecondCondition());
- xml.append(" " );
- }
- xml.append("");
- return xml.toString();
- }
- /**
- * return a string representation of this Conditional Format
- *
- * This method is still incomplete as it only returns data for one rule, and only refers to one range
- */
- // TODO: more than one cf rule???
- public String toString(){
- ConditionalFormatRule[] rules = this.getRules();
- String ret= this.getEncompassingRange() + ": " + rules[0].getType() + " " + rules[0].getOperator(); // range, type + operator
- if (rules[0].getFormula1()!=null) // formulas
- ret+= " " + rules[0].getFormula1().getFormulaString().substring(1);
- if (rules[0].getFormula2()!=null)
- ret+= " and " + rules[0].getFormula2().getFormulaString().substring(1);
- // todo: add formats to this
- return ret;
- }
-
- /**
- * @return Returns the cndfmt.
- */
- protected Condfmt getCndfmt() {
- return cndfmt;
- }
-
- /**
- * @param cndfmt The cndfmt to set.
- */
- protected void setCndfmt(Condfmt cndfmt) {
- this.cndfmt = cndfmt;
- }
-
-
- /**
- * Add a cell to this conditional format record
- * @param cellHandle
- */
- public void addCell(CellHandle cellHandle) {
- if (this.contains(cellHandle))return;
- cndfmt.addLocation(cellHandle.getCellAddress());
- }
-
- /**
- * returns the formatting for each rule of this Contditional Format Handle
- * @return FormatHandle[]
- */
- public FormatHandle[] getFormats() {
- FormatHandle[] fmx = new FormatHandle[this.getCndfmt().getRules().size()];
- if (cndfmt.getFormatHandle()==null) {
- //cfm.initCells(this); // added!
- int cfxe= cndfmt.getCfxe();
- FormatHandle fz = new FormatHandle(cndfmt, worksheet.wbh, cfxe, null);
- }
- for (int t = 0; t < fmx.length; t++) {
- cndfmt.getFormatHandle().updateFromCF((Cf)this.getCndfmt().getRules().get(t), worksheet.wbh);
- fmx[t] = cndfmt.getFormatHandle();
- }
- return fmx;
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.kt b/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.kt
new file mode 100644
index 0000000..e88c2b9
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ConditionalFormatHandle.kt
@@ -0,0 +1,270 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.Cf
+import io.starter.formats.XLS.Condfmt
+import io.starter.toolkit.Logger
+
+import java.util.ArrayList
+
+/**
+ *
+ * ConditionalFormatHandle allows for manipulation of the ConditionalFormat cells in Excel
+ *
+ * Using the ConditionalFormatHandle, the affected range of ConditionalFormats can be modified,
+ * along with the formatting applied to the cells when the condition is true.
+ *
+ * Each ConditionalFormatHandle represents a range of cells and can have a number
+ * of formatting rules and formats (ConditionalFormatRule) applied.
+ *
+ * The ConditionalFormatHandle affected range can either be a contiguous range, or a series of cells and ranges.
+ *
+ * Each ConditionalFormatRule contains one rule and corresponding format data.
+ *
+ *
+ * Many of these calls are very self-explanatory and can be found in the api.
+ *
+ */
+class ConditionalFormatHandle
+/**
+ * For internal use only. Creates a ConditionalFormat Handle based of the Condfmt passed in.
+ *
+ * @param workBookHandle
+ * @param Condfmt
+ */
+(c: Condfmt,
+ /**
+ * get the WorkSheetHandle for this ConditionalFormat
+ *
+ *
+ * ConditionalFormats are bound to a specific worksheet and cannot be
+ * applied to multiple worksheets
+ *
+ * @return the WorkSheetHandle for this ConditionalFormat
+ */
+ val workSheetHandle: WorkSheetHandle) : Handle {
+
+
+ /**
+ * @return Returns the cndfmt.
+ */
+ /**
+ * @param cndfmt The cndfmt to set.
+ */
+ var cndfmt: Condfmt? = null
+ protected set
+
+
+ /**
+ * Get all the rules assocated with this conditional format record
+ *
+ * @return
+ */
+ val rules: Array
+ get() {
+ val cfs = this.cndfmt!!.rules
+ val rules = arrayOfNulls(cfs.size)
+ for (i in cfs.indices) {
+ val cfr = ConditionalFormatRule(cfs[i] as Cf)
+ rules[i] = cfr
+ }
+ return rules
+ }
+
+
+ /**
+ * Return the range of data this ConditionalFormatHandle refers to as a string
+ * This location is the largest bounding rectangle that all cells utilized in this conditional
+ * format can be contained in.
+ *
+ * @return Encompassing range in the format "A2:B12"
+ */
+ val encompassingRange: String
+ get() {
+ val rowcols = cndfmt!!.encompassingRange
+ return ExcelTools.formatRangeRowCol(rowcols)
+ }
+
+
+ /**
+ * Return a string representing all ranges that this conditional format handle can affect
+ *
+ * @return range in the format "A2:B3";
+ */
+ val allAffectedRanges: Array
+ get() = cndfmt!!.allRanges
+
+
+ /**
+ * Return an xml representation of the ConditionalFormatHandle
+ *
+ * @return
+ */
+ // TODO: more than one cf rule???
+ val xml: String
+ get() {
+ val rules = this.rules
+ val xml = StringBuffer()
+ xml.append("")
+ if (rules[0].firstCondition != null) {
+ xml.append("")
+ xml.append(rules[0].firstCondition)
+ xml.append(" ")
+ }
+ if (rules[0].secondCondition != null) {
+ xml.append("")
+ xml.append(rules[0].secondCondition)
+ xml.append(" ")
+ }
+ xml.append(" ")
+ return xml.toString()
+ }
+
+ /**
+ * returns the formatting for each rule of this Contditional Format Handle
+ *
+ * @return FormatHandle[]
+ */
+ //cfm.initCells(this); // added!
+ val formats: Array
+ get() {
+ val fmx = arrayOfNulls(this.cndfmt!!.rules.size)
+ if (cndfmt!!.formatHandle == null) {
+ val cfxe = cndfmt!!.cfxe
+ val fz = FormatHandle(cndfmt!!, workSheetHandle.workBook!!, cfxe, null)
+ }
+ for (t in fmx.indices) {
+ cndfmt!!.formatHandle!!.updateFromCF(this.cndfmt!!.rules[t] as Cf, workSheetHandle.workBook)
+ fmx[t] = cndfmt!!.formatHandle
+ }
+ return fmx
+ }
+
+
+ /**
+ * evaluates the criteria for this Conditional Format
+ * if the criteria involves a comparison i.e. equals, less than, etc., it uses the
+ * value from the passed in referenced cell to compare with
+ *
+ *
+ * If there are multiple rules in the ConditionalFormat then the first rule that passes will be returned.
+ *
+ *
+ * If no valid rules pass then a null result is given
+ *
+ * @param CellHandle refcell - the cell to obtain a value from in order for evaluation to occur
+ * @return the ConditionalFormatRule that passes.
+ * @see io.starter.formats.XLS.Cf.evaluate
+ */
+ fun evaluate(refcell: CellHandle): ConditionalFormatRule? {
+ val rules = this.rules
+ for (i in rules.indices) {
+ if (rules[i].evaluate(refcell)) return rules[i]
+ }
+ return null
+ }
+
+
+ init {
+ this.cndfmt = c
+ }
+
+
+ /**
+ * Determine if the conditional format contains/affects the cell handle passed in
+ *
+ * @param cellHandle
+ * @return
+ */
+ operator fun contains(cellHandle: CellHandle): Boolean {
+ return this.cndfmt!!.contains(cellHandle.intLocation)
+ }
+
+
+ /**
+ * Set the range this ConditionalFormatHandle refers to.
+ * Pass in a range string, sans worksheet.
+ *
+ *
+ * This range will overwrite all other ranges this ConditionalFormatHandle refers to.
+ *
+ *
+ * In order to handle multiple ranges, use the addRange(String range) method
+ *
+ * @param range = standard excel range without worksheet information ("A1" or "A1:A10")
+ */
+ fun setRange(range: String) {
+ this.cndfmt!!.resetRange(range)
+ }
+
+ /**
+ * Determines if the ConditionalFormatHandle contains the cell address passed in
+ *
+ * @param cellAddress a cell address in the format "A1"
+ * @return if the ce
+ */
+ operator fun contains(celladdy: String): Boolean {
+ return this.cndfmt!!.contains(ExcelTools.getRowColFromString(celladdy))
+ }
+
+ /**
+ * return a string representation of this Conditional Format
+ *
+ *
+ * This method is still incomplete as it only returns data for one rule, and only refers to one range
+ */
+ // TODO: more than one cf rule???
+ override fun toString(): String {
+ val rules = this.rules
+ var ret = this.encompassingRange + ": " + rules[0].type + " " + rules[0].operator // range, type + operator
+ if (rules[0].formula1 != null)
+ // formulas
+ ret += " " + rules[0].formula1!!.formulaString.substring(1)
+ if (rules[0].formula2 != null)
+ ret += " and " + rules[0].formula2!!.formulaString.substring(1)
+ // todo: add formats to this
+ return ret
+ }
+
+
+ /**
+ * Add a cell to this conditional format record
+ *
+ * @param cellHandle
+ */
+ fun addCell(cellHandle: CellHandle) {
+ if (this.contains(cellHandle)) return
+ cndfmt!!.addLocation(cellHandle.cellAddress)
+ }
+
+}
diff --git a/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.java b/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.java
deleted file mode 100644
index 3cffba3..0000000
--- a/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.awt.Color;
-
-import io.starter.formats.XLS.Cf;
-import io.starter.formats.XLS.Font;
-import io.starter.formats.XLS.Formula;
-import io.starter.formats.XLS.formulas.Ptg;
-import io.starter.formats.XLS.formulas.PtgRef;
-
-/**
- * ConditionalFormatRule defines a single rule for manipulation of the
- * ConditionalFormat cells in Excel
- *
- * Each ConditionalFormatRule contains one rule and corresponding format data.
- *
- *
- * @see ConditionalFormatHandle
- * @see Handle
- *
- *
- */
-public class ConditionalFormatRule implements Handle {
-
- Cf currentCf = null;
- // static shorts for setting ConditionalFormat type
- public static final byte VALUE_ANY = 0x0;
- public static final byte VALUE_INTEGER = 0x1;
- public static final byte VALUE_DECIMAL = 0x2;
- public static final byte VALUE_USER_DEFINED_LIST = 0x3;
- public static final byte VALUE_DATE = 0x4;
- public static final byte VALUE_TIME = 0x5;
- public static final byte VALUE_TEXT_LENGTH = 0x6;
- public static final byte VALUE_FORMULA = 0x7;
-
- // static shorts for setting action on error
- public static byte ERROR_STOP = 0x0;
- public static byte ERROR_WARN = 0x1;
- public static byte ERROR_INFO = 0x2;
-
- // static shorts for setting conditions on ConditionalFormat
- public static final byte CONDITION_BETWEEN = 0x0;
- public static final byte CONDITION_NOT_BETWEEN = 0x1;
- public static final byte CONDITION_EQUAL = 0x2;
- public static final byte CONDITION_NOT_EQUAL = 0x3;
- public static final byte CONDITION_GREATER_THAN = 0x4;
- public static final byte CONDITION_LESS_THAN = 0x5;
- public static final byte CONDITION_GREATER_OR_EQUAL = 0x6;
- public static final byte CONDITION_LESS_OR_EQUAL = 0x7;
-
- public static String[] OPERATORS = { "nocomparison", "between", "notBetween", "equal", "notEqual", "greaterThan",
- "lessThan", "greaterOrEqual", "lessOrEqual", "beginsWith", "endsWith", "containsText", "notContains" };
-
- /**
- * Get the byte representing the condition type string passed in. Options are'
- * "between", "notBetween", "equal", "notEqual", "greaterThan", "lessThan",
- * "greaterOrEqual", "lessOrEqual"
- *
- * @return
- */
- public static byte getConditionNumber(String conditionType) {
- for (int i = 0; i < OPERATORS.length; i++) {
- if (conditionType.equalsIgnoreCase(OPERATORS[i]))
- return (byte) i;
- }
- return -1;
- }
-
- public static String[] VALUE_TYPE = { "any", "integer", "decimal", "userDefinedList", "date", "time", "textLength",
- "formula" };
-
- /**
- * Get the byte representing the value type string passed in. Options are'
- * "any", "integer", "decimal", "userDefinedList", "date", "time", "textLength",
- * "formula"
- *
- *
- *
- *
- * @return
- */
- public static byte getValueNumber(String valueType) {
- for (int i = 0; i < VALUE_TYPE.length; i++) {
- if (valueType.equalsIgnoreCase(VALUE_TYPE[i]))
- return (byte) i;
- }
- return -1;
- }
-
- /**
- * Create a conditional format rule from a Cf record.
- *
- * @param theCf
- */
- protected ConditionalFormatRule(Cf theCf) {
- currentCf = theCf;
- }
-
- /**
- * evaluates the criteria for this Conditional Format Rule
- * if the criteria involves a comparison i.e. equals, less than, etc., it uses
- * the value from the passed in referenced cell to compare with
- *
- * @return boolean true if evaluation of criteria passes
- * @param Ptg
- * refcell - the Ptg location to obtain cell value from
- * @see io.starter.formats.XLS.Cf#evaluate(io.starter.formats.XLS.formulas.Ptg)
- */
- public boolean evaluate(CellHandle refcell) {
- Ptg/* Ref */ pr = PtgRef.createPtgRefFromString(refcell.getCellAddress(), null);
- return currentCf.evaluate(pr);
- }
-
- /**
- * Get the type operator of this ConditionalFormat as a byte.
- *
- * These bytes map to the CONDITION_* static values in ConditionalFormatHandle
- *
- * @return
- */
- public byte getTypeOperator() {
- return (byte) currentCf.getOperator();
- }
-
- /**
- * set the type operator of this ConditionalFormat as a byte.
- *
- * These bytes map to the CONDITION_* static values in ConditionalFormatHandle
- *
- *
- */
- public void setTypeOperator(byte typOperator) {
- currentCf.setOperator(typOperator);
- }
-
- /**
- * Get the second condition of the ConditionalFormat as a string representation
- *
- * @return
- */
- public String getSecondCondition() {
- if (currentCf != null && currentCf.getFormula2() != null)
- return currentCf.getFormula2().getFormulaString();
- return null;
- }
-
- /**
- * Set the second condition of the ConditionalFormat utilizing a string. This
- * value must conform to the Value Type of this ConditionalFormat or unexpected
- * results may occur. For example, entering a string representation of a date
- * here will not work if your ConditionalFormat is an integer...
- *
- * String passed in should be a vaild XLS formula. Does not need to include the
- * "="
- *
- * Types of conditions Integer values Decimal values User defined list Date Time
- * Text length Formula
- *
- * Be sure that your ConditionalFormat type (getConditionalFormatType()) matches
- * the type of data.
- *
- * @return
- */
- public void setSecondCondition(Object secondCond) {
- String setval = secondCond.toString();
- if (secondCond instanceof java.util.Date) {
- double d = DateConverter.getXLSDateVal((java.util.Date) secondCond);
- setval = d + "";
- }
- currentCf.setCondition2(setval);
- }
-
- /**
- * retrieves the border colors for the current Conditional Format
- *
- * @return java.awt.Color array of Color objects for each border side (Top,
- * Left, Bottom, Right)
- * @see io.starter.formats.XLS.Cf#getBorderColors()
- */
- public Color[] getBorderColors() {
- return currentCf.getBorderColors();
- }
-
- /**
- * returns the bottom border line color for the current Conditional Format
- *
- * @return int bottom border line color constant
- * @see io.starter.formats.XLS.Cf#getBorderLineColorBottom()
- * @see FormatHandle.COLOR_* constants
- */
- public int getBorderLineColorBottom() {
- return currentCf.getBorderLineColorBottom();
- }
-
- /**
- * returns the left border line color for the current Conditional Format
- *
- * @return int left border line color constant
- * @see io.starter.formats.XLS.Cf#getBorderLineColorLeft()
- * @see FormatHandle.COLOR_* constants
- */
- public int getBorderLineColorLeft() {
- return currentCf.getBorderLineColorLeft();
- }
-
- /**
- * returns the right border line color for the current Conditional Format
- *
- * @return int right border line color constant
- * @see io.starter.formats.XLS.Cf#getBorderLineColorRight()
- * @see FormatHandle.COLOR_* constants
- */
- public int getBorderLineColorRight() {
- return currentCf.getBorderLineColorRight();
- }
-
- /**
- * returns the top border line color for the current Conditional Format
- *
- * @return int top border line color constant
- * @see io.starter.formats.XLS.Cf#getBorderLineColorTop()
- * @see FormatHandle.COLOR_* constants
- */
- public int getBorderLineColorTop() {
- return currentCf.getBorderLineColorTop();
- }
-
- /**
- * returns the bottom border line style for the current Conditional Format
- *
- * @return int bottom border line style constant
- * @see io.starter.formats.XLS.Cf#getBorderLineStylesBottom()
- * @see FormatHandle.BORDER* line style constants
- */
- public int getBorderLineStylesBottom() {
- return currentCf.getBorderLineStylesBottom();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getBorderLineStylesLeft()
- */
- public int getBorderLineStylesLeft() {
- return currentCf.getBorderLineStylesLeft();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getBorderLineStylesRight()
- */
- public int getBorderLineStylesRight() {
- return currentCf.getBorderLineStylesRight();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getBorderLineStylesTop()
- */
- public int getBorderLineStylesTop() {
- return currentCf.getBorderLineStylesTop();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getBorderSizes()
- */
- public int[] getBorderSizes() {
- return currentCf.getBorderSizes();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getBorderStyles()
- */
- public int[] getBorderStyles() {
- return currentCf.getBorderStyles();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFont()
- */
- public Font getFont() {
- return currentCf.getFont();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontColorIndex()
- */
- public int getFontColorIndex() {
- return currentCf.getFontColorIndex();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontEscapement()
- */
- public int getFontEscapement() {
- return currentCf.getFontEscapement();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontHeight()
- */
- public int getFontHeight() {
- return currentCf.getFontHeight();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontOptsCancellation()
- */
- public int getFontOptsCancellation() {
- return currentCf.getFontOptsCancellation();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontOptsPosture()
- */
- public int getFontOptsPosture() {
- return currentCf.getFontOptsPosture();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontUnderlineStyle()
- */
- public int getFontUnderlineStyle() {
- return currentCf.getFontUnderlineStyle();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFontWeight()
- */
- public int getFontWeight() {
- return currentCf.getFontWeight();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getForegroundColor()
- */
- public int getForegroundColor() {
- return currentCf.getForegroundColor();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.XLSRecord#getFormatPattern()
- */
- public String getFormatPattern() {
- return currentCf.getFormatPattern();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFormula1()
- */
- public Formula getFormula1() {
- return currentCf.getFormula1();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getFormula2()
- */
- public Formula getFormula2() {
- return currentCf.getFormula2();
- }
-
- /**
- * returns the operator for this Conditional Format Rule
- * e.g. "bewteen", "greater than" ...
- *
- * @return
- */
- public String getOperator() {
- int op = currentCf.getOperator();
- if (op >= 0 && op < OPERATORS.length)
- return OPERATORS[op];
- return "unknown operator: " + op;
- }
-
- /**
- * returns the type of this Conditional Format
- * e.g. "Cell value is" or "Formula value is"
- *
- * @return String Conditional Format Type
- */
- public String getType() {
- return currentCf.getTypeString();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getPatternFillColor()
- */
- public int getPatternFillColor() {
- return currentCf.getPatternFillColor();
- }
-
- /**
- * returns the pattern color, if any, as an HTML color String. Includes custom
- * OOXML colors.
- *
- * @return String HTML Color String
- */
- public String getPatternFgColor() {
- return currentCf.getPatternFgColor();
- }
-
- /**
- * returns the pattern color, if any, as an HTML color String. Includes custom
- * OOXML colors.
- *
- * @return String HTML Color String
- */
- public String getPatternBgColor() {
- return currentCf.getPatternBgColor();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getPatternFillColorBack()
- */
- public int getPatternFillColorBack() {
- return currentCf.getPatternFillColorBack();
- }
-
- /**
- * @return
- * @see io.starter.formats.XLS.Cf#getPatternFillStyle()
- */
- public int getPatternFillStyle() {
- return currentCf.getPatternFillStyle();
- }
-
- /**
- * @param borderLineColorBottom
- * @see io.starter.formats.XLS.Cf#setBorderLineColorBottom(int)
- */
- public void setBorderLineColorBottom(int borderLineColorBottom) {
- currentCf.setBorderLineColorBottom(borderLineColorBottom);
- }
-
- /**
- * @param borderLineColorLeft
- * @see io.starter.formats.XLS.Cf#setBorderLineColorLeft(int)
- */
- public void setBorderLineColorLeft(int borderLineColorLeft) {
- currentCf.setBorderLineColorLeft(borderLineColorLeft);
- }
-
- /**
- * @param borderLineColorTop
- * @see io.starter.formats.XLS.Cf#setBorderLineColorTop(int)
- */
- public void setBorderLineColorTop(int borderLineColorTop) {
- currentCf.setBorderLineColorTop(borderLineColorTop);
- }
-
- /**
- * @param borderLineStylesBottom
- * @see io.starter.formats.XLS.Cf#setBorderLineStylesBottom(int)
- */
- public void setBorderLineStylesBottom(int borderLineStylesBottom) {
- currentCf.setBorderLineStylesBottom(borderLineStylesBottom);
- }
-
- /**
- * @param borderLineStylesLeft
- * @see io.starter.formats.XLS.Cf#setBorderLineStylesLeft(int)
- */
- public void setBorderLineStylesLeft(int borderLineStylesLeft) {
- currentCf.setBorderLineStylesLeft(borderLineStylesLeft);
- }
-
- /**
- * @param borderLineStylesRight
- * @see io.starter.formats.XLS.Cf#setBorderLineStylesRight(int)
- */
- public void setBorderLineStylesRight(int borderLineStylesRight) {
- currentCf.setBorderLineStylesRight(borderLineStylesRight);
- }
-
- /**
- * @param borderLineStylesTop
- * @see io.starter.formats.XLS.Cf#setBorderLineStylesTop(int)
- */
- public void setBorderLineStylesTop(int borderLineStylesTop) {
- currentCf.setBorderLineStylesTop(borderLineStylesTop);
- }
-
- /**
- * @param fontColorIndex
- * @see io.starter.formats.XLS.Cf#setFontColorIndex(int)
- */
- public void setFontColorIndex(int fontColorIndex) {
- currentCf.setFontColorIndex(fontColorIndex);
- }
-
- /**
- * @param fontEscapementFlag
- * @see io.starter.formats.XLS.Cf#setFontEscapement(int)
- */
- public void setFontEscapement(int fontEscapementFlag) {
- currentCf.setFontEscapement(fontEscapementFlag);
- }
-
- /**
- * @param fontHeight
- * @see io.starter.formats.XLS.Cf#setFontHeight(int)
- */
- public void setFontHeight(int fontHeight) {
- currentCf.setFontHeight(fontHeight);
- }
-
- /**
- * @param fontOptsCancellation
- * @see io.starter.formats.XLS.Cf#setFontOptsCancellation(int)
- */
- public void setFontOptsCancellation(int fontOptsCancellation) {
- currentCf.setFontStriken((fontOptsCancellation == Cf.FONT_OPTIONS_CANCELLATION_ON));
- }
-
- /**
- * @param fontOptsPosture
- * @see io.starter.formats.XLS.Cf#setFontOptsPosture(int)
- */
- public void setFontOptsPosture(int fontOptsPosture) {
- currentCf.setFontOptsPosture(fontOptsPosture);
- }
-
- /**
- * @param fontUnderlineStyle
- * @see io.starter.formats.XLS.Cf#setFontUnderlineStyle(int)
- */
- public void setFontUnderlineStyle(int fontUnderlineStyle) {
- currentCf.setFontUnderlineStyle(fontUnderlineStyle);
- }
-
- /**
- * @param fontWeight
- * @see io.starter.formats.XLS.Cf#setFontWeight(int)
- */
- public void setFontWeight(int fontWeight) {
- currentCf.setFontWeight(fontWeight);
- }
-
- /**
- * @param patternFillColor
- * @see io.starter.formats.XLS.Cf#setPatternFillColor(int)
- */
- public void setPatternFillColor(int patternFillColor) {
- currentCf.setPatternFillColor(patternFillColor, null);
- }
-
- /**
- * @param patternFillColorBack
- * @see io.starter.formats.XLS.Cf#setPatternFillColorBack(int)
- */
- public void setPatternFillColorBack(int patternFillColorBack) {
- currentCf.setPatternFillColorBack(patternFillColorBack);
- }
-
- /**
- * @param patternFillStyle
- * @see io.starter.formats.XLS.Cf#setPatternFillStyle(int)
- */
- public void setPatternFillStyle(int patternFillStyle) {
- currentCf.setPatternFillStyle(patternFillStyle);
- }
-
- /**
- * Get the first condition of the ConditionalFormat as a string representation
- *
- * @return
- */
- public String getFirstCondition() {
- return currentCf.getFormula1().getFormulaString();
- }
-
- /**
- * Set the first condition of the ConditionalFormat
- *
- * This value must conform to the Value Type of this ConditionalFormat or
- * unexpected results may occur. For example, entering a string representation
- * of a date here will not work if your ConditionalFormat is an integer...
- *
- * A java.util.Date object can also be passed in. This value will be translated
- * into an integer as excel stores dates. If you need to manipulate/retrieve
- * this value later utilize the DateConverter tool to transform the value
- *
- * String passed in should be a vaild XLS formula. Does not need to include the
- * "="
- *
- * Types of conditions Integer values Decimal values User defined list Date Time
- * Text length Formula
- *
- * Be sure that your ConditionalFormat type (getConditionalFormatType()) matches
- * the type of data.
- *
- * @param firstCond
- * = the first condition for the ConditionalFormat
- */
- public void setFirstCondition(Object firstCond) {
- String setval = firstCond.toString();
- if (firstCond instanceof java.util.Date) {
- double d = DateConverter.getXLSDateVal((java.util.Date) firstCond);
- setval = d + "";
- }
- currentCf.setCondition1(setval);
- }
-
- public int getConditionalFormatType() {
- return 0;
- }
-}
diff --git a/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.kt b/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.kt
new file mode 100644
index 0000000..0bf612a
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ConditionalFormatRule.kt
@@ -0,0 +1,590 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.Cf
+import io.starter.formats.XLS.Font
+import io.starter.formats.XLS.Formula
+import io.starter.formats.XLS.formulas.Ptg
+import io.starter.formats.XLS.formulas.PtgRef
+
+import java.awt.*
+
+/**
+ * ConditionalFormatRule defines a single rule for manipulation of the
+ * ConditionalFormat cells in Excel
+ *
+ *
+ * Each ConditionalFormatRule contains one rule and corresponding format data.
+ *
+ * @see ConditionalFormatHandle
+ *
+ * @see Handle
+ */
+class ConditionalFormatRule
+/**
+ * Create a conditional format rule from a Cf record.
+ *
+ * @param theCf
+ */
+(theCf: Cf) : Handle {
+
+ internal var currentCf: Cf? = null
+
+ /**
+ * Get the type operator of this ConditionalFormat as a byte.
+ *
+ *
+ * These bytes map to the CONDITION_* static values in ConditionalFormatHandle
+ *
+ * @return
+ */
+ /**
+ * set the type operator of this ConditionalFormat as a byte.
+ *
+ *
+ * These bytes map to the CONDITION_* static values in ConditionalFormatHandle
+ */
+ var typeOperator: Byte
+ get() = currentCf!!.operator.toByte()
+ set(typOperator) = currentCf!!.setOperator(typOperator.toInt())
+
+ /**
+ * Get the second condition of the ConditionalFormat as a string representation
+ *
+ * @return
+ */
+ val secondCondition: String?
+ get() = if (currentCf != null && currentCf!!.formula2 != null) currentCf!!.formula2!!.formulaString else null
+
+ /**
+ * retrieves the border colors for the current Conditional Format
+ *
+ * @return java.awt.Color array of Color objects for each border side (Top,
+ * Left, Bottom, Right)
+ * @see io.starter.formats.XLS.Cf.getBorderColors
+ */
+ val borderColors: Array?
+ get() = currentCf!!.borderColors
+
+ /**
+ * returns the bottom border line color for the current Conditional Format
+ *
+ * @return int bottom border line color constant
+ * @see io.starter.formats.XLS.Cf.getBorderLineColorBottom
+ * @see FormatHandle.COLOR_* constants
+ */
+ /**
+ * @param borderLineColorBottom
+ * @see io.starter.formats.XLS.Cf.setBorderLineColorBottom
+ */
+ var borderLineColorBottom: Int
+ get() = currentCf!!.borderLineColorBottom
+ set(borderLineColorBottom) {
+ currentCf!!.borderLineColorBottom = borderLineColorBottom
+ }
+
+ /**
+ * returns the left border line color for the current Conditional Format
+ *
+ * @return int left border line color constant
+ * @see io.starter.formats.XLS.Cf.getBorderLineColorLeft
+ * @see FormatHandle.COLOR_* constants
+ */
+ /**
+ * @param borderLineColorLeft
+ * @see io.starter.formats.XLS.Cf.setBorderLineColorLeft
+ */
+ var borderLineColorLeft: Int
+ get() = currentCf!!.borderLineColorLeft
+ set(borderLineColorLeft) {
+ currentCf!!.borderLineColorLeft = borderLineColorLeft
+ }
+
+ /**
+ * returns the right border line color for the current Conditional Format
+ *
+ * @return int right border line color constant
+ * @see io.starter.formats.XLS.Cf.getBorderLineColorRight
+ * @see FormatHandle.COLOR_* constants
+ */
+ val borderLineColorRight: Int
+ get() = currentCf!!.borderLineColorRight
+
+ /**
+ * returns the top border line color for the current Conditional Format
+ *
+ * @return int top border line color constant
+ * @see io.starter.formats.XLS.Cf.getBorderLineColorTop
+ * @see FormatHandle.COLOR_* constants
+ */
+ /**
+ * @param borderLineColorTop
+ * @see io.starter.formats.XLS.Cf.setBorderLineColorTop
+ */
+ var borderLineColorTop: Int
+ get() = currentCf!!.borderLineColorTop
+ set(borderLineColorTop) {
+ currentCf!!.borderLineColorTop = borderLineColorTop
+ }
+
+ /**
+ * returns the bottom border line style for the current Conditional Format
+ *
+ * @return int bottom border line style constant
+ * @see io.starter.formats.XLS.Cf.getBorderLineStylesBottom
+ * @see FormatHandle.BORDER* line style constants
+ */
+ /**
+ * @param borderLineStylesBottom
+ * @see io.starter.formats.XLS.Cf.setBorderLineStylesBottom
+ */
+ var borderLineStylesBottom: Int
+ get() = currentCf!!.borderLineStylesBottom
+ set(borderLineStylesBottom) {
+ currentCf!!.borderLineStylesBottom = borderLineStylesBottom
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getBorderLineStylesLeft
+ */
+ /**
+ * @param borderLineStylesLeft
+ * @see io.starter.formats.XLS.Cf.setBorderLineStylesLeft
+ */
+ var borderLineStylesLeft: Int
+ get() = currentCf!!.borderLineStylesLeft
+ set(borderLineStylesLeft) {
+ currentCf!!.borderLineStylesLeft = borderLineStylesLeft
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getBorderLineStylesRight
+ */
+ /**
+ * @param borderLineStylesRight
+ * @see io.starter.formats.XLS.Cf.setBorderLineStylesRight
+ */
+ var borderLineStylesRight: Int
+ get() = currentCf!!.borderLineStylesRight
+ set(borderLineStylesRight) {
+ currentCf!!.borderLineStylesRight = borderLineStylesRight
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getBorderLineStylesTop
+ */
+ /**
+ * @param borderLineStylesTop
+ * @see io.starter.formats.XLS.Cf.setBorderLineStylesTop
+ */
+ var borderLineStylesTop: Int
+ get() = currentCf!!.borderLineStylesTop
+ set(borderLineStylesTop) {
+ currentCf!!.borderLineStylesTop = borderLineStylesTop
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getBorderSizes
+ */
+ val borderSizes: IntArray?
+ get() = currentCf!!.borderSizes
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getBorderStyles
+ */
+ val borderStyles: IntArray?
+ get() = currentCf!!.borderStyles
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFont
+ */
+ val font: Font?
+ get() = currentCf!!.font
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontColorIndex
+ */
+ /**
+ * @param fontColorIndex
+ * @see io.starter.formats.XLS.Cf.setFontColorIndex
+ */
+ var fontColorIndex: Int
+ get() = currentCf!!.fontColorIndex
+ set(fontColorIndex) {
+ currentCf!!.fontColorIndex = fontColorIndex
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontEscapement
+ */
+ /**
+ * @param fontEscapementFlag
+ * @see io.starter.formats.XLS.Cf.setFontEscapement
+ */
+ var fontEscapement: Int
+ get() = currentCf!!.fontEscapement
+ set(fontEscapementFlag) {
+ currentCf!!.fontEscapement = fontEscapementFlag
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontHeight
+ */
+ /**
+ * @param fontHeight
+ * @see io.starter.formats.XLS.Cf.setFontHeight
+ */
+ var fontHeight: Int
+ get() = currentCf!!.fontHeight
+ set(fontHeight) {
+ currentCf!!.fontHeight = fontHeight
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontOptsCancellation
+ */
+ /**
+ * @param fontOptsCancellation
+ * @see io.starter.formats.XLS.Cf.setFontOptsCancellation
+ */
+ var fontOptsCancellation: Int
+ get() = currentCf!!.fontOptsCancellation
+ set(fontOptsCancellation) {
+ currentCf!!.fontStriken = fontOptsCancellation == Cf.FONT_OPTIONS_CANCELLATION_ON
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontOptsPosture
+ */
+ /**
+ * @param fontOptsPosture
+ * @see io.starter.formats.XLS.Cf.setFontOptsPosture
+ */
+ var fontOptsPosture: Int
+ get() = currentCf!!.fontOptsPosture
+ set(fontOptsPosture) {
+ currentCf!!.fontOptsPosture = fontOptsPosture
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontUnderlineStyle
+ */
+ /**
+ * @param fontUnderlineStyle
+ * @see io.starter.formats.XLS.Cf.setFontUnderlineStyle
+ */
+ var fontUnderlineStyle: Int
+ get() = currentCf!!.fontUnderlineStyle
+ set(fontUnderlineStyle) {
+ currentCf!!.fontUnderlineStyle = fontUnderlineStyle
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFontWeight
+ */
+ /**
+ * @param fontWeight
+ * @see io.starter.formats.XLS.Cf.setFontWeight
+ */
+ var fontWeight: Int
+ get() = currentCf!!.fontWeight
+ set(fontWeight) {
+ currentCf!!.fontWeight = fontWeight
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getForegroundColor
+ */
+ val foregroundColor: Int
+ get() = currentCf!!.foregroundColor
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.XLSRecord.getFormatPattern
+ */
+ val formatPattern: String?
+ get() = currentCf!!.formatPattern
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFormula1
+ */
+ val formula1: Formula?
+ get() = currentCf!!.formula1
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getFormula2
+ */
+ val formula2: Formula?
+ get() = currentCf!!.formula2
+
+ /**
+ * returns the operator for this Conditional Format Rule
+ * e.g. "bewteen", "greater than" ...
+ *
+ * @return
+ */
+ val operator: String
+ get() {
+ val op = currentCf!!.operator.toInt()
+ return if (op >= 0 && op < OPERATORS.size) OPERATORS[op] else "unknown operator: $op"
+ }
+
+ /**
+ * returns the type of this Conditional Format
+ * e.g. "Cell value is" or "Formula value is"
+ *
+ * @return String Conditional Format Type
+ */
+ val type: String
+ get() = currentCf!!.typeString
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getPatternFillColor
+ */
+ /**
+ * @param patternFillColor
+ * @see io.starter.formats.XLS.Cf.setPatternFillColor
+ */
+ var patternFillColor: Int
+ get() = currentCf!!.patternFillColor
+ set(patternFillColor) = currentCf!!.setPatternFillColor(patternFillColor, null)
+
+ /**
+ * returns the pattern color, if any, as an HTML color String. Includes custom
+ * OOXML colors.
+ *
+ * @return String HTML Color String
+ */
+ val patternFgColor: String?
+ get() = currentCf!!.patternFgColor
+
+ /**
+ * returns the pattern color, if any, as an HTML color String. Includes custom
+ * OOXML colors.
+ *
+ * @return String HTML Color String
+ */
+ val patternBgColor: String?
+ get() = currentCf!!.patternBgColor
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getPatternFillColorBack
+ */
+ /**
+ * @param patternFillColorBack
+ * @see io.starter.formats.XLS.Cf.setPatternFillColorBack
+ */
+ var patternFillColorBack: Int
+ get() = currentCf!!.patternFillColorBack
+ set(patternFillColorBack) {
+ currentCf!!.patternFillColorBack = patternFillColorBack
+ }
+
+ /**
+ * @return
+ * @see io.starter.formats.XLS.Cf.getPatternFillStyle
+ */
+ /**
+ * @param patternFillStyle
+ * @see io.starter.formats.XLS.Cf.setPatternFillStyle
+ */
+ var patternFillStyle: Int
+ get() = currentCf!!.patternFillStyle
+ set(patternFillStyle) {
+ currentCf!!.patternFillStyle = patternFillStyle
+ }
+
+ /**
+ * Get the first condition of the ConditionalFormat as a string representation
+ *
+ * @return
+ */
+ val firstCondition: String
+ get() = currentCf!!.formula1!!.formulaString
+
+ val conditionalFormatType: Int
+ get() = 0
+
+ init {
+ currentCf = theCf
+ }
+
+ /**
+ * evaluates the criteria for this Conditional Format Rule
+ * if the criteria involves a comparison i.e. equals, less than, etc., it uses
+ * the value from the passed in referenced cell to compare with
+ *
+ * @param Ptg refcell - the Ptg location to obtain cell value from
+ * @return boolean true if evaluation of criteria passes
+ * @see io.starter.formats.XLS.Cf.evaluate
+ */
+ fun evaluate(refcell: CellHandle): Boolean {
+ val /* Ref */ pr = PtgRef.createPtgRefFromString(refcell.cellAddress, null)
+ return currentCf!!.evaluate(pr)
+ }
+
+ /**
+ * Set the second condition of the ConditionalFormat utilizing a string. This
+ * value must conform to the Value Type of this ConditionalFormat or unexpected
+ * results may occur. For example, entering a string representation of a date
+ * here will not work if your ConditionalFormat is an integer...
+ *
+ *
+ * String passed in should be a vaild XLS formula. Does not need to include the
+ * "="
+ *
+ *
+ * Types of conditions Integer values Decimal values User defined list Date Time
+ * Text length Formula
+ *
+ *
+ * Be sure that your ConditionalFormat type (getConditionalFormatType()) matches
+ * the type of data.
+ *
+ * @return
+ */
+ fun setSecondCondition(secondCond: Any) {
+ var setval = secondCond.toString()
+ if (secondCond is java.util.Date) {
+ val d = DateConverter.getXLSDateVal(secondCond)
+ setval = d.toString() + ""
+ }
+ currentCf!!.setCondition2(setval)
+ }
+
+ /**
+ * Set the first condition of the ConditionalFormat
+ *
+ *
+ * This value must conform to the Value Type of this ConditionalFormat or
+ * unexpected results may occur. For example, entering a string representation
+ * of a date here will not work if your ConditionalFormat is an integer...
+ *
+ *
+ * A java.util.Date object can also be passed in. This value will be translated
+ * into an integer as excel stores dates. If you need to manipulate/retrieve
+ * this value later utilize the DateConverter tool to transform the value
+ *
+ *
+ * String passed in should be a vaild XLS formula. Does not need to include the
+ * "="
+ *
+ *
+ * Types of conditions Integer values Decimal values User defined list Date Time
+ * Text length Formula
+ *
+ *
+ * Be sure that your ConditionalFormat type (getConditionalFormatType()) matches
+ * the type of data.
+ *
+ * @param firstCond = the first condition for the ConditionalFormat
+ */
+ fun setFirstCondition(firstCond: Any) {
+ var setval = firstCond.toString()
+ if (firstCond is java.util.Date) {
+ val d = DateConverter.getXLSDateVal(firstCond)
+ setval = d.toString() + ""
+ }
+ currentCf!!.setCondition1(setval)
+ }
+
+ companion object {
+ // static shorts for setting ConditionalFormat type
+ val VALUE_ANY: Byte = 0x0
+ val VALUE_INTEGER: Byte = 0x1
+ val VALUE_DECIMAL: Byte = 0x2
+ val VALUE_USER_DEFINED_LIST: Byte = 0x3
+ val VALUE_DATE: Byte = 0x4
+ val VALUE_TIME: Byte = 0x5
+ val VALUE_TEXT_LENGTH: Byte = 0x6
+ val VALUE_FORMULA: Byte = 0x7
+
+ // static shorts for setting action on error
+ var ERROR_STOP: Byte = 0x0
+ var ERROR_WARN: Byte = 0x1
+ var ERROR_INFO: Byte = 0x2
+
+ // static shorts for setting conditions on ConditionalFormat
+ val CONDITION_BETWEEN: Byte = 0x0
+ val CONDITION_NOT_BETWEEN: Byte = 0x1
+ val CONDITION_EQUAL: Byte = 0x2
+ val CONDITION_NOT_EQUAL: Byte = 0x3
+ val CONDITION_GREATER_THAN: Byte = 0x4
+ val CONDITION_LESS_THAN: Byte = 0x5
+ val CONDITION_GREATER_OR_EQUAL: Byte = 0x6
+ val CONDITION_LESS_OR_EQUAL: Byte = 0x7
+
+ var OPERATORS = arrayOf("nocomparison", "between", "notBetween", "equal", "notEqual", "greaterThan", "lessThan", "greaterOrEqual", "lessOrEqual", "beginsWith", "endsWith", "containsText", "notContains")
+
+ /**
+ * Get the byte representing the condition type string passed in. Options are'
+ * "between", "notBetween", "equal", "notEqual", "greaterThan", "lessThan",
+ * "greaterOrEqual", "lessOrEqual"
+ *
+ * @return
+ */
+ fun getConditionNumber(conditionType: String): Byte {
+ for (i in OPERATORS.indices) {
+ if (conditionType.equals(OPERATORS[i], ignoreCase = true))
+ return i.toByte()
+ }
+ return -1
+ }
+
+ var VALUE_TYPE = arrayOf("any", "integer", "decimal", "userDefinedList", "date", "time", "textLength", "formula")
+
+ /**
+ * Get the byte representing the value type string passed in. Options are'
+ * "any", "integer", "decimal", "userDefinedList", "date", "time", "textLength",
+ * "formula"
+ *
+ * @return
+ */
+ fun getValueNumber(valueType: String): Byte {
+ for (i in VALUE_TYPE.indices) {
+ if (valueType.equals(VALUE_TYPE[i], ignoreCase = true))
+ return i.toByte()
+ }
+ return -1
+ }
+ }
+}
diff --git a/src/main/java/io/starter/OpenXLS/DateConverter.java b/src/main/java/io/starter/OpenXLS/DateConverter.java
deleted file mode 100644
index d9da18c..0000000
--- a/src/main/java/io/starter/OpenXLS/DateConverter.java
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-//import java.text.SimpleDateFormat;
-import java.util.*;
-
-import io.starter.toolkit.Logger;
-
-/**
- * Provides methods for conversion to and from Excel serial date values.
- *
- * Excel stores dates as the number of days since midnight on January 1, 1900.
- * Times are represented as fractional days. For example, 6:00 AM on February 2,
- * 1900 is represented as 33.25. Excel incorrectly treats 1900 as a leap year,
- * so serial dates after February 28, 1900 are one higher than they otherwise
- * should be and the value 60 is unmapped. It also interprets the value 0 as
- * January 0, 1900.
- *
- * Excel does not support negative serial date values, so it cannot handle dates
- * prior to 1900. It also does not currently accept date values with a year of
- * 10000 or greater. OpenXLS does not currently support negative date values,
- * but this feature is planned. If you wish to restrict the output to the subset
- * of values supported by Excel, you may enable input validation by calling
- * {@link #setValidate}.
- *
- * Due to the inherent inaccuracy of floating-point types, values from this
- * class can only be guaranteed to equal values generated by Excel to eight
- * decimal places. This provides accuracy to the unit milliseconds, the maximum
- * precision of Java's date classes. Accuracy outside the range supported by
- * Excel is not guaranteed and will degrade as the values get farther from zero.
- *
- */
-public class DateConverter {
- /** The number of milliseconds in a day. */
- private static final int MILLIS_DAY = 86400000;
-
- /** The extra day caused by the 1900 leap year bug. */
- private static final int EXTRA_DAY = 60;
-
- /** Calendar used for date calculation. */
- private static Calendar calendar = Calendar.getInstance();
-
- /** Whether to validate input dates for Excel compatibility. */
- private static boolean validate = false;
-
- /** The set of supported serial date encoding schemes. */
- public static enum DateFormat {
- /** 1900 epoch with negative value support as used in OOXML.
- *
- * Lower limit: -9999/01/01 00:00:00, value -4 346 018
- * Epoch date: 1899/12/30 00:00:00, value 0
- * Upper limit: 9999/12/31 23:59:59, value 2 958 465.999 988 4
- */
- OOXML_1900( 25569, -4346018, 2958465.9999884 ),
-
- /** 1900 epoch without negative value support as used in BIFF8.
- *
- * Epoch date: 1899/12/31 00:00:00, value 0
- * Lower limit: 1900/01/01 00:00:00, value 1
- * Upper limit: 9999/12/31 23:59:59, value 2 958 465.999 988 4
- *
- * In this system 1900 is (incorrectly) considered a leap year. Serial
- * dates after 1900/02/28 are one higher than they otherwise should be
- * and the value 60 is unmapped.
- */
- LEGACY_1900( 25568, 1, 2958465.9999884 ),
-
- /** 1904 epoch without negative value support as used by Excel for Mac.
- *
- * Epoch date: 1904/01/01 00:00:00, value 0
- * Lower limit: 1904/01/01 00:00:00, value 0
- * Upper limit: 9999/12/31 23:59:59, value 2 957 003.999 988 4
- */
- LEGACY_1904( 24107, 0, 2957003.9999884 );
-
- private final int epoch_delta;
- private final double limit_lower, limit_upper;
-
- private DateFormat (int delta, double min, double max) {
- epoch_delta = delta;
- limit_lower = min;
- limit_upper = max;
- }
-
- protected int getEpochDelta() {
- return epoch_delta;
- }
-
- public double getLowerLimit() {
- return limit_lower;
- }
-
- public double getUpperLimit() {
- return limit_upper;
- }
- }
-
- /**
- * Gets a clone of the calendar used for date calculation.
- */
- public static Calendar getCalendar() {
- return (Calendar) calendar.clone();
- }
-
- /**
- * Sets the calendar used to perform date calculation. This allows you to
- * set the locale and time zone to something other than the system default.
- *
- * @param cal
- * the calendar that should be used for date calculations
- */
- public static void setCalendar(Calendar cal) {
- calendar = cal;
- }
-
- /**
- * Returns whether input validation is on.
- */
- public static boolean getValidate() {
- return validate;
- }
-
- /**
- * Sets whether to perform input validation.
- */
- public static void setValidate(boolean validate) {
- DateConverter.validate = validate;
- }
-
- /**
- * returns whether this method will work with your input string
- */
- public static boolean isParseableDateString(String str) {
- // fix problem with timestamps tagged on end
- if (str.indexOf(" ") > 0) {
- str = str.substring(0, str.indexOf(" "));
- }
- try {
- java.sql.Date d1 = java.sql.Date.valueOf(str);
- getXLSDateVal( d1 );
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
-
- /**
- * attempt to interpret a date string into a date
- * returns null if cannot be converted to date
- */
- public static Date getDate(String str) {
- try {
- java.sql.Timestamp d1 = java.sql.Timestamp.valueOf(str);
- Calendar cal = (Calendar) calendar.clone();
- cal.setTime(d1);
- return cal.getTime();
- } catch (Exception e) {
- ;
- }
- return null;
-
- }
- /** Converts the value of the given Calendar to an Excel serial date.
- * The date will be returned in the
- * {@linkplain DateFormat#LEGACY_1900 legacy 1900} format.
- *
- * @param cal the Calendar to convert
- * @return the Excel serial date representing the given calendar's value in
- * the calendar's time zone
- * @deprecated Use {@link #getXLSDateVal( Calendar, DateFormat )} instead.
- */
- public static double getXLSDateVal(Calendar cal) {
- return getXLSDateVal( cal, DateFormat.LEGACY_1900 );
- }
-
- /** Converts the value of the given Calendar to an Excel serial date.
- * @param cal the Calendar to convert
- * @param format the serial date format to use
- * @return the Excel serial date representing the given calendar's value in
- * the calendar's time zone
- */
- public static double getXLSDateVal (Calendar cal, DateFormat format) {
- // Get the UTC milliseconds since the epoch
- long millis = cal.getTimeInMillis();
-
- // Add the GMT offset and daylight savings offset for the time zone
- millis += cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
-
- // Convert from milliseconds to days
- double days = (double) millis / MILLIS_DAY;
-
- // Switch from UNIX epoch to the Excel epoch
- days += format.getEpochDelta();
-
- // If the date is after February 28, 1900 add one day.
- // This compensates for Excel incorrectly treating 1900 as a leap year
- if (format == DateFormat.LEGACY_1900 && days >= EXTRA_DAY)
- days += 1;
-
- // Perform validation
- if (validate && (days < format.getLowerLimit()
- || days > format.getUpperLimit() ) )
- throw new IllegalArgumentException(
- "the given date is not supported by Excel");
-
- // Return the Excel serial date value
- return days;
- }
-
- /** Converts the given Date to an Excel serial date in the default time zone.
- *
- * @param date the date to be converted
- * @param format the serial date format to use
- * @return the Excel serial date value corresponding to the given date
- */
- public static double getXLSDateVal (Date date, DateFormat format) {
- Calendar cal = (Calendar) calendar.clone();
- cal.setTime(date);
- return getXLSDateVal(cal, format);
- }
-
- /** Converts the given Date to an Excel serial date in the default time zone.
- * The date will be returned in the
- * {@linkplain DateFormat#LEGACY_1900 legacy 1900} format.
- *
- * @param date the date to be converted
- * @return the Excel serial date value corresponding to the given date
- * @deprecated Use {@link #getXLSDateVal( Date, DateFormat )} instead.
- */
- public static double getXLSDateVal (Date date) {
- return getXLSDateVal( date, DateFormat.LEGACY_1900 );
- }
-
- /** Parses the the given Excel serial date and returns a Calendar.
- * The date will be interpreted in the
- * {@linkplain DateFormat#LEGACY_1900 legacy 1900} format.
- *
- * @param date the Excel serial date to be interpreted
- * @return a Calendar representing the given Excel date interpreted in the
- * default time zone
- * @deprecated Use {@link #getCalendarFromNumber( double, DateFormat )} instead.
- */
- public static Calendar getCalendarFromNumber (double date) {
- return getCalendarFromNumber( date, DateFormat.LEGACY_1900 );
- }
-
- /** Parses the the given Excel serial date and returns a Calendar.
- *
- * @param date the Excel serial date to be interpreted
- * @param format the date format with which to interpret the serial date
- * @return a Calendar representing the given Excel date interpreted in the
- * default time zone
- */
- public static Calendar getCalendarFromNumber (double date, DateFormat format) {
- Calendar cal = getCalendar();
- double days = date;
-
- // For the legacy 1900 epoch, if the date is after 1900/02/28 subtract
- // one day. This compensates for 1900 being considered a leap year.
- // Not matching the non-existent February 29 causes it to become
- // March 1. This behavior matches that of Calendar for the same input.
- if (format == DateFormat.LEGACY_1900 && days > EXTRA_DAY)
- days -= 1;
-
- // Switch from the Excel epoch to the UNIX epoch
- days -= format.getEpochDelta();
-
- // Convert from days to milliseconds
- long millis = Math.round( days * MILLIS_DAY );
-
- // Set the calendar's approximate time so zone offsets are correct
- // The offsets can still be wrong for certain border cases.
- cal.setTimeInMillis( millis );
-
- // Adjust for time zone and daylight saving time offsets
- long offset = 0;
- for (int count = 0; offset != (offset = cal.get( Calendar.ZONE_OFFSET )
- + cal.get( Calendar.DST_OFFSET ))
- && count < 3; count++)
- cal.setTimeInMillis( millis - offset );
-
- return cal;
- }
-
- /** Parses the the given Excel serial date and returns a Date.
- * The date will be interpreted in the
- * {@linkplain DateFormat#LEGACY_1900 legacy 1900} format.
- *
- * @param date the Excel serial date to be interpreted
- * @param format the date format with which to interpret the serial date
- * @return a Calendar representing the given Excel date interpreted in the
- * default time zone
- * @deprecated Use {@link #getCalendarFromNumber( double, DateFormat )} instead.
- */
- public static Date getDateFromNumber(double date) {
- return getCalendarFromNumber(date).getTime();
- }
-
- /**
- * Gets the Date for the given Excel serial date.
- *
- * @param number
- * a Number representing the serial date to be interpreted
- * @return a Date representing the given Excel date interpreted in the
- * default time zone
- * @throws ClassCastException
- * if the passed object is not a Number
- * @deprecated Use {@link #getDateFromNumber(double)} instead.
- */
- public static Date getDateFromNumber(Object number) {
- if (number instanceof Number)
- return getDateFromNumber(((Number) number).doubleValue());
-
- else
- throw new ClassCastException("passed object was not a number");
- }
-
- /**
- * Gets the Date for the given Excel serial date.
- *
- * @param number
- * a Number representing the serial date to be interpreted
- * @return a Date representing the given Excel date interpreted in the
- * default time zone
- * @throws ClassCastException
- * if the passed object is not a Number
- * @deprecated Identical to {@link #getDateFromNumber(Object)}.
- */
- public static Date getNonLocalizedDateFromNumber(Object number) {
- return getDateFromNumber(number);
- }
-
- /**
- * Gets the Calendar for the given Excel serial date.
- *
- * @param date
- * the Excel serial date or datestring to be interpreted
- * @return a Calendar representing the given Excel date interpreted in the
- * default time zone
- * @throws ClassCastException
- * if the passed object is not a Number
- * @deprecated Use {@link #getCalendarFromNumber(double)} instead.
- */
- public static Calendar getCalendarFromNumber(Object number) {
- if (number==null)
- throw new ClassCastException("object cannot be converted to a date");
- if (!(number instanceof Number))
- number= new Double(number.toString());
-
- if (number instanceof Number)
- return getCalendarFromNumber(((Number) number).doubleValue());
-
- else
- throw new ClassCastException("passed object was not a number");
- }
-
- /**
- * Gets the Date for the given Excel serial date.
- *
- * @param number
- * a Number representing the serial date to be interpreted
- * @return a Date representing the given Excel date interpreted in the
- * default time zone
- * @throws ClassCastException
- * if the passed object is not a Number
- * @deprecated Identical to {@link #getDateFromNumber(Object)}.
- */
- public static Calendar getNonLocalizedCalendarFromNumber(Object number) {
- return getCalendarFromNumber(number);
- }
-
- /**
- * Gets the Date for the given cell.
- *
- * @param cell
- * a CellHandle whose value should be interpreted
- * @return a Date representing the given Excel date interpreted in the
- * default time zone
- */
- public static Date getDateFromCell(CellHandle cell) {
- return getCalendarFromCell( cell ).getTime();
- }
-
- /**
- * returns a Java Calendar from a CellHandle containing an Excel-formatted
- * Date
- *
- * The Excel date format does not map 100% accurately to Java dates, due to
- * the limitation of the precision of the Excel floating-point value record.
- * Due to this, OpenXLS dates may be too precise, this method will round
- * the java.util.Date returned to the precision entered. Rounding is handled
- * by the ROUND_HALF_UP method.
- *
- * Pass in a static Calendar precision, options are Calendar.HOUR
- * Calendar.MINUTE Calendar.SECOND Calendar.MILLISECOND
- *
- * @return Calendar - A GregorianCalendar value of the Cell
- */
- public static Calendar getCalendarFromCellWithPrecision(Cell cell,
- int roundingCalendarField) {
- Calendar tmp = getCalendarFromCell(cell);
- GregorianCalendar newCalendar = new GregorianCalendar();
- newCalendar.set(Calendar.YEAR, tmp.get(Calendar.YEAR));
- newCalendar.set(Calendar.MONTH, tmp.get(Calendar.MONTH));
- newCalendar.set(Calendar.DAY_OF_MONTH, tmp.get(Calendar.DAY_OF_MONTH));
- newCalendar.set(Calendar.HOUR_OF_DAY, tmp.get(Calendar.HOUR_OF_DAY));
- if (roundingCalendarField == Calendar.HOUR) {
- if (tmp.get(Calendar.MINUTE) > 29) {
- newCalendar.set(Calendar.HOUR_OF_DAY,
- tmp.get(Calendar.HOUR_OF_DAY) + 1);
- }
- newCalendar.set(Calendar.MINUTE, 0);
- newCalendar.set(Calendar.SECOND, 0);
- newCalendar.set(Calendar.MILLISECOND, 0);
- return newCalendar;
- }
- newCalendar.set(Calendar.MINUTE, tmp.get(Calendar.MINUTE));
- if (roundingCalendarField == Calendar.MINUTE) {
- if (tmp.get(Calendar.SECOND) > 29) {
- newCalendar.set(Calendar.MINUTE, tmp.get(Calendar.MINUTE) + 1);
- }
- newCalendar.set(Calendar.SECOND, 0);
- newCalendar.set(Calendar.MILLISECOND, 0);
- return newCalendar;
- }
- newCalendar.set(Calendar.SECOND, tmp.get(Calendar.SECOND));
- if (roundingCalendarField == Calendar.SECOND) {
- if (tmp.get(Calendar.MILLISECOND) > 499) {
- newCalendar.set(Calendar.SECOND, tmp.get(Calendar.SECOND) + 1);
- }
- newCalendar.set(Calendar.MILLISECOND, 0);
- return newCalendar;
- }
- // round the milliseconds
- newCalendar.set(Calendar.MILLISECOND, tmp.get(Calendar.MILLISECOND));
- return newCalendar;
-
- }
-
- /**
- * Gets the Calendar for the given cell.
- *
- * @param cell
- * a CellHandle whose value should be interpreted
- * @return a Calendar representing the given Excel date interpreted in the
- * default time zone
- */
- @SuppressWarnings("deprecation")
- public static Calendar getCalendarFromCell(Cell cell) {
- double value;
- DateFormat format = DateFormat.LEGACY_1900;
-
- if (cell instanceof CellHandle) {
- CellHandle realCell = (CellHandle) cell;
- value = realCell.getDoubleVal();
-
- WorkBook book = realCell.getWorkBook();
- if (null != book) {
- format = book.getDateFormat();
- }
- } else {
- value = Double.parseDouble( cell.getVal().toString() );
- }
-
- return getCalendarFromNumber( value, format );
- }
-
- /**
- * Inspects a string to determine if it is a date. Looks for a pattern such
- * as mm/dd/yy, m/d/yy, mm/dd/yyyy etc.
- *
- * @param possibleDate
- * the string to check for date formats
- * @return whether the given string matches a known date format
- */
- public static boolean isDatePattern(String possibleDate) {
- if (possibleDate.indexOf("/") == -1)
- return false;
- StringTokenizer st = new StringTokenizer(possibleDate, "/");
- if (st.countTokens() == 3)
- return true;
- return false;
- }
-
- /**
- * Converts a string representation of a date into a valid calendar object
- * date must be in format mm/dd/yy (or yyyy)
- *
- *
- * @param dateStr
- * @return null if not a valid date
- */
- public static Calendar convertStringToCalendar(String dateStr) {
- if (!isDatePattern(dateStr))
- return null;
- int m, d, y;
- StringTokenizer st = new StringTokenizer(dateStr, "/");
- try {
- m = Integer.valueOf(st.nextToken()).intValue() - 1;
- d = Integer.valueOf(st.nextToken()).intValue();
- String s = st.nextToken();
- int h, mn, sc;
- h = mn = sc = 0;
- if (s.indexOf(" ") > -1) {
- int i = s.indexOf(" ");
- String time = s.substring(i + 1);
- s = s.substring(0, i); // rest of date
- String[] timetokens = time.split(":");
- if (timetokens.length > 0)
- h = Integer.valueOf(timetokens[0]).intValue();
- if (timetokens.length > 1)
- mn = Integer.valueOf(timetokens[1]).intValue();
- if (timetokens.length > 2)
- sc = Integer.valueOf(timetokens[2]).intValue();
- }
- y = Integer.valueOf(s).intValue();
- if (y < 100)
- y += 2000;
- GregorianCalendar cdr = new GregorianCalendar(y, m, d, h, mn, sc);
- return cdr;
- } catch (Exception e) {
- return null;
- }
- }
-
- /**
- * Returns the value of the cell as a date formatted as a String date
- * representation. The format is determined by inspecting the excel format.
- *
- * Currently supported formats in this method are: mm/dd/yy dd-mmm-yy dd-mmm
- * mmm-yy mm/dd/yy hh:mm
- *
- * If the cell's date forrmat pattern falls outside of this range, the
- * default output will be in the following format mm/dd/yyyy
- *
- * @deprecated The date format handling in this method is wildly incorrect.
- * It is retained only to provide compatibility with legacy
- * OpenXLS XML files.
- * @return String, the value of a cell formatted as a date
- */
- public static String getFormattedDateVal(CellHandle cell) {
- // assemble the formatting for the javascript.
- if (!cell.isDate())return "Not a Date";
- if (Double.isNaN(cell.getDoubleVal()))
- return ""; // 20060623 KSC
- Date cal = DateConverter.getDateFromCell(cell);
- FormatHandle f = cell.getFormatHandle();
- int pat = f.getFormatPatternId();
- // SimpleDateFormat sdf = new SimpleDateFormat(); KSC: reuse
-
- switch(pat) {
-
- case 0xe:
- WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy");
- return WorkBookHandle.simpledateformat.format(cal);
-
- case 0xf:
- WorkBookHandle.simpledateformat.applyPattern("dd-MMM-yy");
- return WorkBookHandle.simpledateformat.format(cal);
-
- case 0x10:
- WorkBookHandle.simpledateformat.applyPattern("dd-MMM");
- return WorkBookHandle.simpledateformat.format(cal);
-
- case 0x11:
- WorkBookHandle.simpledateformat.applyPattern("MMM-yy");
- return WorkBookHandle.simpledateformat.format(cal);
-
- case 0x16:
- WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy HH:mm");
- return WorkBookHandle.simpledateformat.format(cal);
-
- default:
- WorkBookHandle.simpledateformat.applyPattern("MM/dd/yyyy");
- return WorkBookHandle.simpledateformat.format(cal);
-
- }
- }
-
- /**
- * @deprecated The date format handling in this method is wildly incorrect.
- * It is retained only to provide compatibility with legacy
- * OpenXLS XML files.
- */
- public static Date parseDate(String s, int pat) {
- if (s.equals(""))
- return null;
- //SimpleDateFormat sdf = new SimpleDateFormat();
- try {
- switch (pat) {
- case 0xe:
- WorkBookHandle.simpledateformat.applyPattern("dd/MM/yy");
- return WorkBookHandle.simpledateformat.parse(s);
-
- case 0xf:
- WorkBookHandle.simpledateformat.applyPattern("dd-MMM-yy");
- return WorkBookHandle.simpledateformat.parse(s);
-
- case 0x10:
- WorkBookHandle.simpledateformat.applyPattern("dd-MMM");
- return WorkBookHandle.simpledateformat.parse(s);
-
- case 0x11:
- WorkBookHandle.simpledateformat.applyPattern("MMM-yy");
- return WorkBookHandle.simpledateformat.parse(s);
-
- case 0x16:
- WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy HH:mm");
- return WorkBookHandle.simpledateformat.parse(s);
-
- default:
- WorkBookHandle.simpledateformat.applyPattern("dd/MM/yyyy");
- return WorkBookHandle.simpledateformat.parse(s);
-
- }
- } catch (Exception e) {
- Logger.logWarn("Failed to parse date " + s + " format pattern: "
- + pat);
- return Calendar.getInstance().getTime();
- }
- }
- /**
- * DATEVALUE
- Returns the serial number of the date represented by date_text. Use DATEVALUE to convert a date represented by text to a serial number.
-
- Syntax
- DATEVALUE(date_text)
-
- Date_text is text that represents a date in a Microsoft Excel date format. For example, "1/30/2008" or "30-Jan-2008" are text strings
- within quotation marks that represent dates. Using the default date system in Excel for Windows,
- date_text must represent a date from January 1, 1900, to December 31, 9999. Using the default date system in Excel for the Macintosh,
- date_text must represent a date from January 1, 1904, to December 31, 9999. DATEVALUE returns the #VALUE! error value if date_text is out of this range.
-
- If the year portion of date_text is omitted, DATEVALUE uses the current year from your computer's built-in clock. Time information in date_text is ignored.
-
- Remarks
-
- Excel stores dates as sequential serial numbers so they can be used in calculations. By default, January 1, 1900 is serial number 1, and January 1, 2008 is serial number 39448 because it is 39,448 days after January 1, 1900. Excel for the Macintosh uses a different date system as its default.
- Most functions automatically convert date values to serial numbers.
-
- * @param String dateString
- * @return
- */
-
- public static Double calcDateValue(String dateString) {
- String[] formats= { "MM/dd/yyyy HH:mm:ss",
- "MM/dd/yy HH:mm:ss",
- "MM/dd/yy",
- "MM/dd/yyyy",
- "MM/d/yyyy HH:mm:ss",
- "MM/d/yy HH:mm:ss",
- "yy-M-d hh:mm:ss a",
- "yy-M-d HH:mm:ss",
- "yy-M-d hh:mm a",
- "yy-M-d HH:mm",
- "dd-M-yyyy hh:mm:ss a", // 10
- "dd-M-yyyy HH:mm:ss",
- "dd-M-yyyy hh:mm a",
- "dd-M-yyyy HH:mm",
- "dd-MMM-yy hh:mm:ss a",
- "dd-MMM-yy HH:mm:ss",
- "dd-MMM-yy hh:mm a",
- "dd-MMM-yy HH:mm",
- "yyMMdd",
- "MM/d/yy",
- "MM/d/yyyy", // 20
- "yyyy/MM/dd",
- "d-MMM-yy",
- "d-M-yy",
- "d-M-yyyy",
- "dd-MMM-yy",
- "dd-MMM-yyyy",
- "dd-M-yyyy",
- "dd-MM-yy",
- "dd-MM-yyyy",
- "d-MMM-yyyy", // 30
- "d-M-yyyy",
- "d-MMM-yyyy", // 32 really is d-MMM but inorder to match, must append year
- "d/MMM/yyyy", // 33 really is d/MMM but in order to match, must append year
- "M-yy" ,
- "MMM-yy",
- "M/d/yyyy",
- "M d, yyyy",
- "yyyy-MM-dd",
- "yy-M-d",
- "yyyy-MM-dd",
- "MMyy",
- "yyMM",
- "yyyyMMddHHmm",
- "yyyyMMddHHmmss",
- "yyMMddHHmmss",
- "MMDDHHmm",
- "MMMM dd, yyyy",
- "E, MMM d, yyyy",
- "E MMM dd, yyyy",
- "EE, MMM dd, yyyy",
- "E, MMMM d, yyyy",
- "E, MMMM dd, yyyy",
- "EE, MMMM dd, yyyy",
- "hh:mm:ss a",
- "HH:mm:ss",
- "hh:mm a",
- "HH:mm",
- };
- for (int i= 0; i < formats.length; i++) {
- try {
- String ds= dateString;
- if (i==32 || i==33) { // then must add year to date
- GregorianCalendar calendar = new GregorianCalendar();
- int curyear = calendar.get(Calendar.YEAR);
- if (i==32) ds= dateString + "-" + curyear;
- else ds= dateString + "/" + curyear;
- }
- //SimpleDateFormat format= new SimpleDateFormat(formats[i], Locale.ENGLISH); // 20090701 KSC: apparently need Locale -- why now though??
- //format.setLenient(false);
- WorkBookHandle.simpledateformat.applyLocalizedPattern(formats[i]);
- WorkBookHandle.simpledateformat.setLenient(false);
- //Date d= format.parse(ds);
- Date d= WorkBookHandle.simpledateformat.parse(ds);
- return DateConverter.getXLSDateVal(d);
- } catch (Exception e) { }
- }
- return null;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/DateConverter.kt b/src/main/java/io/starter/OpenXLS/DateConverter.kt
new file mode 100644
index 0000000..fc335e8
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/DateConverter.kt
@@ -0,0 +1,697 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+//import java.text.SimpleDateFormat;
+
+import io.starter.toolkit.Logger
+
+import java.util.Calendar
+import java.util.Date
+import java.util.GregorianCalendar
+import java.util.StringTokenizer
+
+/**
+ * Provides methods for conversion to and from Excel serial date values.
+ *
+ *
+ * Excel stores dates as the number of days since midnight on January 1, 1900.
+ * Times are represented as fractional days. For example, 6:00 AM on February 2,
+ * 1900 is represented as 33.25. Excel incorrectly treats 1900 as a leap year,
+ * so serial dates after February 28, 1900 are one higher than they otherwise
+ * should be and the value 60 is unmapped. It also interprets the value 0 as
+ * January 0, 1900.
+ *
+ *
+ * Excel does not support negative serial date values, so it cannot handle dates
+ * prior to 1900. It also does not currently accept date values with a year of
+ * 10000 or greater. OpenXLS does not currently support negative date values,
+ * but this feature is planned. If you wish to restrict the output to the subset
+ * of values supported by Excel, you may enable input validation by calling
+ * [.setValidate].
+ *
+ *
+ * Due to the inherent inaccuracy of floating-point types, values from this
+ * class can only be guaranteed to equal values generated by Excel to eight
+ * decimal places. This provides accuracy to the unit milliseconds, the maximum
+ * precision of Java's date classes. Accuracy outside the range supported by
+ * Excel is not guaranteed and will degrade as the values get farther from zero.
+ */
+object DateConverter {
+ /**
+ * The number of milliseconds in a day.
+ */
+ private val MILLIS_DAY = 86400000
+
+ /**
+ * The extra day caused by the 1900 leap year bug.
+ */
+ private val EXTRA_DAY = 60
+
+ /**
+ * Calendar used for date calculation.
+ */
+ private var calendar = Calendar.getInstance()
+
+ /**
+ * Whether to validate input dates for Excel compatibility.
+ */
+ /**
+ * Returns whether input validation is on.
+ */
+ /**
+ * Sets whether to perform input validation.
+ */
+ var validate = false
+
+ /**
+ * The set of supported serial date encoding schemes.
+ */
+ enum class DateFormat private constructor(val epochDelta: Int, val lowerLimit: Double, val upperLimit: Double) {
+ /**
+ * 1900 epoch with negative value support as used in OOXML.
+ *
+ *
+ * Lower limit: -9999/01/01 00:00:00, value -4 346 018
+ * Epoch date: 1899/12/30 00:00:00, value 0
+ * Upper limit: 9999/12/31 23:59:59, value 2 958 465.999 988 4
+ */
+ OOXML_1900(25569, -4346018, 2958465.9999884),
+
+ /**
+ * 1900 epoch without negative value support as used in BIFF8.
+ *
+ *
+ * Epoch date: 1899/12/31 00:00:00, value 0
+ * Lower limit: 1900/01/01 00:00:00, value 1
+ * Upper limit: 9999/12/31 23:59:59, value 2 958 465.999 988 4
+ *
+ *
+ * In this system 1900 is (incorrectly) considered a leap year. Serial
+ * dates after 1900/02/28 are one higher than they otherwise should be
+ * and the value 60 is unmapped.
+ */
+ LEGACY_1900(25568, 1, 2958465.9999884),
+
+ /**
+ * 1904 epoch without negative value support as used by Excel for Mac.
+ *
+ *
+ * Epoch date: 1904/01/01 00:00:00, value 0
+ * Lower limit: 1904/01/01 00:00:00, value 0
+ * Upper limit: 9999/12/31 23:59:59, value 2 957 003.999 988 4
+ */
+ LEGACY_1904(24107, 0, 2957003.9999884)
+ }
+
+ /**
+ * Gets a clone of the calendar used for date calculation.
+ */
+ fun getCalendar(): Calendar {
+ return calendar.clone() as Calendar
+ }
+
+ /**
+ * Sets the calendar used to perform date calculation. This allows you to
+ * set the locale and time zone to something other than the system default.
+ *
+ * @param cal the calendar that should be used for date calculations
+ */
+ fun setCalendar(cal: Calendar) {
+ calendar = cal
+ }
+
+ /**
+ * returns whether this method will work with your input string
+ */
+ fun isParseableDateString(str: String): Boolean {
+ var str = str
+ // fix problem with timestamps tagged on end
+ if (str.indexOf(" ") > 0) {
+ str = str.substring(0, str.indexOf(" "))
+ }
+ try {
+ val d1 = java.sql.Date.valueOf(str)
+ getXLSDateVal(d1)
+ return true
+ } catch (e: IllegalArgumentException) {
+ return false
+ }
+
+ }
+
+ /**
+ * attempt to interpret a date string into a date
+ * returns null if cannot be converted to date
+ */
+ fun getDate(str: String): Date? {
+ try {
+ val d1 = java.sql.Timestamp.valueOf(str)
+ val cal = calendar.clone() as Calendar
+ cal.time = d1
+ return cal.time
+ } catch (e: Exception) {
+ }
+
+ return null
+
+ }
+
+ /**
+ * Converts the value of the given Calendar to an Excel serial date.
+ *
+ * @param cal the Calendar to convert
+ * @param format the serial date format to use
+ * @return the Excel serial date representing the given calendar's value in
+ * the calendar's time zone
+ */
+ @JvmOverloads
+ fun getXLSDateVal(cal: Calendar, format: DateFormat = DateFormat.LEGACY_1900): Double {
+ // Get the UTC milliseconds since the epoch
+ var millis = cal.timeInMillis
+
+ // Add the GMT offset and daylight savings offset for the time zone
+ millis += (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)).toLong()
+
+ // Convert from milliseconds to days
+ var days = millis.toDouble() / MILLIS_DAY
+
+ // Switch from UNIX epoch to the Excel epoch
+ days += format.epochDelta.toDouble()
+
+ // If the date is after February 28, 1900 add one day.
+ // This compensates for Excel incorrectly treating 1900 as a leap year
+ if (format == DateFormat.LEGACY_1900 && days >= EXTRA_DAY)
+ days += 1.0
+
+ // Perform validation
+ if (validate && (days < format.lowerLimit || days > format.upperLimit))
+ throw IllegalArgumentException(
+ "the given date is not supported by Excel")
+
+ // Return the Excel serial date value
+ return days
+ }
+
+ /**
+ * Converts the given Date to an Excel serial date in the default time zone.
+ *
+ * @param date the date to be converted
+ * @param format the serial date format to use
+ * @return the Excel serial date value corresponding to the given date
+ */
+ @JvmOverloads
+ fun getXLSDateVal(date: Date, format: DateFormat = DateFormat.LEGACY_1900): Double {
+ val cal = calendar.clone() as Calendar
+ cal.time = date
+ return getXLSDateVal(cal, format)
+ }
+
+ /**
+ * Parses the the given Excel serial date and returns a Calendar.
+ *
+ * @param date the Excel serial date to be interpreted
+ * @param format the date format with which to interpret the serial date
+ * @return a Calendar representing the given Excel date interpreted in the
+ * default time zone
+ */
+ @JvmOverloads
+ fun getCalendarFromNumber(date: Double, format: DateFormat = DateFormat.LEGACY_1900): Calendar {
+ val cal = getCalendar()
+ var days = date
+
+ // For the legacy 1900 epoch, if the date is after 1900/02/28 subtract
+ // one day. This compensates for 1900 being considered a leap year.
+ // Not matching the non-existent February 29 causes it to become
+ // March 1. This behavior matches that of Calendar for the same input.
+ if (format == DateFormat.LEGACY_1900 && days > EXTRA_DAY)
+ days -= 1.0
+
+ // Switch from the Excel epoch to the UNIX epoch
+ days -= format.epochDelta.toDouble()
+
+ // Convert from days to milliseconds
+ val millis = Math.round(days * MILLIS_DAY)
+
+ // Set the calendar's approximate time so zone offsets are correct
+ // The offsets can still be wrong for certain border cases.
+ cal.timeInMillis = millis
+
+ // Adjust for time zone and daylight saving time offsets
+ var offset: Long = 0
+ var count = 0
+ while (offset != (offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)).toLong()) && count < 3) {
+ cal.timeInMillis = millis - offset
+ count++
+ }
+
+ return cal
+ }
+
+ /**
+ * Parses the the given Excel serial date and returns a Date.
+ * The date will be interpreted in the
+ * [legacy 1900][DateFormat.LEGACY_1900] format.
+ *
+ * @param date the Excel serial date to be interpreted
+ * @param format the date format with which to interpret the serial date
+ * @return a Calendar representing the given Excel date interpreted in the
+ * default time zone
+ */
+ @Deprecated("Use {@link #getCalendarFromNumber(double, DateFormat)} instead.")
+ fun getDateFromNumber(date: Double): Date {
+ return getCalendarFromNumber(date).time
+ }
+
+ /**
+ * Gets the Date for the given Excel serial date.
+ *
+ * @param number a Number representing the serial date to be interpreted
+ * @return a Date representing the given Excel date interpreted in the
+ * default time zone
+ * @throws ClassCastException if the passed object is not a Number
+ */
+ @Deprecated("Use {@link #getDateFromNumber(double)} instead.")
+ fun getDateFromNumber(number: Any): Date {
+ return if (number is Number)
+ getDateFromNumber(number.toDouble())
+ else
+ throw ClassCastException("passed object was not a number")
+ }
+
+ /**
+ * Gets the Date for the given Excel serial date.
+ *
+ * @param number a Number representing the serial date to be interpreted
+ * @return a Date representing the given Excel date interpreted in the
+ * default time zone
+ * @throws ClassCastException if the passed object is not a Number
+ */
+ @Deprecated("Identical to {@link #getDateFromNumber(Object)}.")
+ fun getNonLocalizedDateFromNumber(number: Any): Date {
+ return getDateFromNumber(number)
+ }
+
+ /**
+ * Gets the Calendar for the given Excel serial date.
+ *
+ * @param date the Excel serial date or datestring to be interpreted
+ * @return a Calendar representing the given Excel date interpreted in the
+ * default time zone
+ * @throws ClassCastException if the passed object is not a Number
+ */
+ @Deprecated("Use {@link #getCalendarFromNumber(double)} instead.")
+ fun getCalendarFromNumber(number: Any?): Calendar {
+ var number: Any? = number ?: throw ClassCastException("object cannot be converted to a date")
+ if (number !is Number)
+ number = Double(number!!.toString())
+
+ return if (number is Number)
+ getCalendarFromNumber(number.toDouble())
+ else
+ throw ClassCastException("passed object was not a number")
+ }
+
+ /**
+ * Gets the Date for the given Excel serial date.
+ *
+ * @param number a Number representing the serial date to be interpreted
+ * @return a Date representing the given Excel date interpreted in the
+ * default time zone
+ * @throws ClassCastException if the passed object is not a Number
+ */
+ @Deprecated("Identical to {@link #getDateFromNumber(Object)}.")
+ fun getNonLocalizedCalendarFromNumber(number: Any): Calendar {
+ return getCalendarFromNumber(number)
+ }
+
+ /**
+ * Gets the Date for the given cell.
+ *
+ * @param cell a CellHandle whose value should be interpreted
+ * @return a Date representing the given Excel date interpreted in the
+ * default time zone
+ */
+ fun getDateFromCell(cell: CellHandle): Date {
+ return getCalendarFromCell(cell).time
+ }
+
+ /**
+ * returns a Java Calendar from a CellHandle containing an Excel-formatted
+ * Date
+ *
+ *
+ * The Excel date format does not map 100% accurately to Java dates, due to
+ * the limitation of the precision of the Excel floating-point value record.
+ * Due to this, OpenXLS dates may be too precise, this method will round
+ * the java.util.Date returned to the precision entered. Rounding is handled
+ * by the ROUND_HALF_UP method.
+ *
+ *
+ * Pass in a static Calendar precision, options are Calendar.HOUR
+ * Calendar.MINUTE Calendar.SECOND Calendar.MILLISECOND
+ *
+ * @return Calendar - A GregorianCalendar value of the Cell
+ */
+ fun getCalendarFromCellWithPrecision(cell: Cell,
+ roundingCalendarField: Int): Calendar {
+ val tmp = getCalendarFromCell(cell)
+ val newCalendar = GregorianCalendar()
+ newCalendar.set(Calendar.YEAR, tmp.get(Calendar.YEAR))
+ newCalendar.set(Calendar.MONTH, tmp.get(Calendar.MONTH))
+ newCalendar.set(Calendar.DAY_OF_MONTH, tmp.get(Calendar.DAY_OF_MONTH))
+ newCalendar.set(Calendar.HOUR_OF_DAY, tmp.get(Calendar.HOUR_OF_DAY))
+ if (roundingCalendarField == Calendar.HOUR) {
+ if (tmp.get(Calendar.MINUTE) > 29) {
+ newCalendar.set(Calendar.HOUR_OF_DAY,
+ tmp.get(Calendar.HOUR_OF_DAY) + 1)
+ }
+ newCalendar.set(Calendar.MINUTE, 0)
+ newCalendar.set(Calendar.SECOND, 0)
+ newCalendar.set(Calendar.MILLISECOND, 0)
+ return newCalendar
+ }
+ newCalendar.set(Calendar.MINUTE, tmp.get(Calendar.MINUTE))
+ if (roundingCalendarField == Calendar.MINUTE) {
+ if (tmp.get(Calendar.SECOND) > 29) {
+ newCalendar.set(Calendar.MINUTE, tmp.get(Calendar.MINUTE) + 1)
+ }
+ newCalendar.set(Calendar.SECOND, 0)
+ newCalendar.set(Calendar.MILLISECOND, 0)
+ return newCalendar
+ }
+ newCalendar.set(Calendar.SECOND, tmp.get(Calendar.SECOND))
+ if (roundingCalendarField == Calendar.SECOND) {
+ if (tmp.get(Calendar.MILLISECOND) > 499) {
+ newCalendar.set(Calendar.SECOND, tmp.get(Calendar.SECOND) + 1)
+ }
+ newCalendar.set(Calendar.MILLISECOND, 0)
+ return newCalendar
+ }
+ // round the milliseconds
+ newCalendar.set(Calendar.MILLISECOND, tmp.get(Calendar.MILLISECOND))
+ return newCalendar
+
+ }
+
+ /**
+ * Gets the Calendar for the given cell.
+ *
+ * @param cell a CellHandle whose value should be interpreted
+ * @return a Calendar representing the given Excel date interpreted in the
+ * default time zone
+ */
+ fun getCalendarFromCell(cell: Cell): Calendar {
+ val value: Double
+ var format = DateFormat.LEGACY_1900
+
+ if (cell is CellHandle) {
+ value = cell.doubleVal
+
+ val book = cell.workBook
+ if (null != book) {
+ format = book.dateFormat
+ }
+ } else {
+ value = java.lang.Double.parseDouble(cell.`val`.toString())
+ }
+
+ return getCalendarFromNumber(value, format)
+ }
+
+ /**
+ * Inspects a string to determine if it is a date. Looks for a pattern such
+ * as mm/dd/yy, m/d/yy, mm/dd/yyyy etc.
+ *
+ * @param possibleDate the string to check for date formats
+ * @return whether the given string matches a known date format
+ */
+ fun isDatePattern(possibleDate: String): Boolean {
+ if (possibleDate.indexOf("/") == -1)
+ return false
+ val st = StringTokenizer(possibleDate, "/")
+ return st.countTokens() == 3
+ }
+
+ /**
+ * Converts a string representation of a date into a valid calendar object
+ * date must be in format mm/dd/yy (or yyyy)
+ *
+ * @param dateStr
+ * @return null if not a valid date
+ */
+ fun convertStringToCalendar(dateStr: String): Calendar? {
+ if (!isDatePattern(dateStr))
+ return null
+ val m: Int
+ val d: Int
+ var y: Int
+ val st = StringTokenizer(dateStr, "/")
+ try {
+ m = Integer.valueOf(st.nextToken()).toInt() - 1
+ d = Integer.valueOf(st.nextToken()).toInt()
+ var s = st.nextToken()
+ var h: Int
+ var mn: Int
+ var sc: Int
+ sc = 0
+ mn = sc
+ h = mn
+ if (s.indexOf(" ") > -1) {
+ val i = s.indexOf(" ")
+ val time = s.substring(i + 1)
+ s = s.substring(0, i) // rest of date
+ val timetokens = time.split(":".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
+ if (timetokens.size > 0)
+ h = Integer.valueOf(timetokens[0]).toInt()
+ if (timetokens.size > 1)
+ mn = Integer.valueOf(timetokens[1]).toInt()
+ if (timetokens.size > 2)
+ sc = Integer.valueOf(timetokens[2]).toInt()
+ }
+ y = Integer.valueOf(s).toInt()
+ if (y < 100)
+ y += 2000
+ return GregorianCalendar(y, m, d, h, mn, sc)
+ } catch (e: Exception) {
+ return null
+ }
+
+ }
+
+ /**
+ * Returns the value of the cell as a date formatted as a String date
+ * representation. The format is determined by inspecting the excel format.
+ *
+ *
+ * Currently supported formats in this method are: mm/dd/yy dd-mmm-yy dd-mmm
+ * mmm-yy mm/dd/yy hh:mm
+ *
+ *
+ * If the cell's date forrmat pattern falls outside of this range, the
+ * default output will be in the following format mm/dd/yyyy
+ *
+ * @return String, the value of a cell formatted as a date
+ */
+ @Deprecated("The date format handling in this method is wildly incorrect.\n" +
+ " It is retained only to provide compatibility with legacy\n" +
+ " OpenXLS XML files.")
+ fun getFormattedDateVal(cell: CellHandle): String {
+ // assemble the formatting for the javascript.
+ if (!cell.isDate) return "Not a Date"
+ if (java.lang.Double.isNaN(cell.doubleVal))
+ return "" // 20060623 KSC
+ val cal = DateConverter.getDateFromCell(cell)
+ val f = cell.formatHandle
+ val pat = f!!.formatPatternId
+ // SimpleDateFormat sdf = new SimpleDateFormat(); KSC: reuse
+
+ when (pat) {
+
+ 0xe -> {
+ WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+
+ 0xf -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd-MMM-yy")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+
+ 0x10 -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd-MMM")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+
+ 0x11 -> {
+ WorkBookHandle.simpledateformat.applyPattern("MMM-yy")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+
+ 0x16 -> {
+ WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy HH:mm")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+
+ else -> {
+ WorkBookHandle.simpledateformat.applyPattern("MM/dd/yyyy")
+ return WorkBookHandle.simpledateformat.format(cal)
+ }
+ }
+ }
+
+
+ @Deprecated("The date format handling in this method is wildly incorrect.\n" +
+ " It is retained only to provide compatibility with legacy\n" +
+ " OpenXLS XML files.")
+ fun parseDate(s: String, pat: Int): Date? {
+ if (s == "")
+ return null
+ //SimpleDateFormat sdf = new SimpleDateFormat();
+ try {
+ when (pat) {
+ 0xe -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd/MM/yy")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+
+ 0xf -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd-MMM-yy")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+
+ 0x10 -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd-MMM")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+
+ 0x11 -> {
+ WorkBookHandle.simpledateformat.applyPattern("MMM-yy")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+
+ 0x16 -> {
+ WorkBookHandle.simpledateformat.applyPattern("MM/dd/yy HH:mm")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+
+ else -> {
+ WorkBookHandle.simpledateformat.applyPattern("dd/MM/yyyy")
+ return WorkBookHandle.simpledateformat.parse(s)
+ }
+ }
+ } catch (e: Exception) {
+ Logger.logWarn("Failed to parse date " + s + " format pattern: "
+ + pat)
+ return Calendar.getInstance().time
+ }
+
+ }
+
+ /**
+ * DATEVALUE
+ * Returns the serial number of the date represented by date_text. Use DATEVALUE to convert a date represented by text to a serial number.
+ *
+ *
+ * Syntax
+ * DATEVALUE(date_text)
+ *
+ *
+ * Date_text is text that represents a date in a Microsoft Excel date format. For example, "1/30/2008" or "30-Jan-2008" are text strings
+ * within quotation marks that represent dates. Using the default date system in Excel for Windows,
+ * date_text must represent a date from January 1, 1900, to December 31, 9999. Using the default date system in Excel for the Macintosh,
+ * date_text must represent a date from January 1, 1904, to December 31, 9999. DATEVALUE returns the #VALUE! error value if date_text is out of this range.
+ *
+ *
+ * If the year portion of date_text is omitted, DATEVALUE uses the current year from your computer's built-in clock. Time information in date_text is ignored.
+ *
+ *
+ * Remarks
+ *
+ *
+ * Excel stores dates as sequential serial numbers so they can be used in calculations. By default, January 1, 1900 is serial number 1, and January 1, 2008 is serial number 39448 because it is 39,448 days after January 1, 1900. Excel for the Macintosh uses a different date system as its default.
+ * Most functions automatically convert date values to serial numbers.
+ *
+ * @param String dateString
+ * @return
+ */
+
+ fun calcDateValue(dateString: String): Double? {
+ val formats = arrayOf("MM/dd/yyyy HH:mm:ss", "MM/dd/yy HH:mm:ss", "MM/dd/yy", "MM/dd/yyyy", "MM/d/yyyy HH:mm:ss", "MM/d/yy HH:mm:ss", "yy-M-d hh:mm:ss a", "yy-M-d HH:mm:ss", "yy-M-d hh:mm a", "yy-M-d HH:mm", "dd-M-yyyy hh:mm:ss a", // 10
+ "dd-M-yyyy HH:mm:ss", "dd-M-yyyy hh:mm a", "dd-M-yyyy HH:mm", "dd-MMM-yy hh:mm:ss a", "dd-MMM-yy HH:mm:ss", "dd-MMM-yy hh:mm a", "dd-MMM-yy HH:mm", "yyMMdd", "MM/d/yy", "MM/d/yyyy", // 20
+ "yyyy/MM/dd", "d-MMM-yy", "d-M-yy", "d-M-yyyy", "dd-MMM-yy", "dd-MMM-yyyy", "dd-M-yyyy", "dd-MM-yy", "dd-MM-yyyy", "d-MMM-yyyy", // 30
+ "d-M-yyyy", "d-MMM-yyyy", // 32 really is d-MMM but inorder to match, must append year
+ "d/MMM/yyyy", // 33 really is d/MMM but in order to match, must append year
+ "M-yy", "MMM-yy", "M/d/yyyy", "M d, yyyy", "yyyy-MM-dd", "yy-M-d", "yyyy-MM-dd", "MMyy", "yyMM", "yyyyMMddHHmm", "yyyyMMddHHmmss", "yyMMddHHmmss", "MMDDHHmm", "MMMM dd, yyyy", "E, MMM d, yyyy", "E MMM dd, yyyy", "EE, MMM dd, yyyy", "E, MMMM d, yyyy", "E, MMMM dd, yyyy", "EE, MMMM dd, yyyy", "hh:mm:ss a", "HH:mm:ss", "hh:mm a", "HH:mm")
+ for (i in formats.indices) {
+ try {
+ var ds = dateString
+ if (i == 32 || i == 33) { // then must add year to date
+ val calendar = GregorianCalendar()
+ val curyear = calendar.get(Calendar.YEAR)
+ if (i == 32)
+ ds = "$dateString-$curyear"
+ else
+ ds = "$dateString/$curyear"
+ }
+ //SimpleDateFormat format= new SimpleDateFormat(formats[i], Locale.ENGLISH); // 20090701 KSC: apparently need Locale -- why now though??
+ //format.setLenient(false);
+ WorkBookHandle.simpledateformat.applyLocalizedPattern(formats[i])
+ WorkBookHandle.simpledateformat.isLenient = false
+ //Date d= format.parse(ds);
+ val d = WorkBookHandle.simpledateformat.parse(ds)
+ return DateConverter.getXLSDateVal(d)
+ } catch (e: Exception) {
+ }
+
+ }
+ return null
+ }
+
+}
+/**
+ * Converts the value of the given Calendar to an Excel serial date.
+ * The date will be returned in the
+ * [legacy 1900][DateFormat.LEGACY_1900] format.
+ *
+ * @param cal the Calendar to convert
+ * @return the Excel serial date representing the given calendar's value in
+ * the calendar's time zone
+ */
+/**
+ * Converts the given Date to an Excel serial date in the default time zone.
+ * The date will be returned in the
+ * [legacy 1900][DateFormat.LEGACY_1900] format.
+ *
+ * @param date the date to be converted
+ * @return the Excel serial date value corresponding to the given date
+ */
+/**
+ * Parses the the given Excel serial date and returns a Calendar.
+ * The date will be interpreted in the
+ * [legacy 1900][DateFormat.LEGACY_1900] format.
+ *
+ * @param date the Excel serial date to be interpreted
+ * @return a Calendar representing the given Excel date interpreted in the
+ * default time zone
+ */
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/Document.java b/src/main/java/io/starter/OpenXLS/Document.java
deleted file mode 100644
index e79f823..0000000
--- a/src/main/java/io/starter/OpenXLS/Document.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import io.starter.formats.XLS.*;
-
-/** An interface representing an OpenXLS document.
- * @deprecated This interface provides no functionality beyond the abstract
- * {@link DocumentHandle} class. Use that type instead.
- */
-@Deprecated
-public interface Document{
- public static final int DEBUG_LOW = XLSConstants.DEBUG_LOW;
- public static final int DEBUG_MEDIUM = XLSConstants.DEBUG_MEDIUM;
- public static final int DEBUG_HIGH = XLSConstants.DEBUG_HIGH;
-
-
- /** get a non-Excel property
- * @return Returns the properties.
- */
- public Object getProperty(String name) ;
-
- /** add non-Excel property
- * @param properties The properties to set.
- */
- public void addProperty(String name, Object val) ;
-
- /** The Session for the WorkBook instance
- *
- * @return
-
- public BookSession getSession();
- */
-
- /** Sets the internal name of this WorkBookHandle.
- *
- * Overrides the default for 'getName()' which returns
- * the file name source of this WorkBook by default.
- *
- * @param WorkBook Name
- */
- public abstract void setName(String nm);
- /** Set the Debugging level. Higher values output more
- debugging info during execution.
-
- @parameter int Debug level. higher=more verbose
- */
- public abstract void setDebugLevel(int l);
- /** Returns the name of this WorkBook
-
- @return String name of WorkBook
- */
- public abstract String getName();
-
- /** Clears all values in a template WorkBook.
-
- Use this method to 'reset' the values of your
- WorkBook in memory to defaults.
-
- For example, if you load a Servlet with a
- single WorkBookHandle instance, then modify
- values and stream to a Client system, yo
- should call 'clearAll()' when the request
- is completed to remove the modified values
- and set them back to a default.
-
- */
- public abstract void reset();
-
- /** Writes the document to the given stream in the requested format.
- * @param dest the stream to which the document should be written
- * @param format the constant representing the desired output format
- * @throws IllegalArgumentException if the given type code is invalid
- * @throws IOException if an error occurs while writing to the stream
- */
- public void write (OutputStream dest, int format)
- throws IOException;
-
- /** Writes the document to the given stream in its native format.
- * @param dest the stream to which the document should be written
- * @throws IOException if an error occurs while writing to the stream
- */
- public void write (OutputStream dest)
- throws IOException;
-
- /** Writes the document to the given file in the requested format.
- * @param file the path to which the document should be written
- * @param format the constant representing the desired output format
- * @throws IllegalArgumentException if the given type code is invalid
- * @throws IOException if an error occurs while writing to the file
- */
- public void write (File file, int format)
- throws IOException;
-
- /** Writes the document to the given file in its native format.
- * @param file the path to which the document should be written
- * @throws IOException if an error occurs while writing to the stream
- */
- public void write (File file)
- throws IOException;
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/Document.kt b/src/main/java/io/starter/OpenXLS/Document.kt
new file mode 100644
index 0000000..498954c
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/Document.kt
@@ -0,0 +1,150 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or
+ * modify
+ * it under the terms of the GNU Lesser General Public
+ * License as
+ * published by the Free Software Foundation, either version
+ * 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be
+ * useful,
+ * but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.XLSConstants
+
+import java.io.File
+import java.io.IOException
+import java.io.OutputStream
+
+/**
+ * An interface representing an OpenXLS document.
+ * This interface provides no functionality beyond the abstract
+ * [DocumentHandle] class. Use that type instead.
+ */
+interface Document {
+
+ /**
+ * Returns the name of this WorkBook
+ *
+ * @return String name of WorkBook
+ */
+ /** The Session for the WorkBook instance
+ *
+ * @return public BookSession getSession();
+ */
+
+ /**
+ * Sets the internal name of this WorkBookHandle.
+ *
+ *
+ * Overrides the default for 'getName()' which returns
+ * the file name source of this WorkBook by default.
+ *
+ * @param WorkBook Name
+ */
+ var name: String
+
+ /**
+ * get a non-Excel property
+ *
+ * @return Returns the properties.
+ */
+ fun getProperty(name: String): Any
+
+ /**
+ * add non-Excel property
+ *
+ * @param properties The properties to set.
+ */
+ fun addProperty(name: String, `val`: Any)
+
+ /**
+ * Set the Debugging level. Higher values output more
+ * debugging info during execution.
+ *
+ * @parameter int Debug level. higher=more verbose
+ */
+ fun setDebugLevel(l: Int)
+
+ /**
+ * Clears all values in a template WorkBook.
+ *
+ *
+ * Use this method to 'reset' the values of your
+ * WorkBook in memory to defaults.
+ *
+ *
+ * For example, if you load a Servlet with a
+ * single WorkBookHandle instance, then modify
+ * values and stream to a Client system, yo
+ * should call 'clearAll()' when the request
+ * is completed to remove the modified values
+ * and set them back to a default.
+ */
+ fun reset()
+
+ /**
+ * Writes the document to the given stream in the requested format.
+ *
+ * @param dest the stream to which the document should be written
+ * @param format the constant representing the desired output format
+ * @throws IllegalArgumentException if the given type code is invalid
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ fun write(dest: OutputStream, format: Int)
+
+ /**
+ * Writes the document to the given stream in its native format.
+ *
+ * @param dest the stream to which the document should be written
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ fun write(dest: OutputStream)
+
+ /**
+ * Writes the document to the given file in the requested format.
+ *
+ * @param file the path to which the document should be written
+ * @param format the constant representing the desired output format
+ * @throws IllegalArgumentException if the given type code is invalid
+ * @throws IOException if an error occurs while writing to the file
+ */
+ @Throws(IOException::class)
+ fun write(file: File, format: Int)
+
+ /**
+ * Writes the document to the given file in its native format.
+ *
+ * @param file the path to which the document should be written
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ fun write(file: File)
+
+ companion object {
+ val DEBUG_LOW = XLSConstants.DEBUG_LOW
+ val DEBUG_MEDIUM = XLSConstants.DEBUG_MEDIUM
+ val DEBUG_HIGH = XLSConstants.DEBUG_HIGH
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/DocumentHandle.java b/src/main/java/io/starter/OpenXLS/DocumentHandle.java
deleted file mode 100644
index 9c84565..0000000
--- a/src/main/java/io/starter/OpenXLS/DocumentHandle.java
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import io.starter.formats.LEO.LEOFile;
-import io.starter.formats.XLS.OOXMLAdapter;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.TempFileManager;
-
-/** Functionality common to all document types.
- */
-public abstract class DocumentHandle
-implements Document, Handle, Closeable {
- /** Format constant for the most appropriate format for this document.
- * If the document was read in from a file, this is usually the format that
- * was read in.
- */
- public static final int FORMAT_NATIVE = 0;
-
- /** The level of debugging output requested by the user.
- * Higher values should produce more output.
- */
- //TODO: should the debug level be static?
- protected int DEBUGLEVEL = 0;
-
- /** The user-visible display name or title of this document. */
- protected String name = null;
-
- /** The file associated with this document.
- * This will generally be the file the document was parsed from, if any.
- */
- protected File file;
-
- /** Store for workbook properties. */
- private Map props = new HashMap();
-
- /** Handling for a streaming worksheet based workbook **/
- private boolean streamingSheets = false;
-
- /**
- * default constructor
- */
- public DocumentHandle() {
- super();
-
- }
-
- /**
- * Apr 5, 2011
- * @param urlx
- */
- public DocumentHandle(InputStream urlx) {
- super();
- // TODO Auto-generated constructor stub
- Logger.logErr("DocumentHandle InputStream Constructor Not Implemented");
- }
-
- /** Retrieves a property in the workbook property store.
- * This is not an Excel-compatible feature.
- *
- * @param name the name of the property to retrieve
- * @return the value of the requested property or null if it doesn't exist
- */
- public Object getProperty(String name) {
- return props.get(name);
- }
-
- /** Sets the value of a property in the workbook property store.
- * This is not an Excel-compatible feature.
- *
- * @param name the name of the property which should be updated
- * @param value the value to which the property should be set
- */
- public void addProperty(String name, Object val) {
- props.put(name,val);
- }
-
- /** Retrieves a Map containing the workbook properties store.
- * This is not an Excel-compatible feature.
- * @return an immutable Map containing the current workbook properties
- */
- public Map getProperties() {
- return Collections.unmodifiableMap( props );
- }
-
- /** Replaces the workbook properties with the values in a given Map.
- * This is not an Excel-compatible feature.
- *
- * @param properties the values that will replace the existing properties
- */
- public void setProperties(Map properties) {
- props = new HashMap();
- props.putAll( properties );
- }
-
- /** Gets the OpenXLS version number.
- */
- public static String getVersion() {
- return GetInfo.getVersion();
- }
-
- /** Sets the user-visible descriptive name or title of this document.
- * Some formats will persist this setting in the document itself.
- */
- public void setName(String nm) {
- name = nm;
- }
-
-
- /** Handling for streaming sheets. Currently this is in development and unsupported
- * @param streamSheets
- */
- public void setStreamingSheets(boolean streamSheets) {
- this.streamingSheets = streamSheets;
- }
-
- /** Sets the file name associated with this document.
- * @deprecated Use {@link #setFile(File)} instead.
- */
- public void setFileName (String name) {
- file = new File( name ).getAbsoluteFile();
- }
-
- /** Sets the file associated with this document.
- */
- public void setFile (File file) {
- this.file = file;
- }
-
- /** Gets the file associated with this document.
- * For documents read in from a file, this defaults to that file. If no
- * file is associated with this document, for example if the document was
- * parsed from a stream, this may return null.
- */
- public File getFile() {
- return file;
- }
-
- /** Looks for magic numbers in the given input data and attempts to parse
- * it with an appropriate DocumentHandle subclass. Detection
- * is performed on a best-effort basis and is not guaranteed to be accurate.
- * @throws IOException if an error occurs while reading from the stream
- * @throws WorkBookException if parsing fails
- */
- public static DocumentHandle getInstance (InputStream input)
- throws IOException {
- BufferedInputStream bufferedStream = new BufferedInputStream(input);
- // read in that start of the file for checking magic numbers
- byte[] headerBytes;
- int count;
- // make sure the file is long enough to get magic numbers
- bufferedStream.mark(1028);
- headerBytes = new byte[ 512 ];
- count = bufferedStream.read( headerBytes );
- bufferedStream.reset();
-
- // if it starts with the LEO magic number check the header
- if (LEOFile.checkIsLEO( headerBytes, count )) {
- LEOFile leo = new LEOFile( bufferedStream );
-
- if (leo.hasWorkBook()) return new WorkBookHandle( leo );
- else throw new WorkBookException(
- "input is LEO but no supported format detected", -1 );
- }
-
- String headerString;
- try {
- headerString = new String( headerBytes, 0, count, "UTF-8" );
- } catch (UnsupportedEncodingException e) {
- // UTF-8 support is required by the JLS
- throw new Error( "the JVM does not support UTF-8", e );
- }
-
- // if it's a ZIP archive, try parsing as OOXML
- if (headerString.startsWith( "PK" )) {
- return new WorkBookHandle( bufferedStream );
- }
-
- if((headerString.indexOf(",")>-1)
- &&(headerString.indexOf(",")>-1)){
- // init a blank workbook
- WorkBookHandle book = new WorkBookHandle();
-
-
- // map CSV into workbook
- try{
- WorkSheetHandle sheet = book.getWorkSheet( 0 );
- sheet.readCSV( new BufferedReader(
- new InputStreamReader( bufferedStream ) ) );
- return book;
- }catch(Exception e){
- throw new WorkBookException(
- "Error encountered importing CSV: " + e.toString(), WorkBookException.ILLEGAL_INIT_ERROR);
- }
- }
-
- else {
- throw new WorkBookException( "unknown file format", -1 );
- }
- }
-
- /** Gets the file name associated with this document.
- * For documents read in from a file, this defaults to that file. If no
- * file is associated with this document, for example if the document was
- * parsed from a stream, this may return null.
- * @deprecated Use {@link #getFile()} instead.
- */
- public String getFileName(){
- return file != null ? file.getPath() : "New Document.doc";
- }
-
- /** Sets the debugging output level.
- * Higher values will produce more output. Output at higher values will
- * generally only be of use to OpenXLS developers. Increased output incurs
- * a performance penalty, so it is recommended this be left at zero unless
- * you are reporting a bug.
- */
- public void setDebugLevel (int level) {
- DEBUGLEVEL = level;
- }
-
- public int getDebugLevel() { return DEBUGLEVEL; }
-
- /** Downloads the resource at the given URL to a temporary file.
- * @param u the URL representing the resource to be downloaded
- * @return the path to a temporary file containing the downloaded resource
- * or null if an error occurred
- * @deprecated The download should be handled outside OpenXLS.
- * There is no specific replacement for this method.
- */
- @Deprecated
- protected static File getFileFromURL(URL u) {
- try{
- File fx = TempFileManager.createTempFile("upload-"+System.currentTimeMillis(),".tmp");
-
- URLConnection uc = u.openConnection();
- String contentType = uc.getContentType();
- int contentLength = uc.getContentLength();
- if (contentType.startsWith("text/") || contentLength == -1) {
- throw new IOException("This is not a binary file.");
- }
- InputStream raw = uc.getInputStream();
- InputStream in = new BufferedInputStream(raw);
- byte[] data = new byte[contentLength];
- int bytesRead = 0;
- int offset = 0;
- while (offset < contentLength) {
- bytesRead = in.read(data, offset, data.length - offset);
- if (bytesRead == -1)
- break;
- offset += bytesRead;
- }
- in.close();
-
- if (offset != contentLength) {
- throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes");
- }
-
- // String filename = u.getFile().substring(filename.lastIndexOf('/') + 1);
- FileOutputStream out = new FileOutputStream(fx);
- out.write(data);
- out.flush();
- out.close();
- return fx;
- }catch(Exception e){
- Logger.logErr("Could not load WorkBook from URL: " + e.toString());
- return null;
- }
- }
-
- /** Gets the user-visible descriptive name or title of this document.
- */
- public String getName(){
- if(name!=null)
- return name;
- else
- return "Untitled Document";
- }
-
- /** Resets the document state to what it was when it was loaded.
- * @throws UnsupportedOperationException if there is not sufficient data
- * available to perform the reversion
- */
- public abstract void reset();
-
- /** Gets the constant representing this document's native format.
- */
- public abstract int getFormat();
-
- /** Gets the file name extension for this document's native format.
- */
- public abstract String getFileExtension();
-
- /** Writes the document to the given stream in the requested format.
- * @param dest the stream to which the document should be written
- * @param format the constant representing the desired output format
- * @throws IllegalArgumentException if the given type code is invalid
- * @throws IOException if an error occurs while writing to the stream
- */
- public abstract void write (OutputStream dest, int format)
- throws IOException;
-
- /** Writes the document to the given stream in its native format.
- * @param dest the stream to which the document should be written
- * @throws IOException if an error occurs while writing to the stream
- */
- public void write (OutputStream dest)
- throws IOException {
- this.write( dest, FORMAT_NATIVE );
- }
-
- /** Writes the document to the given file in the requested format.
- * @param file the path to which the document should be written
- * @param format the constant representing the desired output format
- * @throws IllegalArgumentException if the given type code is invalid
- * @throws IOException if an error occurs while writing to the file
- */
- public void write (File file, int format)
- throws IOException {
- if (format > WorkBookHandle.FORMAT_XLS && this.file!=null)
- OOXMLAdapter.refreshPassThroughFiles((WorkBookHandle)this);
-
- if (file.exists()) file.delete(); // try this
- OutputStream stream = new BufferedOutputStream(new FileOutputStream( file ) );
- this.write( stream, format );
- this.file= file; // necesary for OOXML re-write ...
- stream.flush();
- stream.close();
- }
-
- /** Writes the document to the given file in its native format.
- * @param file the path to which the document should be written
- * @throws IOException if an error occurs while writing to the stream
- */
- public void write (File file)
- throws IOException {
- this.write( file, FORMAT_NATIVE );
- }
-
- /** Returns a string representation of the object.
- * This is currently equivalent to {@link #getName()}.
- */
- public String toString() {
- return getName();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/DocumentHandle.kt b/src/main/java/io/starter/OpenXLS/DocumentHandle.kt
new file mode 100644
index 0000000..063ccfb
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/DocumentHandle.kt
@@ -0,0 +1,419 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or
+ * modify
+ * it under the terms of the GNU Lesser General Public
+ * License as
+ * published by the Free Software Foundation, either version
+ * 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be
+ * useful,
+ * but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.LEO.LEOFile
+import io.starter.formats.XLS.OOXMLAdapter
+import io.starter.toolkit.Logger
+import io.starter.toolkit.TempFileManager
+
+import java.io.*
+import java.net.URL
+import java.net.URLConnection
+import java.nio.charset.StandardCharsets
+import java.util.Collections
+import java.util.HashMap
+
+/**
+ * Functionality common to all document types.
+ */
+abstract class DocumentHandle : Document, Handle, Closeable {
+
+ /**
+ * The level of debugging output requested by the user.
+ * Higher values should produce more output.
+ */
+ // TODO: should the debug level be static?
+ protected var DEBUGLEVEL = 0
+
+ /**
+ * The user-visible display name or title of this document.
+ */
+ protected var name: String? = null
+
+ /**
+ * The file associated with this document.
+ * This will generally be the file the document was parsed from, if any.
+ */
+ /**
+ * Gets the file associated with this document.
+ * For documents read in from a file, this defaults to that file. If no
+ * file is associated with this document, for example if the document was
+ * parsed from a stream, this may return `null`.
+ */
+ /**
+ * Sets the file associated with this document.
+ */
+ var file: File? = null
+
+ /**
+ * Store for workbook properties.
+ */
+ private var props: MutableMap = HashMap()
+
+ /**
+ * Handling for a streaming worksheet based workbook
+ */
+ private var streamingSheets = false
+
+ /**
+ * Retrieves a Map containing the workbook properties store.
+ * This is not an Excel-compatible feature.
+ *
+ * @return an immutable Map containing the current workbook properties
+ */
+ /**
+ * Replaces the workbook properties with the values in a given Map.
+ * This is not an Excel-compatible feature.
+ *
+ * @param properties the values that will replace the existing properties
+ */
+ var properties: Map
+ get() = Collections.unmodifiableMap(props)
+ set(properties) {
+ props = HashMap()
+ props.putAll(properties)
+ }
+
+ /**
+ * Gets the file name associated with this document.
+ * For documents read in from a file, this defaults to that file. If no
+ * file is associated with this document, for example if the document was
+ * parsed from a stream, this may return `null`.
+ *
+ */
+ /**
+ * Sets the file name associated with this document.
+ *
+ */
+ var fileName: String
+ @Deprecated("Use {@link #getFile()} instead.")
+ get() = if (file != null) file!!.path else "New Document.doc"
+ @Deprecated("Use {@link #setFile(File)} instead.")
+ set(name) {
+ file = File(name).absoluteFile
+ }
+
+ /**
+ * Gets the constant representing this document's native format.
+ */
+ abstract val format: Int
+
+ /**
+ * Gets the file name extension for this document's native format.
+ */
+ abstract val fileExtension: String
+
+ /**
+ * default constructor
+ */
+ constructor() : super() {
+
+ }
+
+ /**
+ * Apr 5, 2011
+ *
+ * @param urlx
+ */
+ constructor(urlx: InputStream) : super() {
+ // TODO Auto-generated constructor stub
+ Logger.logErr("DocumentHandle InputStream Constructor Not Implemented")
+ }
+
+ constructor(input: File) {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * Retrieves a property in the workbook property store.
+ * This is not an Excel-compatible feature.
+ *
+ * @param name the name of the property to retrieve
+ * @return the value of the requested property or null if it doesn't exist
+ */
+ override fun getProperty(name: String): Any {
+ return props[name]
+ }
+
+ /**
+ * Sets the value of a property in the workbook property store.
+ * This is not an Excel-compatible feature.
+ *
+ * @param name the name of the property which should be updated
+ * @param value the value to which the property should be set
+ */
+ override fun addProperty(name: String, `val`: Any) {
+ props[name] = `val`
+ }
+
+ /**
+ * Sets the user-visible descriptive name or title of this document.
+ * Some formats will persist this setting in the document itself.
+ */
+ override fun setName(nm: String) {
+ name = nm
+ }
+
+ /**
+ * Handling for streaming sheets. Currently this is in development and unsupported
+ *
+ * @param streamSheets
+ */
+ fun setStreamingSheets(streamSheets: Boolean) {
+ this.streamingSheets = streamSheets
+ }
+
+ /**
+ * Sets the debugging output level.
+ * Higher values will produce more output. Output at higher values will
+ * generally only be of use to OpenXLS developers. Increased output incurs
+ * a performance penalty, so it is recommended this be left at zero unless
+ * you are reporting a bug.
+ */
+ override fun setDebugLevel(level: Int) {
+ DEBUGLEVEL = level
+ }
+
+ fun getDebugLevel(): Int {
+ return DEBUGLEVEL
+ }
+
+ /**
+ * Gets the user-visible descriptive name or title of this document.
+ */
+ override fun getName(): String {
+ return if (name != null)
+ name
+ else
+ "Untitled Document"
+ }
+
+ /**
+ * Resets the document state to what it was when it was loaded.
+ *
+ * @throws UnsupportedOperationException if there is not sufficient data
+ * available to perform the reversion
+ */
+ abstract override fun reset()
+
+ /**
+ * Writes the document to the given stream in the requested format.
+ *
+ * @param dest the stream to which the document should be written
+ * @param format the constant representing the desired output format
+ * @throws IllegalArgumentException if the given type code is invalid
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ abstract override fun write(dest: OutputStream, format: Int)
+
+ /**
+ * Writes the document to the given stream in its native format.
+ *
+ * @param dest the stream to which the document should be written
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ override fun write(dest: OutputStream) {
+ this.write(dest, FORMAT_NATIVE)
+ }
+
+ /**
+ * Writes the document to the given file in the requested format.
+ *
+ * @param file the path to which the document should be written
+ * @param format the constant representing the desired output format
+ * @throws IllegalArgumentException if the given type code is invalid
+ * @throws IOException if an error occurs while writing to the file
+ */
+ @Throws(IOException::class)
+ override fun write(file: File, format: Int) {
+ if (format > WorkBookHandle.FORMAT_XLS && this.file != null)
+ OOXMLAdapter.refreshPassThroughFiles(this as WorkBookHandle)
+
+ if (file.exists())
+ file.delete() // try this
+ val stream = BufferedOutputStream(
+ FileOutputStream(file))
+ this.write(stream, format)
+ this.file = file // necesary for OOXML re-write ...
+ stream.flush()
+ stream.close()
+ }
+
+ /**
+ * Writes the document to the given file in its native format.
+ *
+ * @param file the path to which the document should be written
+ * @throws IOException if an error occurs while writing to the stream
+ */
+ @Throws(IOException::class)
+ override fun write(file: File) {
+ this.write(file, FORMAT_NATIVE)
+ }
+
+ /**
+ * Returns a string representation of the object.
+ * This is currently equivalent to [.getName].
+ */
+ override fun toString(): String {
+ return getName()
+ }
+
+ companion object {
+
+ var workingdir = System.getProperty("user.dir") + "/tmp"
+
+ /**
+ * Format constant for the most appropriate format for this document.
+ * If the document was read in from a file, this is usually the format that
+ * was read in.
+ */
+ val FORMAT_NATIVE = 0
+
+ /**
+ * Gets the OpenXLS version number.
+ */
+ val version: String
+ get() = GetInfo.getVersion()
+
+ /**
+ * Looks for magic numbers in the given input data and attempts to parse
+ * it with an appropriate `DocumentHandle` subclass. Detection
+ * is performed on a best-effort basis and is not guaranteed to be accurate.
+ *
+ * @throws IOException if an error occurs while reading from the stream
+ * @throws WorkBookException if parsing fails
+ */
+ @Throws(IOException::class)
+ fun getInstance(input: InputStream): DocumentHandle {
+ val bufferedStream = BufferedInputStream(input)
+ // read in that start of the file for checking magic numbers
+ val headerBytes: ByteArray
+ val count: Int
+ // make sure the file is long enough to get magic numbers
+ bufferedStream.mark(1028)
+ headerBytes = ByteArray(512)
+ count = bufferedStream.read(headerBytes)
+ bufferedStream.reset()
+
+ // if it starts with the LEO magic number check the header
+ if (LEOFile.checkIsLEO(headerBytes, count)) {
+ val leo = LEOFile(bufferedStream)
+
+ return if (leo.hasWorkBook())
+ WorkBookHandle(leo)
+ else
+ throw WorkBookException(
+ "input is LEO but no supported format detected", -1)
+ }
+
+ val headerString: String
+ headerString = String(headerBytes, 0, count, StandardCharsets.UTF_8)
+
+ // if it's a ZIP archive, try parsing as OOXML
+ if (headerString.startsWith("PK")) {
+ return WorkBookHandle(bufferedStream)
+ }
+
+ if (headerString.indexOf(",") > -1 && headerString.indexOf(",") > -1) {
+ // init a blank workbook
+ val book = WorkBookHandle()
+
+ // map CSV into workbook
+ try {
+ val sheet = book.getWorkSheet(0)
+ sheet.readCSV(BufferedReader(
+ InputStreamReader(bufferedStream)))
+ return book
+ } catch (e: Exception) {
+ throw WorkBookException(
+ "Error encountered importing CSV: $e",
+ WorkBookException.ILLEGAL_INIT_ERROR)
+ }
+
+ } else {
+ throw WorkBookException("unknown file format", -1)
+ }
+ }
+
+ /**
+ * Downloads the resource at the given URL to a temporary file.
+ *
+ * @param u the URL representing the resource to be downloaded
+ * @return the path to a temporary file containing the downloaded resource
+ * or `null` if an error occurred
+ */
+ @Deprecated("The download should be handled outside OpenXLS.\n" +
+ " There is no specific replacement for this method.")
+ protected fun getFileFromURL(u: URL): File? {
+ try {
+ val fx = TempFileManager.createTempFile("upload-" + System.currentTimeMillis(), ".tmp")
+
+ val uc = u.openConnection()
+ val contentType = uc.contentType
+ val contentLength = uc.contentLength
+ if (contentType.startsWith("text/") || contentLength == -1) {
+ throw IOException("This is not a binary file.")
+ }
+ val raw = uc.getInputStream()
+ val `in` = BufferedInputStream(raw)
+ val data = ByteArray(contentLength)
+ var bytesRead = 0
+ var offset = 0
+ while (offset < contentLength) {
+ bytesRead = `in`.read(data, offset, data.size - offset)
+ if (bytesRead == -1)
+ break
+ offset += bytesRead
+ }
+ `in`.close()
+
+ if (offset != contentLength) {
+ throw IOException("Only read " + offset
+ + " bytes; Expected " + contentLength + " bytes")
+ }
+
+ // String filename =
+ // u.getFile().substring(filename.lastIndexOf('/') + 1);
+ val out = FileOutputStream(fx)
+ out.write(data)
+ out.flush()
+ out.close()
+ return fx
+ } catch (e: Exception) {
+ Logger.logErr("Could not load WorkBook from URL: $e")
+ return null
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.java b/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.java
deleted file mode 100644
index 06b2dad..0000000
--- a/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-public class DocumentObjectNotFoundException extends Exception {
-
-
- private static final long serialVersionUID = 6605511680058750453L;
-
- public DocumentObjectNotFoundException(String string) {
- super(string);
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.kt b/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.kt
new file mode 100644
index 0000000..1ed7d92
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/DocumentObjectNotFoundException.kt
@@ -0,0 +1,32 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+class DocumentObjectNotFoundException(string: String) : Exception(string) {
+ companion object {
+
+
+ private val serialVersionUID = 6605511680058750453L
+ }
+
+}
diff --git a/src/main/java/io/starter/OpenXLS/ExcelTools.java b/src/main/java/io/starter/OpenXLS/ExcelTools.java
deleted file mode 100644
index 4938574..0000000
--- a/src/main/java/io/starter/OpenXLS/ExcelTools.java
+++ /dev/null
@@ -1,1207 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.text.DecimalFormat;
-//import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.IllegalFormatConversionException;
-import java.util.StringTokenizer;
-
-import io.starter.formats.XLS.Formula;
-import io.starter.formats.XLS.XLSRecord;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.ResourceLoader;
-import io.starter.toolkit.CompatibleBigDecimal;
-import io.starter.toolkit.StringTool;
-
-
-/**
- * OpenXLS helper methods.
- * Contains helpful methods to ease use of the OpenXLS toolkit.
- *
- * "http://starter.io">Starter Inc.
- * @see ByteTools
- */
-
-public class ExcelTools implements java.io.Serializable {
-
- private static final long serialVersionUID = 7622857355626065370L;
-
- /**
- * Formats a double in the standard OpenXLS (General) format. Up to
- * 99999999999 is expressed in standard notation. Above that is formatted in
- * scientific notation
- *
- * In addition, Excel precision of 9 digits is maintained
- *
- *
- * returns a number formatted in Excel's General format, (assuming a wide
- * enough column width - see below) example:
- * formatNumericNotation(1234567890123) returns "1.23457E+12"
- *
- * Information on NOTATION_STANDARD_EXCEL (i.e. Excel's General Format): //
- * Excel will show as many decimal places that the text item has room for,
- * it won't use a thousands separator, and if the // number can't fit, Excel
- * uses a scientific number format. // RULES: // 1- Assuming the column is
- * wide enough numbers will only be displayed in the scientific format when
- * they contain more than 10 digits. // 2- If you enter a number into a cell
- * and thre is not enough room to display all the digits // then the number
- * will either be displayed in scientific format or will not be displayed at
- * all, meaning that ##### will appear. // The exact precision of the
- * scientific format will depend on the width of the actual cell.
- *
- * @param fpnum
- * @return String formatted number
- */
- public static String getNumberAsString(double fpnum) {
- // Ensure precision and number of digits ala Excel
- // double issues - use BigDecimal
- java.math.BigDecimal bd = new java.math.BigDecimal(fpnum);
- int scale = bd.scale();
- if ((Math.abs(fpnum) > 0.000000001) && scale > 9) {
- bd= bd.setScale(9, java.math.RoundingMode.HALF_UP);
- } else if (scale > 9)
- bd= new java.math.BigDecimal(fpnum, new java.math.MathContext(5,java.math.RoundingMode.HALF_UP));
- bd= bd.stripTrailingZeros();
- String s = bd.toPlainString();
- int len = s.length();
- // If larger than 11 characters, truncate string
- if (len > 11 && fpnum > 0 || len > 12) { // must deal with exponents and such as well
- if (scale==0) {
- s= new java.math.BigDecimal(bd.toString(), new java.math.MathContext(6,java.math.RoundingMode.HALF_UP)).toString();
- } else if (bd.toString().indexOf("E")==-1) {
- s= new java.math.BigDecimal(bd.toString(), new java.math.MathContext(10,java.math.RoundingMode.HALF_UP)).toString();
- while (s.length()>0 && s.charAt(s.length()-1)=='0')
- s= s.substring(0, s.length()-1);
- if (s.endsWith("."))
- s= s.substring(0, s.length()-1);
- } else { // 5 + E+XX + sign
- s= new java.math.BigDecimal(bd.toString(), new java.math.MathContext(5,java.math.RoundingMode.HALF_UP)).toString();
- }
- }
- return s;
- }
-
- /**
- * static version of getFormattedStringVal; given an object value, a
- * valid Excel format pattern, return the formatted string value.
- * @param Object o
- * @param String pattern if General or "" returns string value
- * @param boolean isInteger if General pattern, attempt to use integer value (rather than double)
- */
- public static String getFormattedStringVal(Object o, String pattern/*, boolean isInteger*/){
- if (o==null) o= "";
-
- boolean isInteger= false;
- if (o instanceof Integer || (o instanceof Double && ((Double)o).intValue()==((Double)o).doubleValue()))
- isInteger= true;
- else {
- isInteger= false;
- }
-
- if(pattern==null || pattern.equals("")||pattern.equalsIgnoreCase("GENERAL")) {
- if (isInteger)
- return String.valueOf(Double.valueOf(o.toString()).intValue());
- else { // general double numbers have default precision ...
- try {
- double d= new Double(o.toString());
- return ExcelTools.getNumberAsString(Double.valueOf(o.toString())); // handles default precision
- }catch(NumberFormatException e) {
- }
- return o.toString();
- }
- } else if (pattern.equals("000-00-0000")) { // special case for SSN format ... sigh ...
- try {
- new Double(o.toString()); // if it can't be converted to a number, return original string (tis what excel does)
- String s= o.toString();
- while (s.length() < 9) // tis what excel does ...
- s= '0' + s;
- return s.substring(0, 3) + "-" + s.substring(3, 5) + "-" + s.substring(5);
- } catch (Exception e) {
- return o.toString();
- }
- }
-
-
- /** try to determine if the format is numeric (+currency) or date */
- boolean isNumeric= false, isDate= false, isString= false;
-
- /** excel formats can have up to 4 parts: ;;; */
- String[] pats= pattern.split(";"); // assign the correct pattern according to double or string value
-
- String tester= StringTool.convertPatternExtractBracketedExpression(pats[0]);
- if (tester.matches(".*(((y{1,4}|m{1,5}|d{1,4}|h{1,2}|s{1,2}).*)+).*")) {
- isDate= true;
- pats[0]= tester; // ignore locale and other info for dates ...
- }
- if (!isDate)
- {
- int idx= pats.length-1; // default with string
- try{
- double d = new Double(o.toString());
- isNumeric= true;
- if (d > 0) // 1st expression is for + numbers
- idx= 0;
- else if (pats.length > 1 && d < 0) // 2nd is for - numbers
- idx= 1;
- else if (pats.length > 2 && d==0) // 3rd for 0
- idx= 2;
- pattern= StringTool.convertPatternFromExcelToStringFormatter(pats[idx], d < 0); // get correct format for String.format formatter
- } catch (NumberFormatException e) { // 4th for text (non-numeric)
- if (pats.length > 3)
- idx= 3;
- isString= true;
- pattern= StringTool.convertPatternFromExcelToStringFormatter(pats[idx], false); // get correct format for String.format formatter
- }
- } else {
- pattern= pats[0];
- pattern= StringTool.convertDatePatternFromExcelToStringFormatter(pattern); // get correct format for SimpleDateFormat
- }
-
-
- if (isString) { // use string portion of format, if any
- try {
- return String.format(pattern, o);
- } catch (IllegalFormatConversionException e) {
- return o.toString();
- }
- }
- if (isNumeric) {
- try{
- double d = new Double(o.toString());
- if (!Double.isNaN(d)) {
- d= Math.abs(d); // negative number intricacies have been handled in convertPattern method
- // ugly, but has to be done ...
- if (pattern.indexOf("%%")!=-1) // convert to percent
- d*=100;
- // special case of "@" -- integers converted to doubles format incorrectly ...
- if (pattern.equals("%s")) {
- return o.toString();
- }
- return String.format(pattern, d);
- }
- } catch (Exception e) {
- }
- return o.toString();
- }
- if (isDate) {
- try{
- WorkBookHandle.simpledateformat.applyPattern(pattern);
- }catch(Exception ex) {
- return o.toString();
- }
- try {
- return WorkBookHandle.simpledateformat.format(DateConverter.getCalendarFromNumber(o).getTime());
-/*// KSC: TESTING
-Date d= DateConverter.getCalendarFromNumber(o).getTime();
-return WorkBookHandle.simpledateformat.format(d);*/
- } catch (NumberFormatException e) {
- try {
- return WorkBookHandle.simpledateformat.format(new Date(o.toString()).getTime());
- } catch (IllegalArgumentException i) {
- if (o instanceof Number)
- Logger.logWarn("Unable to format date in " + pattern);
- }
- } catch (IllegalArgumentException e) {
- if (o instanceof Number)
- Logger.logWarn("Unable to format date in " + pattern);
- }
- }
- // otherwise
- return o.toString();
- }
-
-
-
-
-
- /**
- * A FAIL FAST implementation for finding whether a cell string address
- * falls within a set of row/col range coordinates.
- *
- * Sep 21, 2010
- *
- * @param rng
- * the range you want to test
- * @param rowFirst
- * in the target range
- * @param rowLast
- * in the target range
- * @param colFirst
- * in the target range
- * @param colLast
- * in the target range
- * @return
- */
- public static boolean isInRange(String rng, int rowFirst, int rowLast,
- int colFirst, int colLast) {
- int[] sh = io.starter.OpenXLS.ExcelTools.getRowColFromString(rng);
-
- // the guantlet
- if (sh[1] < colFirst)
- return false;
- if (sh[1] > colLast)
- return false;
- if (sh[0] < rowFirst)
- return false;
- if (sh[0] > rowLast)
- return false;
-
- return true; // passes!
-
- }
-
- /**
- * returns true if range intersects with range2
- *
- * @param rng
- * @param rc
- * @return
- */
- public static boolean intersects(String rng, int[] rc) {
- int[] rc2 = ExcelTools.getRangeCoords(rng);
- if ((rc[0] >= rc2[0]) && (rc[2] <= rc2[2]) && (rc[1] >= rc2[1])
- && (rc[3] <= rc2[3]))
- return true;
- return false;
- }
-
- /**
- * returns true if address is before the range coordinates defined by rc
- *
- * @param rc
- * row col of address
- * @param rng
- * int[] coordinates as: row0, col0, row1, col1
- * @return true if address is before the range coordinates
- */
- public static boolean isBeforeRange(int[] rc, int[] rng) {
- if (rc[0] < rng[0] || (rc[0] == rng[0] && rc[1] < rng[1]))
- return true;
- return false;
- }
-
- /**
- * returns true if address is before the range coordinates defined by rc
- *
- * @param rc
- * row col of address
- * @param rng
- * int[] coordinates as: row0, col0, row1, col1
- * @return true if address is before the range coordinates
- */
- public static boolean isAfterRange(int[] rc, int[] rng) {
- if (rc[0] > rng[2] || (rc[0] == rng[2] && rc[1] > rng[3]))
- return true;
- return false;
- }
-
- /**
- * Takes an input Object and attempts to convert to numeric Objects of the
- * highest precision possible.
- *
- * This method is useful for avoiding the Excel warnings
- * "Number Stored As Text" when storing string data that contains numbers.
- *
- * NOTE: this method is useful for ensuring that Formula references contain
- * true numeric values as not all String numbers are properly interpreted in
- * Formula engines, and can silently fail.
- *
- * For this reason, always use numeric, non-string values to calculated
- * cells.
- *
- *
- * @param input
- * @return
- */
- public static Object getObject(Object in) {
- // do not record -- only called from other methods
- if (!(in instanceof String)) {
- return in;
- }
-
- String input = String.valueOf(in);
- Object ret = input; // default is the original string
-
- try {
- ret = new Double(input);
- return ret;
- } catch (NumberFormatException ex) {
- try {
- ret = new Float(input);
- return ret;
- } catch (NumberFormatException ex2) {
- try {
- ret = Integer.valueOf(input);
- return ret;
- } catch (NumberFormatException ex3) {
- // ret Is set outside of loop incase no match is ever found.
- }
- }
- }
-
- // list of formatting chars to check for
- String[][] fmtlist = { { "$", "," }, { ",", "," }, { "%", "," } };
-
- // strip the formatting
- for (int t = 0; t < fmtlist.length; t++) {
- if (input.indexOf(fmtlist[t][0]) > -1) { // contains!
- String converted = StringTool.replaceText(input, fmtlist[t][0],
- ""); // strip first token (ie: '$')
- converted = StringTool
- .replaceText(converted, fmtlist[t][1], ""); // strip
- // second
- // token
- // (ie: ',')
- try {
- ret = new Double(converted);
- return ret;
- } catch (NumberFormatException ex) {
- try {
- ret = new Float(converted);
- return ret;
- } catch (NumberFormatException ex2) {
- try {
- ret = Integer.valueOf(converted);
- return ret;
- } catch (NumberFormatException ex3) {
- // ret Is set outside of loop incase no match is
- // ever found.
- }
- }
- }
- }
-
- }
-
- return ret;
- }
-
- /**
- * convert twips to pixels
- *
- *
- * In addition to a calculated size unit derived from the average size of
- * the default characters 0-9, Excel uses the 'twips' measurement which is
- * defined as:
- *
- * 1 twip = 1/20 point or 20 twips = 1 point 1 twip = 1/567 centimeter or
- * 567 twips = 1 centimeter 1 twip = 1/1440 inch or 1440 twips = 1 inch
- *
- *
- * 1 pixel = 0.75 points 1 pixel * 1.3333 = 1 point 1 twip * 20 = 1 point
- *
- * @param pixels
- * @return twips
- */
- public static final float getPixels(float twips) {
- float points = twips / 20;
- float pixels = points * 1.3333333f; // good enuff precision
- return pixels;
- }
-
- /**
- * convert pixels to twips
- *
- *
- * In addition to a calculated size unit derived from the average size of
- * the default characters 0-9, Excel uses the 'twips' measurement which is
- * defined as:
- *
- * 1 pixel = 0.75 points 1 pixel * 1.3333 = 1 point 1 twip * 20 = 1 point
- *
- * @param pixels
- * @return twips
- */
- public static final float getTwips(float pixels) {
- float points = pixels * .75f;
- float twips = points * 20;
- return twips;
- }
-
- /**
- * get recordy byte def as a String
- *
- * public static String getRecordByteDef(XLSRecord rec){ byte[] b =
- * rec.read(); StringBuffer sb = new StringBuffer("byte[] rbytes = {");
- * for(int t = 0;t start time, last time,
- * start mem, last mem
- *
- * @param info
- * @param perfobj
- */
- public static void benchmark(String info, Object perfobj) {
- Runtime rt = Runtime.getRuntime();
- long[] p = null;
- long lasttime = 0l, lastmem = 0l;
- if (System.getProperties().get(perfobj.toString()) != null) {
- p = (long[]) System.getProperties().get(perfobj.toString());
- lasttime = p[1];
- lastmem = p[3];
- p[1] = System.currentTimeMillis();
- p[3] = rt.freeMemory();
- double elapsedsec = p[1] - lasttime;
- double usedmem = lastmem - p[3]; // - lastmem;
- if (usedmem < 0)
- usedmem *= -1;
- Logger.logInfo(getLogDate() + " " + info);
- Logger.logInfo(" time: " + elapsedsec + " millis");
- Logger.logInfo(" mem: " + usedmem + " bytes.");
- } else {
- p = new long[4];
- p[0] = System.currentTimeMillis();
- p[1] = System.currentTimeMillis();
- p[2] = rt.freeMemory();
- p[3] = rt.freeMemory();
- lasttime = p[1];
- lastmem = p[3];
- System.getProperties().put(perfobj.toString(), p);
- }
-
- }
-
- /**
- * get the bytes from a Vector of objects public byte[]
- * getBytesFrom(CompatibleVector objs){
- *
- * for(int t = 0;t 701) { // has 3rd digit
- int z = (i / 676) - 1; // -1 to account for 0-based
- if ((i % 676) < 26) { // then "leftover" is actually 2nd digit
- z--;
- leftover = 676;
- }
- ret = String.valueOf(ExcelTools.alpharr[z]);
- i = i % 676;
- i += leftover;
- }
- if (i > 25) { // has 2nd digit
- int z = (i / 26) - 1; // -1 to account for 0-based
- ret = ret + ExcelTools.alpharr[z];
- i = i % 26;
- }
-
- // bbennett: this raises AIOOB if i = -1. In this situation we don't
- // care about alpha because it will just be in the message of the
- // exception that flags cell as non existent.
- ret += i < 0 ? Integer.toString(i) : String.valueOf(ExcelTools.alpharr[(i)]);
-
- return ret;
- }
-
- /**
- * get the int value of the Excel-style Column alpha representation.
- *
- * @param String
- * column name
- * @return int the 0-based column number
- */
- public static int getIntVal(String c) {
- c = c.toUpperCase();
- if (c.length() > 3) // max col value= XFD in Excel 2007
- return -1;
- int i = c.length() - 1;
- int ret = 0;
- while (i >= 0) { // process least to most-sigificant dig
- int z = 0;
- char cc = c.charAt(i);
- while (z < alpharr.length && cc != alpharr[z++])
- ;
- z *= Math.pow(26, c.length() - i - 1); // 1-based col for computing
- ret += z;
- i--;
- }
- // make 0-based
- ret--;
- return ret;
- }
-
- /**
- * Parses an Excel cell address into row and column integers.
- *
- * @param address
- * the address to parse, either A1 or R1C1
- * @return int[2]: [0] row index, [1] column index
- * @throws IllegalArgumentException
- * if the argument is not a valid address
- */
- public static int[] getRowColFromString(String address) {
-
- if (address.indexOf("$") > -1) {
- address = StringTool.strip(address, "$");
- }
- if (address.indexOf("!") > -1) {
- address = address.substring(address.indexOf("!") + 1);
- }
- if (address.indexOf(":") > -1)
- return getRangeRowCol(address);
-
- char[] adrchars = address.toCharArray();
- int row = 0, col = 0;
- int charpos = -1, numpos = -1;
- boolean r1c1 = false;
- for (int i = 0; i < adrchars.length; i++) {
- if (Character.isDigit(adrchars[i])) {
- if (numpos == -1) // its a number
- numpos = i;
- } else if (charpos == -1) {
- charpos = i;
- if (numpos >= 0) { // we have already set number and we now have
- // a nondigit - R1C1 style
- r1c1 = true;
- // break, it's all over!
- break;
- }
- }
- }
-
- if (r1c1) { // it's a single cell ref
- try {
- // there's an R and a C, not adjacent
- if (address.toUpperCase().indexOf("R") == 0) { // startwith R
- String rx = address.substring(1, address.toUpperCase()
- .indexOf("C"));
- String cx = address.substring(address.toUpperCase()
- .indexOf("C") + 1);
- row = Integer.parseInt(rx);
- col = Integer.parseInt(cx);
- }
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("illegal R1C1 address '"
- + address + "'");
- }
- } else {
- row = 0; // -1 below
- col = -1;
- if (charpos == 0 && numpos > 0) {
- String colval = address.substring(0, numpos);
- col = getIntVal(colval);
- if (col < 0)
- throw new IllegalArgumentException("illegal column value '"
- + colval + "' in address '" + address + "'");
- }
- if (numpos >= 0) {
- row = Integer.parseInt(address.substring(numpos));
- if (row < 1)
- throw new IllegalArgumentException(
- "row may not be negative in address '" + address
- + "'");
- } else { // it's a wholecol ref
- col = getIntVal(address);
- if (col < 0)
- throw new IllegalArgumentException("illegal column value '"
- + address + "' in address '" + address + "'");
- }
- }
-
- int[] ret = { row - 1, col };
- return ret;
- }
-
- /**
- * Parses an Excel cell range and returns the addresses as an int array. The
- * range may not be qualified with sheet names. Strip them with
- * {@link #stripSheetNameFromRange} before calling this method. If the
- * argument is a single cell address it will be returned for both bounds.
- *
- * @param range
- * the range to parse
- * @return int[4]: [0] first row, [1] first column, [2] second row, [3]
- * second column
- * @throws IllegalArgumentException
- * if the addresses are invalid
- */
- public static int[] getRangeRowCol(String range) {
- int colon = range.indexOf(":");
-
- String firstloc;
- String lastloc;
-
- if (colon > -1) {
- firstloc = range.substring(0, colon);
- lastloc = range.substring(colon + 1);
- } else {
- firstloc = range;
- lastloc = range;
- }
-
- int[] result = new int[4];
- int[] temp;
-
- temp = getRowColFromString(firstloc);
- System.arraycopy(temp, 0, result, 0, 2);
-
- temp = getRowColFromString(lastloc);
- System.arraycopy(temp, 0, result, 2, 2);
-
- return result;
- }
-
- /**
- * Takes an int array representing a row and column and formats it as a cell
- * address.
- *
- * The index is zero-based.
- *
- * [0][0] is "A1" [1][1] is "B2" [2][2] is "C3"
- *
- * @param int[] the numeric range to convert
- * @return String the string representation of the range
- */
- public static String formatLocation(int[] rowCol) {
- StringBuffer sb = new StringBuffer(getAlphaVal(rowCol[1]));
- sb.append(String.valueOf(rowCol[0] + 1));
-
- // handle ranges
- if (rowCol.length > 3) {
- // 20090807: KSC: only a range if 1st is != 2nd cell :)
- if (rowCol[0] == rowCol[2] && rowCol[1] == rowCol[3]) // it's a single address
- return sb.toString();
- sb.append(":");
- sb.append(getAlphaVal(rowCol[3]));
- sb.append(String.valueOf(rowCol[2] + 1));
- }
-
- return sb.toString();
- }
-
- /**
- * Takes an int array representing a row and column and formats it as a cell
- * address, taking into account relative or absolute refs
- *
- * The index is zero-based.
- *
- * [0][0] is "A1", $A1, A$1 or $A$1 depending upon bRelRow or bRelCol [1][1]
- * is "B2", $B1, B$1 or B$1 depending upon bRelRow or bRelCol [2][2] is
- * "C3", $C1, C$1 or $C$1 depending upon bRelRow or bRelCol
- *
- * @param int[] the numeric range to convert
- * @param bRelRow
- * if true, no "$"s are added, relative row reference
- * @param bRelCol
- * if true, no "$"s are added, relative col reference
- * @return String the string representation of the range
- */
- public static String formatLocation(int[] s, boolean bRelRow,
- boolean bRelCol) {
- StringBuffer sb = new StringBuffer((bRelCol ? "" : "$"));
- if (s[1] > -1) // account for WholeRow/WholeCol references
- sb.append(getAlphaVal(s[1]));
-
- if (s[0] > -1) // account for WholeRow/WholeCol references
- sb.append((bRelRow ? "" : "$") + String.valueOf(s[0] + 1));
- // 20090906 KSC: handle ranges
- if (s.length > 3) {
- if (s[0] == s[2] && s[1] == s[3]) // it's a single address
- return sb.toString();
- sb.append(":");
- sb.append((bRelCol ? "" : "$"));
- sb.append(getAlphaVal(s[3]));
- sb.append((bRelRow ? "" : "$") + String.valueOf(s[2] + 1));
- }
-
- return sb.toString();
- }
-
- /**
- * Takes an array of four shorts and formats it as a cell range.
- *
- * IE [0][3][1][4] would be "A2:B3"
- *
- * @param int[] the numeric range to convert
- * @return String the string representation of the range
- */
- public static String formatRange(int[] s) {
- if (s.length != 4)
- return "incorrect array size in ExcelTools.formatLocation";
- int[] temp = new int[2];
- temp[0] = s[1];
- temp[1] = s[0];
- String firstcell = formatLocation(temp);
- temp[0] = s[3];
- temp[1] = s[2];
- String lastcell = formatLocation(temp);
- return firstcell + ":" + lastcell;
- }
-
- /**
- * format a range as a string, range in format of [r][c][r1][c1]
- *
- * @param s
- * @return String representation of the integers as a range, ie A1:B4
- */
- public static String formatRangeRowCol(int[] s) {
- if (s.length != 4)
- return "incorrect array size in ExcelTools.formatLocation";
- int[] temp = new int[2];
- temp[0] = s[0];
- temp[1] = s[1];
- String firstcell = formatLocation(temp);
- temp[0] = s[2];
- temp[1] = s[3];
- String lastcell = formatLocation(temp);
- return firstcell + ":" + lastcell;
- }
-
- /**
- * format a range as a string, range in format of [r][c][r1][c1] including
- * relative address state
- *
- *
- * @param s
- * @param bRelAddresses
- * contains relative row and col state for each rcr1c1
- * @return String representation of the integers as a range, ie A1:B4
- */
- public static String formatRangeRowCol(int[] s, boolean[] bRelAddresses) {
- if (s.length != 4)
- return "incorrect array size in ExcelTools.formatLocation";
- int[] temp = new int[2];
- temp[0] = s[0];
- temp[1] = s[1];
- String firstcell = formatLocation(temp, bRelAddresses[0],
- bRelAddresses[1]);
- temp[0] = s[2];
- temp[1] = s[3];
- String lastcell = formatLocation(temp, bRelAddresses[2],
- bRelAddresses[3]);
- // unfortunately, no formatLocation can do this. This is
- // formattingRANGERowCol
- // if (firstcell.equals(lastcell)) return firstcell; // 20090309 KSC:
- return firstcell + ":" + lastcell;
- }
-
- /**
- * Transforms a string to an array of ints for evaluation purposes. For
- * example, acdc == [0][2][3][2]
- */
- public static int[] transformStringToIntVals(String trans) {
- int[] intarr = new int[trans.length()];
- for (int i = 0; i < trans.length(); i++) {
- char c = trans.charAt(i);
- for (int x = 0; x < alpharr.length; x++) {
- if (String.valueOf(c).equalsIgnoreCase(
- String.valueOf(alpharr[x]))) {
- intarr[i] = x;
- }
- }
- }
- return intarr;
- }
-
- /**
- * Formats a string representation of a numeric value as a string in the
- * specified notation:
- *
- * @param int
- * NOTATION_STANDARD = 0,
- * NOTATION_SCIENTIFIC = 1,
- * NOTATION_SCIENTIFIC_EXCEL = 2,
- * EXTENXLS_NOTATION = 3
- *
- *
- * example: formatNumericNotation(1.23456E5, 0) returns a "123456"
- * example: formatNumericNotation(123456, 1) returns "1.23456E5"
- * example: formatNumericNotation(123456, 2) returns "1.23456E+5"
- * example: formatNumericNotation(123456, 3) returns "1.23456E+5"
- */
- public static String formatNumericNotation(String num, int notationType) {
- // if (notationType > 2)return null;
- boolean negative = false;
- if (num.substring(0, 1).equals("-")) {
- negative = true;
- num = num.substring(1, num.length());
- }
- String preString, postString, fullString = "";
- switch (notationType) {
- case 0: // NOTATION_STANDARD
- int i = num.indexOf("E");
- if (i == -1) { // just return
- if (num.substring(num.length() - 2, num.length()).equals(".0")) {
- num = num.substring(0, num.length() - 2);
- }
- if (negative) {
- return "-" + num;
- }
- return num;
- }
- preString = num.substring(0, i);
- CompatibleBigDecimal outNumD = new CompatibleBigDecimal(preString);
- String exp = "";
- if (num.indexOf("+") == -1) {
- exp = num.substring(i + 1, num.length());
- } else {
- exp = num.substring(i + 2, num.length());
- }
- int expNum = Integer.valueOf(exp).intValue();
- outNumD = new CompatibleBigDecimal(outNumD.movePointRight(expNum));
- // outNumD = outNumD.multiply(new CompatibleBigDecimal(Math.pow(10,
- // expNum)));
- // Logger.logInfo(String.valueOf(outNumD));
- // outNum = Math.r
-
- // check if we should be returning a whole number or a decimal
- int moveLen = num.indexOf("E") - num.indexOf(".") - 1;
- if (expNum >= moveLen) {
- if (negative) {
- return "-"
- + String.valueOf(Math.round(outNumD.doubleValue()));
- } else {
- return String.valueOf(Math.round(outNumD.doubleValue()));
- }
- }
- Object[] args = new Object[0];
- // args[0] = outNumD;
- Object res = ResourceLoader.executeIfSupported(outNumD, args,
- "toPlainString");
- if (res != null) {
- fullString = res.toString();
- } else {
- fullString = outNumD.toCompatibleString();
- }
- break;
- case 1: // NOTATION_SCIENTIFIC
- if (num.indexOf("E") != -1 && num.indexOf("+") == -1) {
- fullString = num;
- } else if (num.indexOf("+") != -1) {
- preString = num.substring(0, num.indexOf("+"));
- postString = num.substring(num.indexOf("+") + 1, num.length());
- return preString + postString;
- } else if (num.indexOf(".") != -1) {
- int pos = num.indexOf(".");
- preString = num.substring(0, 1) + "."
- + num.substring(1, num.indexOf("."));
- CompatibleBigDecimal d = new CompatibleBigDecimal(num);
- if (d.doubleValue() < 1 && d.doubleValue() != 0) {
- // it is a very small value, ie 1.0E-10
- int counter = 0;
- while (d.doubleValue() < 1) {
- d = new CompatibleBigDecimal(d.movePointRight(1));
- counter++;
- }
- String retStr = d.toCompatibleString() + "E-" + counter;
- return retStr;
- }
- postString = num.substring(num.indexOf(".") + 1, num.length());
- fullString = preString + postString;
- fullString = fullString + "E" + (pos - 1);
- } else {
- preString = num.substring(0, 1) + ".";
- if (num.length() > 1) {
- preString += num.substring(1, num.length());
- } else {
- preString += "0";
- }
- fullString = preString + "E" + (num.length() - 1);
- }
- break;
- case 2: // NOTATION_SCIENTIFIC_EXCEL
- if (num.indexOf("E") != -1 && num.indexOf("+") != -1) {
- fullString = num;
- } else if (num.indexOf("E") != -1) {
- preString = num.substring(0, num.indexOf("E") + 1);
- postString = "+"
- + num.substring(num.indexOf("E") + 1, num.length());
- fullString = preString + postString;
- } else if (num.indexOf(".") != -1) {
- int pos = num.indexOf(".");
- CompatibleBigDecimal d = new CompatibleBigDecimal(num);
- if (d.doubleValue() < 1 && d.doubleValue() != 0) {
- // it is a very small value, ie 1.0E-10
- int counter = 0;
- while (d.doubleValue() < 1) {
- d = new CompatibleBigDecimal(d.movePointRight(1));
- counter++;
- }
- String retStr = d.toCompatibleString() + "E-" + counter;
- return retStr;
- }
- preString = num.substring(0, 1) + "."
- + num.substring(1, num.indexOf("."));
- postString = num.substring(num.indexOf(".") + 1, num.length());
- fullString = preString + postString;
- fullString = fullString + "E+" + (pos - 1);
- } else {
- preString = num.substring(0, 1) + ".";
- if (num.length() > 1) {
- preString += num.substring(1, num.length());
- } else {
- preString += "0";
- }
- fullString = preString + "E+" + (num.length() - 1);
- }
- break;
- default:
- return num;
- }
- if (negative)
- fullString = "-" + fullString;
- return fullString;
- }
-
- /**
- * Return an array of cell handles specified from the string passed in.
- *
- * Note that a CellHandle cannot exist for an empty cell, so the cells
- * retrieved in this manner will be blank cells, not empty cells.
- *
- * @param cellstr
- * - a comma delimited String representing cells and cell ranges,
- * example "A1,A5,A6,B1:B5" would return cells A1, A5, A6, B1,
- * B2, B3, B4, B5
- * @param sheet
- * the worksheet containing the cells.
- * @return CellHandle[]
- */
- public static CellHandle[] getCellHandlesFromSheet(String strRange,
- WorkSheetHandle sheet) {
- CellHandle[] retCells;
- StringTokenizer cellTokenizer = new StringTokenizer(strRange, ",");
- ArrayList cells = new ArrayList();
- do {
- String element = (String) cellTokenizer.nextElement();
- if (element.indexOf(":") != -1) {
- CellRange aRange = new CellRange(sheet.getSheetName() + "!"
- + strRange, sheet.wbh, true);
- cells.addAll(aRange.getCellList());
- } else {
- CellHandle aCell = null;
- try {
- aCell = sheet.getCell(element);
- } catch (Exception ce) {
- aCell = sheet.add(null, element);
- }
- if (aCell != null)
- cells.add(aCell);
- }
- } while (cellTokenizer.hasMoreElements());
- retCells = new CellHandle[cells.size()];
- retCells = (CellHandle[]) cells.toArray(retCells);
- return retCells;
- }
-
- /**
- * Strip sheet name(s) from range string can be Sheet1!AB:Sheet!BC or
- * Sheet!AB:BC or AB:BC or Sheet1:Sheet2!A1:A2
- *
- * @param address
- * or range String
- * @return 1st sheetname
- *
- * Ok, this is a strange method. It returns a string array of the
- * following format 0 - sheetname1 1 - cell address or range (what
- * if there are 2?) 2 - sheetname2 3 - external link 1 ?? some ooxml
- * record 4 - external link 2
- */
- public static String[] stripSheetNameFromRange(String address) {
- String sheetname = null, sheetname2 = null;
- int m = address.indexOf('!');
- if (m > -1) {
- if (address.substring(0, m).indexOf(":") == -1)
- sheetname = address.substring(0, m);
- else {
- int z = address.indexOf(":");
- sheetname = address.substring(0, z);
- sheetname2 = address.substring(z + 1, m);
- }
- }
- address = address.substring(m + 1);
- int n = address.indexOf('!'); // see if 2nd sheet name exists
- if (n > -1 && !address.equals("#REF!")) {
- m = address.indexOf(':');
- sheetname2 = address.substring(m + 1, n);
- m = address.indexOf(':');
- address = address.substring(0, m + 1) + address.substring(n + 1);
- }
- // 20090323 KSC: handle external references (OOXML-Specific format of
- // [#]SheetName!Ref where # denotes ExternalLink workbook
- String exLink1 = null, exLink2 = null;
- if (sheetname != null && sheetname.indexOf('[') >= 0) { // External
- // OOXML
- // reference
- exLink1 = sheetname.substring(sheetname.indexOf('['));
- exLink1 = exLink1.substring(0, exLink1.indexOf(']') + 1);
- sheetname = StringTool.replaceText(sheetname, exLink1, "");
- if (sheetname.equals(""))
- sheetname = null; // possible to have address in form of =
- // [#]!Name or range
- }
- if (sheetname2 != null && sheetname2.indexOf('[') >= 0) { // External
- // OOXML
- // reference
- exLink2 = sheetname2.substring(sheetname2.indexOf('['));
- exLink2 = exLink2.substring(0, exLink2.indexOf(']') + 1);
- sheetname2 = StringTool.replaceText(sheetname2, exLink2, "");
- if (sheetname2.equals(""))
- sheetname2 = null; // possible to have address in form of =
- // [#]!Name or range
- }
- // return new String[]{sheetname, address, sheetname2};
- return new String[] { sheetname, address, sheetname2, exLink1, exLink2 }; // 20090323
- // KSC:
- // add
- // any
- // external
- // link
- // info
- }
-
- /**
- * return the first and last coords of a range in int form + the number of
- * cells in the range range is in the format of Sheet
- *
- */
- public static int[] getRangeCoords(String range) {
- int numrows = 0;
- int numcols = 0;
- int numcells = 0;
- int[] coords = new int[5];
- String temprange = range;
- // figure out the sheet bounds using the range string
- temprange = ExcelTools.stripSheetNameFromRange(temprange)[1];
- String startcell = "", endcell = "";
- int lastcolon = temprange.lastIndexOf(":");
- endcell = temprange.substring(lastcolon + 1);
- if (lastcolon == -1) // no range
- startcell = endcell;
- else
- startcell = temprange.substring(0, lastcolon);
- startcell = StringTool.strip(startcell, "$");
- endcell = StringTool.strip(endcell, "$");
-
- // get the first cell's coordinates
- int charct = startcell.length();
- while (charct > 0) {
- if (!Character.isDigit(startcell.charAt(--charct))) {
- charct++;
- break;
- }
- }
- String firstcellrowstr = startcell.substring(charct);
- int firstcellrow = -1;
- try {
- firstcellrow = Integer.parseInt(firstcellrowstr);
- } catch (NumberFormatException e) { // could be a whole-col-style ref
- }
- String firstcellcolstr = startcell.substring(0, charct).trim();
- int firstcellcol = ExcelTools.getIntVal(firstcellcolstr);
- // get the last cell's coordinates
- charct = endcell.length();
- while (charct > 0) {
- if (!Character.isDigit(endcell.charAt(--charct))) {
- charct++;
- break;
- }
- }
- String lastcellrowstr = endcell.substring(charct);
- int lastcellrow = -1;
- try {
- lastcellrow = Integer.parseInt(lastcellrowstr);
- } catch (NumberFormatException e) { // could be a whole-col-style ref
- }
- String lastcellcolstr = endcell.substring(0, charct);
- int lastcellcol = ExcelTools.getIntVal(lastcellcolstr);
- numrows = (lastcellrow - firstcellrow) + 1;
- numcols = (lastcellcol - firstcellcol) + 1;
- /*
- * if(numrows == 0)numrows =1; if(numcols == 0)numcols =1;
- */
- numcells = numrows * numcols;
- if (numcells < 0)
- numcells *= -1; // handle swapped cells ie: "B1:A1"
-
- coords[0] = firstcellrow;
- coords[1] = firstcellcol;
- coords[2] = lastcellrow;
- coords[3] = lastcellcol;
- coords[4] = numcells;
- // Trap errors in range
- // if (firstcellrow < 0 || lastcellrow < 0 || firstcellcol < 0 ||
- // lastcellcol < 0)
- // Logger.logErr("ExcelTools.getRangeCoords: Error in Range " + range);
- return coords;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/ExcelTools.kt b/src/main/java/io/starter/OpenXLS/ExcelTools.kt
new file mode 100644
index 0000000..945a4f2
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ExcelTools.kt
@@ -0,0 +1,1210 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.toolkit.CompatibleBigDecimal
+import io.starter.toolkit.Logger
+import io.starter.toolkit.ResourceLoader
+import io.starter.toolkit.StringTool
+
+import java.util.ArrayList
+import java.util.Date
+import java.util.IllegalFormatConversionException
+import java.util.StringTokenizer
+
+//import java.text.SimpleDateFormat;
+
+
+/**
+ * OpenXLS helper methods.
+ * Contains helpful methods to ease use of the OpenXLS toolkit.
+ *
+ *
+ * "http://starter.io">Starter Inc.
+ *
+ * @see ByteTools
+ */
+
+class ExcelTools : java.io.Serializable {
+ companion object {
+
+ private const val serialVersionUID = 7622857355626065370L
+
+ /**
+ * Formats a double in the standard OpenXLS (General) format. Up to
+ * 99999999999 is expressed in standard notation. Above that is formatted in
+ * scientific notation
+ *
+ *
+ * In addition, Excel precision of 9 digits is maintained
+ *
+ *
+ *
+ *
+ * returns a number formatted in Excel's General format, (assuming a wide
+ * enough column width - see below) example:
+ * formatNumericNotation(1234567890123) returns "1.23457E+12"
+ *
+ *
+ * Information on NOTATION_STANDARD_EXCEL (i.e. Excel's General Format): //
+ * Excel will show as many decimal places that the text item has room for,
+ * it won't use a thousands separator, and if the // number can't fit, Excel
+ * uses a scientific number format. // RULES: // 1- Assuming the column is
+ * wide enough numbers will only be displayed in the scientific format when
+ * they contain more than 10 digits. // 2- If you enter a number into a cell
+ * and thre is not enough room to display all the digits // then the number
+ * will either be displayed in scientific format or will not be displayed at
+ * all, meaning that ##### will appear. // The exact precision of the
+ * scientific format will depend on the width of the actual cell.
+ *
+ * @param fpnum
+ * @return String formatted number
+ */
+ fun getNumberAsString(fpnum: Double): String {
+ // Ensure precision and number of digits ala Excel
+ // double issues - use BigDecimal
+ var bd = java.math.BigDecimal(fpnum)
+ val scale = bd.scale()
+ if (Math.abs(fpnum) > 0.000000001 && scale > 9) {
+ bd = bd.setScale(9, java.math.RoundingMode.HALF_UP)
+ } else if (scale > 9)
+ bd = java.math.BigDecimal(fpnum, java.math.MathContext(5, java.math.RoundingMode.HALF_UP))
+ bd = bd.stripTrailingZeros()
+ var s = bd.toPlainString()
+ val len = s.length
+ // If larger than 11 characters, truncate string
+ if (len > 11 && fpnum > 0 || len > 12) { // must deal with exponents and such as well
+ if (scale == 0) {
+ s = java.math.BigDecimal(bd.toString(), java.math.MathContext(6, java.math.RoundingMode.HALF_UP)).toString()
+ } else if (bd.toString().indexOf("E") == -1) {
+ s = java.math.BigDecimal(bd.toString(), java.math.MathContext(10, java.math.RoundingMode.HALF_UP)).toString()
+ while (s.length > 0 && s[s.length - 1] == '0')
+ s = s.substring(0, s.length - 1)
+ if (s.endsWith("."))
+ s = s.substring(0, s.length - 1)
+ } else { // 5 + E+XX + sign
+ s = java.math.BigDecimal(bd.toString(), java.math.MathContext(5, java.math.RoundingMode.HALF_UP)).toString()
+ }
+ }
+ return s
+ }
+
+ /**
+ * static version of getFormattedStringVal; given an object value, a
+ * valid Excel format pattern, return the formatted string value.
+ *
+ * @param Object o
+ * @param String pattern if General or "" returns string value
+ * @param boolean isInteger if General pattern, attempt to use integer value (rather than double)
+ */
+ fun getFormattedStringVal(o: Any?, pattern: String?/*, boolean isInteger*/): String {
+ var o = o
+ var pattern = pattern
+ if (o == null) o = ""
+
+ var isInteger = false
+ isInteger = o is Int || o is Double && o.toInt().toDouble() == o.toDouble()
+
+ if (pattern == null || pattern == "" || pattern.equals("GENERAL", ignoreCase = true)) {
+ if (isInteger)
+ return java.lang.Double.valueOf(o.toString()).toInt().toString()
+ else { // general double numbers have default precision ...
+ try {
+ val d = Double(o.toString())
+ return ExcelTools.getNumberAsString(java.lang.Double.valueOf(o.toString())) // handles default precision
+ } catch (e: NumberFormatException) {
+ }
+
+ return o.toString()
+ }
+ } else if (pattern == "000-00-0000") { // special case for SSN format ... sigh ...
+ try {
+ Double(o.toString()) // if it can't be converted to a number, return original string (tis what excel does)
+ var s = o.toString()
+ while (s.length < 9)
+ // tis what excel does ...
+ s = '0' + s
+ return s.substring(0, 3) + "-" + s.substring(3, 5) + "-" + s.substring(5)
+ } catch (e: Exception) {
+ return o.toString()
+ }
+
+ }
+
+
+ /** try to determine if the format is numeric (+currency) or date */
+ var isNumeric = false
+ var isDate = false
+ var isString = false
+
+ /** excel formats can have up to 4 parts: ;;; */
+ val pats = pattern.split(";".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() // assign the correct pattern according to double or string value
+
+ val tester = StringTool.convertPatternExtractBracketedExpression(pats[0])
+ if (tester.matches(".*(((y{1,4}|m{1,5}|d{1,4}|h{1,2}|s{1,2}).*)+).*".toRegex())) {
+ isDate = true
+ pats[0] = tester // ignore locale and other info for dates ...
+ }
+ if (!isDate) {
+ var idx = pats.size - 1 // default with string
+ try {
+ val d = Double(o.toString())
+ isNumeric = true
+ if (d > 0)
+ // 1st expression is for + numbers
+ idx = 0
+ else if (pats.size > 1 && d < 0)
+ // 2nd is for - numbers
+ idx = 1
+ else if (pats.size > 2 && d == 0.0)
+ // 3rd for 0
+ idx = 2
+ pattern = StringTool.convertPatternFromExcelToStringFormatter(pats[idx], d < 0) // get correct format for String.format formatter
+ } catch (e: NumberFormatException) { // 4th for text (non-numeric)
+ if (pats.size > 3)
+ idx = 3
+ isString = true
+ pattern = StringTool.convertPatternFromExcelToStringFormatter(pats[idx], false) // get correct format for String.format formatter
+ }
+
+ } else {
+ pattern = pats[0]
+ pattern = StringTool.convertDatePatternFromExcelToStringFormatter(pattern!!) // get correct format for SimpleDateFormat
+ }
+
+
+ if (isString) { // use string portion of format, if any
+ try {
+ return String.format(pattern!!, o)
+ } catch (e: IllegalFormatConversionException) {
+ return o.toString()
+ }
+
+ }
+ if (isNumeric) {
+ try {
+ var d = Double(o.toString())
+ if (!java.lang.Double.isNaN(d)) {
+ d = Math.abs(d) // negative number intricacies have been handled in convertPattern method
+ // ugly, but has to be done ...
+ if (pattern!!.indexOf("%%") != -1)
+ // convert to percent
+ d *= 100.0
+ // special case of "@" -- integers converted to doubles format incorrectly ...
+ return if (pattern == "%s") {
+ o.toString()
+ } else String.format(pattern, d)
+ }
+ } catch (e: Exception) {
+ }
+
+ return o.toString()
+ }
+ if (isDate) {
+ try {
+ WorkBookHandle.simpledateformat.applyPattern(pattern!!)
+ } catch (ex: Exception) {
+ return o.toString()
+ }
+
+ try {
+ return WorkBookHandle.simpledateformat.format(DateConverter.getCalendarFromNumber(o).time)
+ /*// KSC: TESTING
+Date d= DateConverter.getCalendarFromNumber(o).getTime();
+return WorkBookHandle.simpledateformat.format(d);*/
+ } catch (e: NumberFormatException) {
+ try {
+ return WorkBookHandle.simpledateformat.format(Date(o.toString()).time)
+ } catch (i: IllegalArgumentException) {
+ if (o is Number)
+ Logger.logWarn("Unable to format date in $pattern")
+ }
+
+ } catch (e: IllegalArgumentException) {
+ if (o is Number)
+ Logger.logWarn("Unable to format date in $pattern")
+ }
+
+ }
+ // otherwise
+ return o.toString()
+ }
+
+
+ /**
+ * A FAIL FAST implementation for finding whether a cell string address
+ * falls within a set of row/col range coordinates.
+ *
+ *
+ * Sep 21, 2010
+ *
+ * @param rng the range you want to test
+ * @param rowFirst in the target range
+ * @param rowLast in the target range
+ * @param colFirst in the target range
+ * @param colLast in the target range
+ * @return
+ */
+ fun isInRange(rng: String, rowFirst: Int, rowLast: Int,
+ colFirst: Int, colLast: Int): Boolean {
+ val sh = io.starter.OpenXLS.ExcelTools.getRowColFromString(rng)
+
+ // the guantlet
+ if (sh[1] < colFirst)
+ return false
+ if (sh[1] > colLast)
+ return false
+ return if (sh[0] < rowFirst) false else sh[0] <= rowLast
+// passes!
+
+ }
+
+ /**
+ * returns true if range intersects with range2
+ *
+ * @param rng
+ * @param rc
+ * @return
+ */
+ fun intersects(rng: String, rc: IntArray): Boolean {
+ val rc2 = ExcelTools.getRangeCoords(rng)
+ return (rc[0] >= rc2[0] && rc[2] <= rc2[2] && rc[1] >= rc2[1]
+ && rc[3] <= rc2[3])
+ }
+
+ /**
+ * returns true if address is before the range coordinates defined by rc
+ *
+ * @param rc row col of address
+ * @param rng int[] coordinates as: row0, col0, row1, col1
+ * @return true if address is before the range coordinates
+ */
+ fun isBeforeRange(rc: IntArray, rng: IntArray): Boolean {
+ return rc[0] < rng[0] || rc[0] == rng[0] && rc[1] < rng[1]
+ }
+
+ /**
+ * returns true if address is before the range coordinates defined by rc
+ *
+ * @param rc row col of address
+ * @param rng int[] coordinates as: row0, col0, row1, col1
+ * @return true if address is before the range coordinates
+ */
+ fun isAfterRange(rc: IntArray, rng: IntArray): Boolean {
+ return rc[0] > rng[2] || rc[0] == rng[2] && rc[1] > rng[3]
+ }
+
+ /**
+ * Takes an input Object and attempts to convert to numeric Objects of the
+ * highest precision possible.
+ *
+ *
+ * This method is useful for avoiding the Excel warnings
+ * "Number Stored As Text" when storing string data that contains numbers.
+ *
+ *
+ * NOTE: this method is useful for ensuring that Formula references contain
+ * true numeric values as not all String numbers are properly interpreted in
+ * Formula engines, and can silently fail.
+ *
+ *
+ * For this reason, always use numeric, non-string values to calculated
+ * cells.
+ *
+ * @param input
+ * @return
+ */
+ fun getObject(`in`: Any): Any {
+ // do not record -- only called from other methods
+ if (`in` !is String) {
+ return `in`
+ }
+
+ val input = `in`.toString()
+ var ret: Any = input // default is the original string
+
+ try {
+ ret = Double(input)
+ return ret
+ } catch (ex: NumberFormatException) {
+ try {
+ ret = Float(input)
+ return ret
+ } catch (ex2: NumberFormatException) {
+ try {
+ ret = Integer.valueOf(input)
+ return ret
+ } catch (ex3: NumberFormatException) {
+ // ret Is set outside of loop incase no match is ever found.
+ }
+
+ }
+
+ }
+
+ // list of formatting chars to check for
+ val fmtlist = arrayOf(arrayOf("$", ","), arrayOf(",", ","), arrayOf("%", ","))
+
+ // strip the formatting
+ for (t in fmtlist.indices) {
+ if (input.indexOf(fmtlist[t][0]) > -1) { // contains!
+ var converted = StringTool.replaceText(input, fmtlist[t][0],
+ "") // strip first token (ie: '$')
+ converted = StringTool
+ .replaceText(converted, fmtlist[t][1], "") // strip
+ // second
+ // token
+ // (ie: ',')
+ try {
+ ret = Double(converted)
+ return ret
+ } catch (ex: NumberFormatException) {
+ try {
+ ret = Float(converted)
+ return ret
+ } catch (ex2: NumberFormatException) {
+ try {
+ ret = Integer.valueOf(converted)
+ return ret
+ } catch (ex3: NumberFormatException) {
+ // ret Is set outside of loop incase no match is
+ // ever found.
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return ret
+ }
+
+ /**
+ * convert twips to pixels
+ *
+ *
+ *
+ *
+ * In addition to a calculated size unit derived from the average size of
+ * the default characters 0-9, Excel uses the 'twips' measurement which is
+ * defined as:
+ *
+ *
+ * 1 twip = 1/20 point or 20 twips = 1 point 1 twip = 1/567 centimeter or
+ * 567 twips = 1 centimeter 1 twip = 1/1440 inch or 1440 twips = 1 inch
+ *
+ *
+ *
+ *
+ * 1 pixel = 0.75 points 1 pixel * 1.3333 = 1 point 1 twip * 20 = 1 point
+ *
+ * @param pixels
+ * @return twips
+ */
+ fun getPixels(twips: Float): Float {
+ val points = twips / 20
+ return points * 1.3333333f
+ }
+
+ /**
+ * convert pixels to twips
+ *
+ *
+ *
+ *
+ * In addition to a calculated size unit derived from the average size of
+ * the default characters 0-9, Excel uses the 'twips' measurement which is
+ * defined as:
+ *
+ *
+ * 1 pixel = 0.75 points 1 pixel * 1.3333 = 1 point 1 twip * 20 = 1 point
+ *
+ * @param pixels
+ * @return twips
+ */
+ fun getTwips(pixels: Float): Float {
+ val points = pixels * .75f
+ return points * 20
+ }
+
+ /**
+ * get recordy byte def as a String
+ *
+ *
+ * public static String getRecordByteDef(XLSRecord rec){ byte[] b =
+ * rec.read(); StringBuffer sb = new StringBuffer("byte[] rbytes = {");
+ * for(int t = 0;t ;t++){
+ *
+ *
+ * Byte thisb = new Byte(b[t]);
+ *
+ *
+ * sb.append(thisb.toString() + ", "); } sb.append("};"); return
+ * sb.toString(); }
+ */
+
+ val logDate: String
+ get() = Date(System.currentTimeMillis()).toString()
+
+ /**
+ * tracks minimal info container for counters -> start time, last time,
+ * start mem, last mem
+ *
+ * @param info
+ * @param perfobj
+ */
+ fun benchmark(info: String, perfobj: Any) {
+ val rt = Runtime.getRuntime()
+ var p: LongArray? = null
+ var lasttime = 0L
+ var lastmem = 0L
+ if (System.getProperties()[perfobj.toString()] != null) {
+ p = System.getProperties()[perfobj.toString()] as LongArray
+ lasttime = p[1]
+ lastmem = p[3]
+ p[1] = System.currentTimeMillis()
+ p[3] = rt.freeMemory()
+ val elapsedsec = (p[1] - lasttime).toDouble()
+ var usedmem = (lastmem - p[3]).toDouble() // - lastmem;
+ if (usedmem < 0)
+ usedmem *= -1.0
+ Logger.logInfo("$logDate $info")
+ Logger.logInfo(" time: $elapsedsec millis")
+ Logger.logInfo(" mem: $usedmem bytes.")
+ } else {
+ p = LongArray(4)
+ p[0] = System.currentTimeMillis()
+ p[1] = System.currentTimeMillis()
+ p[2] = rt.freeMemory()
+ p[3] = rt.freeMemory()
+ lasttime = p[1]
+ lastmem = p[3]
+ System.getProperties()[perfobj.toString()] = p
+ }
+
+ }
+
+ /**
+ * get the bytes from a Vector of objects public byte[]
+ * getBytesFrom(CompatibleVector objs){
+ *
+ *
+ * for(int t = 0;t ();t++){
+ *
+ *
+ * }
+ *
+ *
+ *
+ *
+ * }
+ */
+
+ internal var alpharr = charArrayOf('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
+ /*
+ * NOT USED ANYMORE -- see getAlphaVal -- OK to remove??
+ */
+ val ALPHASDELETE = arrayOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL", "BM", "BN", "BO", "BP", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BX", "BY", "BZ", "CA", "CB", "CC", "CD", "CE", "CF", "CG", "CH", "CI", "CJ", "CK", "CL", "CM", "CN", "CO", "CP", "CQ", "CR", "CS", "CT", "CU", "CV", "CW", "CX", "CY", "CZ", "DA", "DB", "DC", "DD", "DE", "DF", "DG", "DH", "DI", "DJ", "DK", "DL", "DM", "DN", "DO", "DP", "DQ", "DR", "DS", "DT", "DU", "DV", "DW", "DX", "DY", "DZ", "EA", "EB", "EC", "ED", "EE", "EF", "EG", "EH", "EI", "EJ", "EK", "EL", "EM", "EN", "EO", "EP", "EQ", "ER", "ES", "ET", "EU", "EV", "EW", "EX", "EY", "EZ", "FA", "FB", "FC", "FD", "FE", "FF", "FG", "FH", "FI", "FJ", "FK", "FL", "FM", "FN", "FO", "FP", "FQ", "FR", "FS", "FT", "FU", "FV", "FW", "FX", "FY", "FZ", "GA", "GB", "GC", "GD", "GE", "GF", "GG", "GH", "GI", "GJ", "GK", "GL", "GM", "GN", "GO", "GP", "GQ", "GR", "GS", "GT", "GU", "GV", "GW", "GX", "GY", "GZ", "HA", "HB", "HC", "HD", "HE", "HF", "HG", "HH", "HI", "HJ", "HK", "HL", "HM", "HN", "HO", "HP", "HQ", "HR", "HS", "HT", "HU", "HV", "HW", "HX", "HY", "HZ", "IA", "IB", "IC", "ID", "IE", "IF", "IG", "IH", "II", "IJ", "IK", "IL", "IM", "IN", "IO", "IP", "IQ", "IR", "IS", "IT", "IU", "IV", "IW", "IX", "IY", "IZ")
+
+ /**
+ * get the Excel-style Column alphabetical representation of an integer
+ * (0-based).
+ *
+ *
+ * for example: 0 = A 26= AA 701= ZZ 702= AAA 16383= XFD (max)
+ */
+ fun getAlphaVal(i: Int): String {
+ var i = i
+ var ret = ""
+ var leftover = 0
+ if (i > 701) { // has 3rd digit
+ var z = i / 676 - 1 // -1 to account for 0-based
+ if (i % 676 < 26) { // then "leftover" is actually 2nd digit
+ z--
+ leftover = 676
+ }
+ ret = ExcelTools.alpharr[z].toString()
+ i = i % 676
+ i += leftover
+ }
+ if (i > 25) { // has 2nd digit
+ val z = i / 26 - 1 // -1 to account for 0-based
+ ret = ret + ExcelTools.alpharr[z]
+ i = i % 26
+ }
+
+ // bbennett: this raises AIOOB if i = -1. In this situation we don't
+ // care about alpha because it will just be in the message of the
+ // exception that flags cell as non existent.
+ ret += if (i < 0) Integer.toString(i) else ExcelTools.alpharr[i].toString()
+
+ return ret
+ }
+
+ /**
+ * get the int value of the Excel-style Column alpha representation.
+ *
+ * @param String column name
+ * @return int the 0-based column number
+ */
+ fun getIntVal(c: String): Int {
+ var c = c
+ c = c.toUpperCase()
+ if (c.length > 3)
+ // max col value= XFD in Excel 2007
+ return -1
+ var i = c.length - 1
+ var ret = 0
+ while (i >= 0) { // process least to most-sigificant dig
+ var z = 0
+ val cc = c[i]
+ while (z < alpharr.size && cc != alpharr[z++])
+ ;
+ z *= Math.pow(26.0, (c.length - i - 1).toDouble()).toInt() // 1-based col for computing
+ ret += z
+ i--
+ }
+ // make 0-based
+ ret--
+ return ret
+ }
+
+ /**
+ * Parses an Excel cell address into row and column integers.
+ *
+ * @param address the address to parse, either A1 or R1C1
+ * @return int[2]: [0] row index, [1] column index
+ * @throws IllegalArgumentException if the argument is not a valid address
+ */
+ fun getRowColFromString(address: String): IntArray {
+ var address = address
+
+ if (address.indexOf("$") > -1) {
+ address = StringTool.strip(address, "$")
+ }
+ if (address.indexOf("!") > -1) {
+ address = address.substring(address.indexOf("!") + 1)
+ }
+ if (address.indexOf(":") > -1)
+ return getRangeRowCol(address)
+
+ val adrchars = address.toCharArray()
+ var row = 0
+ var col = 0
+ var charpos = -1
+ var numpos = -1
+ var r1c1 = false
+ for (i in adrchars.indices) {
+ if (Character.isDigit(adrchars[i])) {
+ if (numpos == -1)
+ // its a number
+ numpos = i
+ } else if (charpos == -1) {
+ charpos = i
+ if (numpos >= 0) { // we have already set number and we now have
+ // a nondigit - R1C1 style
+ r1c1 = true
+ // break, it's all over!
+ break
+ }
+ }
+ }
+
+ if (r1c1) { // it's a single cell ref
+ try {
+ // there's an R and a C, not adjacent
+ if (address.toUpperCase().indexOf("R") == 0) { // startwith R
+ val rx = address.substring(1, address.toUpperCase()
+ .indexOf("C"))
+ val cx = address.substring(address.toUpperCase()
+ .indexOf("C") + 1)
+ row = Integer.parseInt(rx)
+ col = Integer.parseInt(cx)
+ }
+ } catch (e: NumberFormatException) {
+ throw IllegalArgumentException("illegal R1C1 address '"
+ + address + "'")
+ }
+
+ } else {
+ row = 0 // -1 below
+ col = -1
+ if (charpos == 0 && numpos > 0) {
+ val colval = address.substring(0, numpos)
+ col = getIntVal(colval)
+ if (col < 0)
+ throw IllegalArgumentException("illegal column value '"
+ + colval + "' in address '" + address + "'")
+ }
+ if (numpos >= 0) {
+ row = Integer.parseInt(address.substring(numpos))
+ if (row < 1)
+ throw IllegalArgumentException(
+ "row may not be negative in address '" + address
+ + "'")
+ } else { // it's a wholecol ref
+ col = getIntVal(address)
+ if (col < 0)
+ throw IllegalArgumentException("illegal column value '"
+ + address + "' in address '" + address + "'")
+ }
+ }
+
+ return intArrayOf(row - 1, col)
+ }
+
+ /**
+ * Parses an Excel cell range and returns the addresses as an int array. The
+ * range may not be qualified with sheet names. Strip them with
+ * [.stripSheetNameFromRange] before calling this method. If the
+ * argument is a single cell address it will be returned for both bounds.
+ *
+ * @param range the range to parse
+ * @return int[4]: [0] first row, [1] first column, [2] second row, [3]
+ * second column
+ * @throws IllegalArgumentException if the addresses are invalid
+ */
+ fun getRangeRowCol(range: String): IntArray {
+ val colon = range.indexOf(":")
+
+ val firstloc: String
+ val lastloc: String
+
+ if (colon > -1) {
+ firstloc = range.substring(0, colon)
+ lastloc = range.substring(colon + 1)
+ } else {
+ firstloc = range
+ lastloc = range
+ }
+
+ val result = IntArray(4)
+ var temp: IntArray
+
+ temp = getRowColFromString(firstloc)
+ System.arraycopy(temp, 0, result, 0, 2)
+
+ temp = getRowColFromString(lastloc)
+ System.arraycopy(temp, 0, result, 2, 2)
+
+ return result
+ }
+
+ /**
+ * Takes an int array representing a row and column and formats it as a cell
+ * address.
+ *
+ *
+ * The index is zero-based.
+ *
+ *
+ * [0][0] is "A1" [1][1] is "B2" [2][2] is "C3"
+ *
+ * @param int[] the numeric range to convert
+ * @return String the string representation of the range
+ */
+ fun formatLocation(rowCol: IntArray): String {
+ val sb = StringBuffer(getAlphaVal(rowCol[1]))
+ sb.append(rowCol[0] + 1)
+
+ // handle ranges
+ if (rowCol.size > 3) {
+ // 20090807: KSC: only a range if 1st is != 2nd cell :)
+ if (rowCol[0] == rowCol[2] && rowCol[1] == rowCol[3])
+ // it's a single address
+ return sb.toString()
+ sb.append(":")
+ sb.append(getAlphaVal(rowCol[3]))
+ sb.append(rowCol[2] + 1)
+ }
+
+ return sb.toString()
+ }
+
+ /**
+ * Takes an int array representing a row and column and formats it as a cell
+ * address, taking into account relative or absolute refs
+ *
+ *
+ * The index is zero-based.
+ *
+ *
+ * [0][0] is "A1", $A1, A$1 or $A$1 depending upon bRelRow or bRelCol [1][1]
+ * is "B2", $B1, B$1 or B$1 depending upon bRelRow or bRelCol [2][2] is
+ * "C3", $C1, C$1 or $C$1 depending upon bRelRow or bRelCol
+ *
+ * @param int[] the numeric range to convert
+ * @param bRelRow if true, no "$"s are added, relative row reference
+ * @param bRelCol if true, no "$"s are added, relative col reference
+ * @return String the string representation of the range
+ */
+ fun formatLocation(s: IntArray, bRelRow: Boolean,
+ bRelCol: Boolean): String {
+ val sb = StringBuffer(if (bRelCol) "" else "$")
+ if (s[1] > -1)
+ // account for WholeRow/WholeCol references
+ sb.append(getAlphaVal(s[1]))
+
+ if (s[0] > -1)
+ // account for WholeRow/WholeCol references
+ sb.append((if (bRelRow) "" else "$") + (s[0] + 1))
+ // 20090906 KSC: handle ranges
+ if (s.size > 3) {
+ if (s[0] == s[2] && s[1] == s[3])
+ // it's a single address
+ return sb.toString()
+ sb.append(":")
+ sb.append(if (bRelCol) "" else "$")
+ sb.append(getAlphaVal(s[3]))
+ sb.append((if (bRelRow) "" else "$") + (s[2] + 1))
+ }
+
+ return sb.toString()
+ }
+
+ /**
+ * Takes an array of four shorts and formats it as a cell range.
+ *
+ *
+ * IE [0][3][1][4] would be "A2:B3"
+ *
+ * @param int[] the numeric range to convert
+ * @return String the string representation of the range
+ */
+ fun formatRange(s: IntArray): String {
+ if (s.size != 4)
+ return "incorrect array size in ExcelTools.formatLocation"
+ val temp = IntArray(2)
+ temp[0] = s[1]
+ temp[1] = s[0]
+ val firstcell = formatLocation(temp)
+ temp[0] = s[3]
+ temp[1] = s[2]
+ val lastcell = formatLocation(temp)
+ return "$firstcell:$lastcell"
+ }
+
+ /**
+ * format a range as a string, range in format of [r][c][r1][c1]
+ *
+ * @param s
+ * @return String representation of the integers as a range, ie A1:B4
+ */
+ fun formatRangeRowCol(s: IntArray): String {
+ if (s.size != 4)
+ return "incorrect array size in ExcelTools.formatLocation"
+ val temp = IntArray(2)
+ temp[0] = s[0]
+ temp[1] = s[1]
+ val firstcell = formatLocation(temp)
+ temp[0] = s[2]
+ temp[1] = s[3]
+ val lastcell = formatLocation(temp)
+ return "$firstcell:$lastcell"
+ }
+
+ /**
+ * format a range as a string, range in format of [r][c][r1][c1] including
+ * relative address state
+ *
+ * @param s
+ * @param bRelAddresses contains relative row and col state for each rcr1c1
+ * @return String representation of the integers as a range, ie A1:B4
+ */
+ fun formatRangeRowCol(s: IntArray, bRelAddresses: BooleanArray): String {
+ if (s.size != 4)
+ return "incorrect array size in ExcelTools.formatLocation"
+ val temp = IntArray(2)
+ temp[0] = s[0]
+ temp[1] = s[1]
+ val firstcell = formatLocation(temp, bRelAddresses[0],
+ bRelAddresses[1])
+ temp[0] = s[2]
+ temp[1] = s[3]
+ val lastcell = formatLocation(temp, bRelAddresses[2],
+ bRelAddresses[3])
+ // unfortunately, no formatLocation can do this. This is
+ // formattingRANGERowCol
+ // if (firstcell.equals(lastcell)) return firstcell; // 20090309 KSC:
+ return "$firstcell:$lastcell"
+ }
+
+ /**
+ * Transforms a string to an array of ints for evaluation purposes. For
+ * example, acdc == [0][2][3][2]
+ */
+ fun transformStringToIntVals(trans: String): IntArray {
+ val intarr = IntArray(trans.length)
+ for (i in 0 until trans.length) {
+ val c = trans[i]
+ for (x in alpharr.indices) {
+ if (c.toString().equals(
+ alpharr[x].toString(), ignoreCase = true)) {
+ intarr[i] = x
+ }
+ }
+ }
+ return intarr
+ }
+
+ /**
+ * Formats a string representation of a numeric value as a string in the
+ * specified notation:
+ *
+ * @param int
+ * NOTATION_STANDARD = 0,
+ * NOTATION_SCIENTIFIC = 1,
+ * NOTATION_SCIENTIFIC_EXCEL = 2,
+ * EXTENXLS_NOTATION = 3
+ *
+ *
+ *
+ *
+ * example: formatNumericNotation(1.23456E5, 0) returns a "123456"
+ * example: formatNumericNotation(123456, 1) returns "1.23456E5"
+ * example: formatNumericNotation(123456, 2) returns "1.23456E+5"
+ * example: formatNumericNotation(123456, 3) returns "1.23456E+5"
+ */
+ fun formatNumericNotation(num: String, notationType: Int): String {
+ var num = num
+ // if (notationType > 2)return null;
+ var negative = false
+ if (num.substring(0, 1) == "-") {
+ negative = true
+ num = num.substring(1)
+ }
+ var preString: String
+ val postString: String
+ var fullString: String? = ""
+ when (notationType) {
+ 0 // NOTATION_STANDARD
+ -> {
+ val i = num.indexOf("E")
+ if (i == -1) { // just return
+ if (num.substring(num.length - 2) == ".0") {
+ num = num.substring(0, num.length - 2)
+ }
+ return if (negative) {
+ "-$num"
+ } else num
+ }
+ preString = num.substring(0, i)
+ var outNumD = CompatibleBigDecimal(preString)
+ var exp = ""
+ if (num.indexOf("+") == -1) {
+ exp = num.substring(i + 1)
+ } else {
+ exp = num.substring(i + 2)
+ }
+ val expNum = Integer.valueOf(exp).toInt()
+ outNumD = CompatibleBigDecimal(outNumD.movePointRight(expNum))
+ // outNumD = outNumD.multiply(new CompatibleBigDecimal(Math.pow(10,
+ // expNum)));
+ // Logger.logInfo(String.valueOf(outNumD));
+ // outNum = Math.r
+
+ // check if we should be returning a whole number or a decimal
+ val moveLen = num.indexOf("E") - num.indexOf(".") - 1
+ if (expNum >= moveLen) {
+ return if (negative) {
+ "-" + Math.round(outNumD.toDouble())
+ } else {
+ Math.round(outNumD.toDouble()).toString()
+ }
+ }
+ val args = arrayOfNulls(0)
+ // args[0] = outNumD;
+ val res = ResourceLoader.executeIfSupported(outNumD, args,
+ "toPlainString")
+ if (res != null) {
+ fullString = res.toString()
+ } else {
+ fullString = outNumD.toCompatibleString()
+ }
+ }
+ 1 // NOTATION_SCIENTIFIC
+ -> if (num.indexOf("E") != -1 && num.indexOf("+") == -1) {
+ fullString = num
+ } else if (num.indexOf("+") != -1) {
+ preString = num.substring(0, num.indexOf("+"))
+ postString = num.substring(num.indexOf("+") + 1)
+ return preString + postString
+ } else if (num.indexOf(".") != -1) {
+ val pos = num.indexOf(".")
+ preString = (num.substring(0, 1) + "."
+ + num.substring(1, num.indexOf(".")))
+ var d = CompatibleBigDecimal(num)
+ if (d.toDouble() < 1 && d.toDouble() != 0.0) {
+ // it is a very small value, ie 1.0E-10
+ var counter = 0
+ while (d.toDouble() < 1) {
+ d = CompatibleBigDecimal(d.movePointRight(1))
+ counter++
+ }
+ return d.toCompatibleString() + "E-" + counter
+ }
+ postString = num.substring(num.indexOf(".") + 1)
+ fullString = preString + postString
+ fullString = fullString + "E" + (pos - 1)
+ } else {
+ preString = num.substring(0, 1) + "."
+ if (num.length > 1) {
+ preString += num.substring(1)
+ } else {
+ preString += "0"
+ }
+ fullString = preString + "E" + (num.length - 1)
+ }
+ 2 // NOTATION_SCIENTIFIC_EXCEL
+ -> if (num.indexOf("E") != -1 && num.indexOf("+") != -1) {
+ fullString = num
+ } else if (num.indexOf("E") != -1) {
+ preString = num.substring(0, num.indexOf("E") + 1)
+ postString = "+" + num.substring(num.indexOf("E") + 1)
+ fullString = preString + postString
+ } else if (num.indexOf(".") != -1) {
+ val pos = num.indexOf(".")
+ var d = CompatibleBigDecimal(num)
+ if (d.toDouble() < 1 && d.toDouble() != 0.0) {
+ // it is a very small value, ie 1.0E-10
+ var counter = 0
+ while (d.toDouble() < 1) {
+ d = CompatibleBigDecimal(d.movePointRight(1))
+ counter++
+ }
+ return d.toCompatibleString() + "E-" + counter
+ }
+ preString = (num.substring(0, 1) + "."
+ + num.substring(1, num.indexOf(".")))
+ postString = num.substring(num.indexOf(".") + 1)
+ fullString = preString + postString
+ fullString = fullString + "E+" + (pos - 1)
+ } else {
+ preString = num.substring(0, 1) + "."
+ if (num.length > 1) {
+ preString += num.substring(1)
+ } else {
+ preString += "0"
+ }
+ fullString = preString + "E+" + (num.length - 1)
+ }
+ else -> return num
+ }
+ if (negative)
+ fullString = "-" + fullString!!
+ return fullString
+ }
+
+ /**
+ * Return an array of cell handles specified from the string passed in.
+ *
+ *
+ * Note that a CellHandle cannot exist for an empty cell, so the cells
+ * retrieved in this manner will be blank cells, not empty cells.
+ *
+ * @param cellstr - a comma delimited String representing cells and cell ranges,
+ * example "A1,A5,A6,B1:B5" would return cells A1, A5, A6, B1,
+ * B2, B3, B4, B5
+ * @param sheet the worksheet containing the cells.
+ * @return CellHandle[]
+ */
+ fun getCellHandlesFromSheet(strRange: String,
+ sheet: WorkSheetHandle): Array {
+ var retCells: Array
+ val cellTokenizer = StringTokenizer(strRange, ",")
+ val cells = ArrayList()
+ do {
+ val element = cellTokenizer.nextElement() as String
+ if (element.indexOf(":") != -1) {
+ val aRange = CellRange(sheet.sheetName + "!"
+ + strRange, sheet.workBook, true)
+ cells.addAll(aRange.cellList)
+ } else {
+ var aCell: CellHandle? = null
+ try {
+ aCell = sheet.getCell(element)
+ } catch (ce: Exception) {
+ aCell = sheet.add(null, element)
+ }
+
+ if (aCell != null)
+ cells.add(aCell)
+ }
+ } while (cellTokenizer.hasMoreElements())
+ retCells = arrayOfNulls(cells.size)
+ retCells = cells.toTypedArray()
+ return retCells
+ }
+
+ /**
+ * Strip sheet name(s) from range string can be Sheet1!AB:Sheet!BC or
+ * Sheet!AB:BC or AB:BC or Sheet1:Sheet2!A1:A2
+ *
+ * @param address or range String
+ * @return 1st sheetname
+ *
+ *
+ * Ok, this is a strange method. It returns a string array of the
+ * following format 0 - sheetname1 1 - cell address or range (what
+ * if there are 2?) 2 - sheetname2 3 - external link 1 ?? some ooxml
+ * record 4 - external link 2
+ */
+ fun stripSheetNameFromRange(address: String): Array {
+ var address = address
+ var sheetname: String? = null
+ var sheetname2: String? = null
+ var m = address.indexOf('!')
+ if (m > -1) {
+ if (address.substring(0, m).indexOf(":") == -1)
+ sheetname = address.substring(0, m)
+ else {
+ val z = address.indexOf(":")
+ sheetname = address.substring(0, z)
+ sheetname2 = address.substring(z + 1, m)
+ }
+ }
+ address = address.substring(m + 1)
+ val n = address.indexOf('!') // see if 2nd sheet name exists
+ if (n > -1 && address != "#REF!") {
+ m = address.indexOf(':')
+ sheetname2 = address.substring(m + 1, n)
+ m = address.indexOf(':')
+ address = address.substring(0, m + 1) + address.substring(n + 1)
+ }
+ // 20090323 KSC: handle external references (OOXML-Specific format of
+ // [#]SheetName!Ref where # denotes ExternalLink workbook
+ var exLink1: String? = null
+ var exLink2: String? = null
+ if (sheetname != null && sheetname.indexOf('[') >= 0) { // External
+ // OOXML
+ // reference
+ exLink1 = sheetname.substring(sheetname.indexOf('['))
+ exLink1 = exLink1!!.substring(0, exLink1.indexOf(']') + 1)
+ sheetname = StringTool.replaceText(sheetname, exLink1, "")
+ if (sheetname == "")
+ sheetname = null // possible to have address in form of =
+ // [#]!Name or range
+ }
+ if (sheetname2 != null && sheetname2.indexOf('[') >= 0) { // External
+ // OOXML
+ // reference
+ exLink2 = sheetname2.substring(sheetname2.indexOf('['))
+ exLink2 = exLink2!!.substring(0, exLink2.indexOf(']') + 1)
+ sheetname2 = StringTool.replaceText(sheetname2, exLink2, "")
+ if (sheetname2 == "")
+ sheetname2 = null // possible to have address in form of =
+ // [#]!Name or range
+ }
+ // return new String[]{sheetname, address, sheetname2};
+ return arrayOf(sheetname, address, sheetname2, exLink1, exLink2) // 20090323
+ // KSC:
+ // add
+ // any
+ // external
+ // link
+ // info
+ }
+
+ /**
+ * return the first and last coords of a range in int form + the number of
+ * cells in the range range is in the format of Sheet
+ */
+ fun getRangeCoords(range: String): IntArray {
+ var numrows = 0
+ var numcols = 0
+ var numcells = 0
+ val coords = IntArray(5)
+ var temprange = range
+ // figure out the sheet bounds using the range string
+ temprange = ExcelTools.stripSheetNameFromRange(temprange)[1]
+ var startcell = ""
+ var endcell = ""
+ val lastcolon = temprange.lastIndexOf(":")
+ endcell = temprange.substring(lastcolon + 1)
+ if (lastcolon == -1)
+ // no range
+ startcell = endcell
+ else
+ startcell = temprange.substring(0, lastcolon)
+ startcell = StringTool.strip(startcell, "$")
+ endcell = StringTool.strip(endcell, "$")
+
+ // get the first cell's coordinates
+ var charct = startcell.length
+ while (charct > 0) {
+ if (!Character.isDigit(startcell[--charct])) {
+ charct++
+ break
+ }
+ }
+ val firstcellrowstr = startcell.substring(charct)
+ var firstcellrow = -1
+ try {
+ firstcellrow = Integer.parseInt(firstcellrowstr)
+ } catch (e: NumberFormatException) { // could be a whole-col-style ref
+ }
+
+ val firstcellcolstr = startcell.substring(0, charct).trim({ it <= ' ' })
+ val firstcellcol = ExcelTools.getIntVal(firstcellcolstr)
+ // get the last cell's coordinates
+ charct = endcell.length
+ while (charct > 0) {
+ if (!Character.isDigit(endcell[--charct])) {
+ charct++
+ break
+ }
+ }
+ val lastcellrowstr = endcell.substring(charct)
+ var lastcellrow = -1
+ try {
+ lastcellrow = Integer.parseInt(lastcellrowstr)
+ } catch (e: NumberFormatException) { // could be a whole-col-style ref
+ }
+
+ val lastcellcolstr = endcell.substring(0, charct)
+ val lastcellcol = ExcelTools.getIntVal(lastcellcolstr)
+ numrows = lastcellrow - firstcellrow + 1
+ numcols = lastcellcol - firstcellcol + 1
+ /*
+ * if(numrows == 0)numrows =1; if(numcols == 0)numcols =1;
+ */
+ numcells = numrows * numcols
+ if (numcells < 0)
+ numcells *= -1 // handle swapped cells ie: "B1:A1"
+
+ coords[0] = firstcellrow
+ coords[1] = firstcellcol
+ coords[2] = lastcellrow
+ coords[3] = lastcellcol
+ coords[4] = numcells
+ // Trap errors in range
+ // if (firstcellrow < 0 || lastcellrow < 0 || firstcellcol < 0 ||
+ // lastcellcol < 0)
+ // Logger.logErr("ExcelTools.getRangeCoords: Error in Range " + range);
+ return coords
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/FormatCache.java b/src/main/java/io/starter/OpenXLS/FormatCache.java
deleted file mode 100644
index c85d711..0000000
--- a/src/main/java/io/starter/OpenXLS/FormatCache.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-/**
- * FormatCache.java
- *
- *
- *
- */
-package io.starter.OpenXLS;
-
-import java.util.*;
-import io.starter.toolkit.Logger;
-
-
-/** Handles the caching of the Formats
-
- This class is no longer in use nor needed
- *
- *@deprecated
- */
-// is this a valid class anymore?
-public class FormatCache {
-
- Map, ?> mpx = new java.util.HashMap();
-
- /** Consolidate all identical formats to avoid too many formats errors
- *
- * @deprecated
- */
- public void pack() {
- Iterator> itx = mpx.keySet().iterator();
- while(itx.hasNext()) {
- Object oby = mpx.get(itx.next());
- FormatHandle thisfmt = (FormatHandle)oby;
- thisfmt = this.get(thisfmt);
- }
- }
-
- /**
- * @deprecated
- * @return
- */
- public FormatHandle get(FormatHandle fmx) {
- String fmt = fmx.toString();
- if(!mpx.containsKey(fmt)){
- Logger.logErr("missing in cache: FH " + fmt);
- }
- FormatHandle ret = (FormatHandle)mpx.get(fmt);
- return ret;
- }
-
- /**
- * @deprecated
- * @return
- */
- public Object get(String f) {
- Object myo = mpx.get(f);
- return myo;
- }
-
- /**
- * @deprecated
- * @return
- */
- public int getInt(String f) {
- int findex = -1;
- if(mpx.containsKey(f)) findex = ((Integer)mpx.get(f)).intValue();
- return findex;
- }
-
-}
diff --git a/src/main/java/io/starter/OpenXLS/FormatCache.kt b/src/main/java/io/starter/OpenXLS/FormatCache.kt
new file mode 100644
index 0000000..6675d11
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/FormatCache.kt
@@ -0,0 +1,85 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+/**
+ * FormatCache.java
+ */
+package io.starter.OpenXLS
+
+import io.starter.toolkit.Logger
+
+
+/** Handles the caching of the Formats
+ *
+ * This class is no longer in use nor needed
+ *
+ */
+// is this a valid class anymore?
+@Deprecated("")
+class FormatCache {
+
+ internal var mpx: Map<*, *> = java.util.HashMap()
+
+ /** Consolidate all identical formats to avoid too many formats errors
+ *
+ */
+ @Deprecated("")
+ fun pack() {
+ val itx = mpx.keys.iterator()
+ while (itx.hasNext()) {
+ val oby = mpx.get(itx.next())
+ var thisfmt = oby as FormatHandle
+ thisfmt = this[thisfmt]
+ }
+ }
+
+ /**
+ * @return
+ */
+ @Deprecated(" ")
+ operator fun get(fmx: FormatHandle): FormatHandle {
+ val fmt = fmx.toString()
+ if (!mpx.containsKey(fmt)) {
+ Logger.logErr("missing in cache: FH $fmt")
+ }
+ return mpx.get(fmt) as FormatHandle
+ }
+
+ /**
+ * @return
+ */
+ @Deprecated(" ")
+ operator fun get(f: String): Any {
+ return mpx.get(f)
+ }
+
+ /**
+ * @return
+ */
+ @Deprecated(" ")
+ fun getInt(f: String): Int {
+ var findex = -1
+ if (mpx.containsKey(f)) findex = (mpx.get(f) as Int).toInt()
+ return findex
+ }
+
+}
diff --git a/src/main/java/io/starter/OpenXLS/FormatHandle.java b/src/main/java/io/starter/OpenXLS/FormatHandle.java
deleted file mode 100644
index 9698284..0000000
--- a/src/main/java/io/starter/OpenXLS/FormatHandle.java
+++ /dev/null
@@ -1,2903 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import io.starter.formats.OOXML.Fill;
-import io.starter.formats.XLS.*;
-import io.starter.formats.XLS.WorkBook;
-import io.starter.toolkit.*;
-import java.util.*;
-import java.awt.Color;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Provides methods for querying and changing cell formatting information. Cell
- * formating includes fonts, borders, text alignment, background colors, cell
- * protection (locking), etc.
- *
- * The mutator methods of a FormatHandle object directly and immediately change
- * the formatting of the cell(s) to which it is applied. Under no circumstances
- * will a FormatHandle alter the formatting of cells to which it is not applied.
- * The list of cells to which a FormatHandle applies may be queried with the
- * {@link #getCells} method. Additional cells may be added with {@link #addCell}
- * and related methods.
- *
- * A FormatHandle may also be obtained for a row or a column. In such a case the
- * FormatHandle sets the default formats for the row or column. The default
- * format for a row or column is the format which appears when no other formats
- * for the cell are specified, such as for newly created cells.
- *
- */
-public class FormatHandle implements Handle, FormatConstants {
-
- private CompatibleVector mycells = new CompatibleVector(); // all the Cells sharing this format e.g. CellRange
- private Xf myxf;
- private int xfe;
-// see Xf.usedCount instead private boolean canModify = false;
- private ColHandle mycol = null;
- private RowHandle myrow = null;
- private boolean writeImmediate = false;
- boolean underlined = false;
-
- private io.starter.formats.XLS.WorkBook wkbook;
- private io.starter.OpenXLS.WorkBook wbh;
-
- public static final Map numericFormatMap;
- public static final Map currencyFormatMap;
- public static final Map dateFormatMap;
-
- static {
- Map formats = new HashMap();
- for (String[] formatArr : FormatConstants.NUMERIC_FORMATS) {
- if (formatArr.length == 3) {
- formats.put(formatArr[0].toLowerCase(), formatArr[2]);
- }
- }
- numericFormatMap = Collections.unmodifiableMap(formats);
-
- formats = new HashMap();
- for (String[] formatArr : FormatConstants.CURRENCY_FORMATS) {
- if (formatArr.length == 3) {
- formats.put(formatArr[0].toLowerCase(), formatArr[2]);
- }
- }
- currencyFormatMap = Collections.unmodifiableMap(formats);
-
- formats = new HashMap();
- for (String[] formatArr : FormatConstants.DATE_FORMATS) {
- if (formatArr.length == 3) {
- formats.put(formatArr[0].toLowerCase(), formatArr[2]);
- } else {
- // only 2 elements in date format string array: pattern and hex id
- formats.put(formatArr[0].toLowerCase(), formatArr[0]);
- }
- }
- dateFormatMap = Collections.unmodifiableMap(formats);
- }
-
- /**
- * Nullary constructor for use in bean context. This is not part of the
- * public API and should not be called.
- */
- public FormatHandle() {
- }
-
- /**
- * Constructs a FormatHandle for the given WorkBook and format record.
- * This is not part of the public API and should not be called.
- */
- public FormatHandle(io.starter.OpenXLS.WorkBook book, Xf xfr) {
- myxf = xfr;
- xfe = myxf.getIdx();
- wbh = book;
- if (book != null) {
- wkbook = book.getWorkBook();
- } else {
- if (xfr.getWorkBook() != null) {
- wkbook = xfr.getWorkBook();
- } else {
- Logger.logErr("FormatHandle constructed with null WorkBook.");
- }
- }
- }
-
- /**
- * Constructs a FormatHandle for the given WorkBook's default format.
- */
- public FormatHandle(io.starter.OpenXLS.WorkBook book) {
- this(book, book.getWorkBook().getDefaultIxfe());
- }
-
- /** Constructs a FormatHandle for the given format ID and WorkBook.
- * This is useful for creating a FormatHandle with the same parameters as
- * a cell that does not refer to the cell. For example:
- *
- * CellHandle cell = <get cell here>;
- * FormatHandle format = new FormatHandle(
- * cell.getWorkBook(), cell.getFormatId() );
- *
- *
- * @param book the WorkBook from which the format should be retrieved
- * @param xfnum the ID of the format
- */
- public FormatHandle(io.starter.formats.XLS.WorkBook book, int xfnum) {
- wkbook = book;
- if (xfnum > -1 && xfnum < wkbook.getNumXfs()) {
- myxf = wkbook.getXf(xfnum);
- xfe = myxf.getIdx();
- }
- if (myxf == null) { // add new xf if necessary
- myxf = duplicateXf(null);
- }
- myxf.getFont(); // will set to default (0th) font if not already set
- }
-
- /** Constructs a FormatHandle for the given format ID and WorkBook.
- * This is useful for creating a FormatHandle with the same parameters as
- * a cell that does not refer to the cell. For example:
- *
- * CellHandle cell = <get cell here>;
- * FormatHandle format = new FormatHandle(
- * cell.getWorkBook(), cell.getFormatId() );
- *
- *
- * @param book
- * the WorkBook from which the format should be retrieved
- * @param xfnum
- * the ID of the format public FormatHandle(WorkBook book, int
- * xfnum ,int x) { this(book.getWorkBook(),xfnum); wbh = book; }
- */
-
- /**
- * Constructs a FormatHandle for the given format index and WorkBook.
- * This is not part of the public API and should not be called.
- */
- /*
- * This constructor is just used from XML parsing, due to some dedupe
- * errors. possibly errors in .xlsx too?
- */
- protected FormatHandle(io.starter.OpenXLS.WorkBook book, int xfnum,
- boolean dedupe) {
- this(book, xfnum);
- writeImmediate = dedupe;
- }
-
- /**
- * Constructs a dummy FormatHandle for the given conditional format. This
- * is not part of the public API and should not be called.
- *
- * This unique flavor of FormatHandle is only used to display the formatting
- * values of a Conditional format record.
- *
- * Creates a dummy Xf to store values, otherwise has no effect on the
- * WorkBook record stream which are manipulated through CellHandle.
- *
- * @param book
- * containing the conditional formats
- * @param the
- * index to the conditional format in the book collection
- */
- protected FormatHandle(Condfmt cx, io.starter.OpenXLS.WorkBook book,
- int xfnum, CellHandle c) {
- cx.setFormatHandle(this);
- xfe = xfnum;
- wbh = book;
- wkbook = book.getWorkBook();
- if (c == null) {
- // ok, this is a horrible hack, as its only correct if the top left
- // cell of the range has the same background format
- // as the cell a user is hitting. Lame, but i've been handed this at
- // the last moment and am patching things. weak effort guys.
- try {
- int[] rc = cx.getEncompassingRange();
- c = new CellHandle(cx.getSheet().getCell(rc[0], rc[1]),
- (WorkBookHandle) book);
- } catch (Exception e) {
- }
- ;
- }
- myxf = duplicateXf(book.getWorkBook().getXf(c.getFormatId()));
-
- // set the format from the cf
- List> lx = cx.getRules();
- Iterator> itx = lx.iterator();
- while (itx.hasNext()) {
- Cf format = (Cf) itx.next();
- this.updateFromCF(format, book);
- }
- }
-
- /**
- * updates this format handle via a Cf rule
- *
- * @param cf
- * Cf rule
- * @param book
- * workbook
- */
- protected void updateFromCF(Cf cf, io.starter.OpenXLS.WorkBook book) {
- // border colors
- Color[] clr = cf.getBorderColors();
- if (clr != null)
- setBorderColors(clr);
-
- // line style
- int[] xs = cf.getBorderStyles();
- if (xs != null)
- this.setBorderLineStyle(xs);
-
- /*
- * // cf.getBorderSizes() int[] b = cf.getBorderSizes(); if(b!=null)
- * setBorderLineStyle(b);
- */
- // cf.getFont()
- Font f = cf.getFont();
- if (f != null)
- setFont(f);
- else
- this.setFontHeight(180); // why????????
-
- if (cf.getFontItalic())
- this.setItalic(true);
-
- if (cf.getFontStriken())
- this.setStricken(true);
-
- int fsup = cf.getFontEscapement();
- // super/sub (0 = none, 1 = super, 2 = sub)
- if (fsup > -1)
- this.setScript(fsup);
-
- // handle underlines
- int us = cf.getFontUnderlineStyle();
-
- if (us > -1) {
- this.setUnderlineStyle(us);
- this.setUnderlined(true);
- }
-
- // number cf
- if (cf.getFormatPattern() != null)
- setFormatPattern(cf.getFormatPattern());
-
- if (cf.getFill() != null) {
- this.setFill(cf.getFill());
- } else {
- int fill = cf.getPatternFillStyle(); // Now -1 is a valid entry:
- if (fill > -1) {
- /* If the fill style is solid: When solid is specified, the
- foreground color (fgColor) is the only color rendered,
- even when a background color (bgColor) is also
- specified. */
- int bg = cf.getPatternFillColorBack();
- int fg = cf.getPatternFillColor();
- this.setFill(fill, fg, bg);
- } else {
- int fg = cf.getForegroundColor();
- if (fg > -1)
- setForegroundColor(fg);
- }
- }
- }
-
- /**
- * Creates a FormatHandle for the given cell. This is not part of the
- * public API and should not be called. Customers should use
- * {@link CellHandle#getFormatHandle()} instead.
- */
- public FormatHandle(CellHandle c) {
- wkbook = c.getCell().getWorkBook();
- if (c.getCell().getXfRec() != null) {
- myxf = c.getCell().getXfRec();
- xfe = myxf.getIdx(); // update the pointer - 20071010 KSC
- } else { // ?? create new
- // 20090512 KSC: Shigeo NPE error formaterror646694, create new
- // rather than outputting warning
- // Logger.logWarn("No XF for cell " + c.toString());
- myxf = wkbook.getXf(c.getCell().getIxfe());
- xfe = myxf.getIdx();
- }
- // 20101201 KSC: only add to cache when adding xf's addToCache();
- }
-
- /**
- * overrides the equals method to perform equality based on format
- * properties ------------------------------------------------------------
- *
- * @param Object
- * another - the FormatHandle to compare with this FormatHandle
- * @return true if this FormatHandle equals another
- */
- public boolean equals(Object another) {
- return another.toString().equals(toString());
- }
-
- /**
- * Locks the cell attached to this FormatHandle for editing (makes
- * read-only) lock cell and make read-only
- *
- *
- * @param boolean locked - true if cells should be locked for this
- * FormatHandle
- */
- public void setLocked(boolean locked) {
- Xf xf = cloneXf(myxf);
- xf.setLocked(locked);
- updateXf(xf);
- }
-
- /**
- * sets the cell attached to this FormatHandle to hide or show formula
- * strings;
- *
- * @param boolean b- true if formulas should be hidden for this FormatHandle
- */
- public void setFormulaHidden(boolean b) {
- Xf xf = cloneXf(myxf);
- xf.setFormulaHidden(b);
- updateXf(xf);
- }
-
- /**
- * returns whether this FormatHandle is set to hide formula strings
- *
- * @return true if the formula strings are hidden, false otherwise
- */
- public boolean isFormulaHidden() {
- return myxf.isFormulaHidden();
- }
-
- /**
- * returns whether this Format Handle specifies that cells are locked for
- * changing
- *
- * @return true if cells are locked
- */
- public boolean isLocked() {
- return myxf.isLocked();
- }
-
- /**
- * provides a mapping between Excel formats and Java formats
- * see: http://java.sun.com/docs/books/tutorial/i18n/format
- * /decimalFormat.html
- *
- * Note there are slight Excel-specific differences in the format strings
- * returned. Several numeric and currency formats in excel have different
- * formatting for postive and negative numbers. In these cases, the java
- * format string is split by semicolons and may contain text [Red] which is
- * to specify the negative number should be displayed in red. Remove this
- * from the string before passing into the Format class;
- *
- *
- * G Era designator Text AD
- * y Year Year 1996; 96
- * M Month in year Month July; Jul; 07
- * w Week in year Number 27
- * W Week in month Number 2
- * D Day in year Number 189
- * d Day in month Number 10
- * F Day of week in month Number 2
- * E Day in week Text Tuesday; Tue
- * a Am/pm marker Text PM
- * H Hour in day (0-23) Number 0
- * k Hour in day (1-24) Number 24
- * K Hour in am/pm (0-11) Number 0
- * h Hour in am/pm (1-12) Number 12
- * m Minute in hour Number 30
- * s Second in minute Number 55
- * S Millisecond Number 978
- * z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
- * Z Time zone RFC 822 time zone -0800
- *
- *
- * @return String the formatting pattern for the cell
- */
- public String getJavaFormatString() {
- String pat = getFormatPattern();
- if (pat==null)return null;
-
- // toLowerCase is a simplistic way to implement the case insensitivity
- // of the pattern tokens. It could cause issues with string literals.
- Object patty = convertFormatString(pat.toLowerCase());
- if (patty != null)
- patty = StringTool.qualifyPatternString(patty.toString());
- if (myxf.isDatePattern()) {
- if (patty != null)
- return (String) patty;
- else
- return "M/d/yy h:mm";
- }
- if (patty != null)
- return (String) patty;
- /*
- * If we reached here, we don't have a mapping for this particular
- * format. Send a warning to the system then make sure the pattern we
- * are sending back is valid. Many excel patterns have 4 patterns
- * separated by semicolons. We only can pass 2 into the formatter
- * (positive and negative). This usually works out to be the first two
- * patterns in the string.
- */
- pat = StringTool.qualifyPatternString(pat.toString());
- int firstParens = pat.indexOf(";");
- if (firstParens != -1) {
- int secondParens = pat.indexOf(";", firstParens + 1);
- if (secondParens != -1) {
- pat = pat.substring(0, secondParens);
- } else { // yet another hackaround -jm
- pat = pat.substring(firstParens + 2, pat.length() - 1);
- }
- }
- return pat;
- }
-
- /**
- * converts an Excel-style format string to a Java Format string.
- *
- * @param String
- * pattern - Excel Format String
- * @return String that can be used with the Java Format classes.
- * @see getJavaFormatString
- */
- public static String convertFormatString(String pattern) {
- String ret = (String) numericFormatMap.get(pattern);
- if (ret != null)
- return ret;
- ret = (String) currencyFormatMap.get(pattern);
- if (ret != null)
- return ret;
- ret = (String) dateFormatMap.get(pattern);
- if (ret != null)
- return ret;
- return null;
- }
-
- /*
- * FIXME: Border Issues (marker)
- *
- * The methods to set individual border line styles do not follow a
- * consistent naming convention with the rest of the border methods.
- *
- * There are no methods for getting or setting the inside borders. I don't
- * know whether this is a problem or a design choice. It depends on whether
- * the inside borders are stored in the format record or as separate cell
- * formats.
- *
- * There are no methods to get the diagonal borders. There is a method to
- * set the diagonal border line style, but it affects both diagonals.
- */
-
- /**
- * sets the border color for all borders (top, left, bottom and right) from
- * a Color array
- *
- * NOTE: this setting will affect every cell which refers to this
- * FormatHandle
- *
- * @param java
- * .awt.Color array - 4-element array of desired border colors
- * [T, L, B, R]
- */
- public void setBorderColors(Color[] bordercolors) {
- Xf xf = cloneXf(myxf);
- if (bordercolors[0] != null)
- xf.setTopBorderColor(getColorInt(bordercolors[0]));
- if (bordercolors[1] != null)
- xf.setLeftBorderColor(getColorInt(bordercolors[1]));
- if (bordercolors[2] != null)
- xf.setBottomBorderColor(getColorInt(bordercolors[2]));
- if (bordercolors[3] != null)
- xf.setRightBorderColor(getColorInt(bordercolors[3]));
- updateXf(xf);
- }
-
- /**
- * remove borders for this format
- *
- */
- public void removeBorders() {
- Xf xf = cloneXf(myxf);
- xf.removeBorders();
- updateXf(xf);
- }
-
- /**
- * sets the border color for all borders (top, left, bottom and right) from
- * an int array containing color constants
- *
- *
- * NOTE: this setting will affect every cell which refers to this
- * FormatHandle
- *
- * @param int[] bordercolors - 4-element array of desired border color
- * constants [T, L, B, R]
- * @see FormatHandle.COLOR_* constants
- */
- public void setBorderColors(int[] bordercolors) {
- Xf xf = cloneXf(myxf);
- xf.setTopBorderColor(bordercolors[0]);
- xf.setLeftBorderColor(bordercolors[1]);
- xf.setBottomBorderColor(bordercolors[2]);
- xf.setRightBorderColor(bordercolors[3]);
- updateXf(xf);
-
- }
-
- /**
- * set the border color for all borders (top, left, bottom, and right) to
- * one color via color constant
- *
- *
- * NOTE: this setting will affect every cell which refers to this
- * FormatHandle
- *
- * @param int x - color constant which represents the color to set all
- * border sides
- * @see FormatHandle.COLOR_* constants
- */
- public void setBorderColor(int x) {
- Xf xf = cloneXf(myxf);
- xf.setRightBorderColor((short) x);
- xf.setLeftBorderColor((short) x);
- xf.setTopBorderColor((short) x);
- xf.setBottomBorderColor((short) x);
- updateXf(xf);
-
- }
-
- /**
- * set the border color for all borders (top, left, bottom, and right) to
- * one java.awt.Color
- *
- * NOTE: this setting will affect every cell which refers to this
- * FormatHandle
- *
- * @param Color
- * col - color to set all border sides
- */
- public void setBorderColor(Color col) {
- Xf xf = cloneXf(myxf);
- short x = (short) getColorInt(col);
- xf.setRightBorderColor(x);
- xf.setLeftBorderColor(x);
- xf.setTopBorderColor(x);
- xf.setBottomBorderColor(x);
- updateXf(xf);
-
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderRightColor(int x) {
- Xf xf = cloneXf(myxf);
- xf.setRightBorderColor((short) x);
- updateXf(xf);
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderRightColor(Color x) {
- Xf xf = cloneXf(myxf);
- xf.setRightBorderColor((short) getColorInt(x));
- updateXf(xf);
- }
-
- /**
- * Get the Right border color
- *
- * @return color constant
- */
- public Color getBorderRightColor() {
- if (myxf.getRightBorderLineStyle() == 0)
- return null;
- int x = myxf.getRightBorderColor();
- if (x < this.getWorkBook().colorTable.length)
- return this.getWorkBook().getColorTable()[x];
- else
- return this.getWorkBook().getColorTable()[0]; // black i'm afraid
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderLeftColor(int x) {
- Xf xf = cloneXf(myxf);
- xf.setLeftBorderColor((short) x);
- updateXf(xf);
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderLeftColor(Color x) {
- Xf xf = cloneXf(myxf);
- xf.setLeftBorderColor((short) getColorInt(x));
- updateXf(xf);
- }
-
- /**
- * returns Border Colors of Cell ie: top, left, bottom, right
- *
- * returns null or 1 color for each of 4 sides
- *
- * 1,1,1,1 represents a border all around the cell 1,1,0,0 represents on the
- * top left edge of the cell
- *
- * @return int array representing Cell borders
- */
- public Color[] getBorderColors() {
- Color[] colors = new Color[4];
- colors[0] = getBorderTopColor();
- colors[1] = getBorderLeftColor();
- colors[2] = getBorderBottomColor();
- colors[3] = getBorderRightColor();
- return colors;
- }
-
- /**
- * Get the Left border color
- *
- * @return color constant
- */
- public Color getBorderLeftColor() {
- if (myxf.getLeftBorderLineStyle() == 0)
- return null;
- return this.getWorkBook().getColorTable()[myxf.getLeftBorderColor()];
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderTopColor(int x) {
- Xf xf = cloneXf(myxf);
- xf.setTopBorderColor(x);
- updateXf(xf);
- }
-
- /**
- * Get the Top border color
- *
- * @return color constant
- */
- public Color getBorderTopColor() {
- if (myxf.getTopBorderLineStyle() == 0)
- return null;
- int xt = myxf.getTopBorderColor();
- if (xt > this.getWorkBook().getColorTable().length) // guards
- xt = 0;
- return this.getWorkBook().getColorTable()[xt];
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderTopColor(Color x) {
- Xf xf = cloneXf(myxf);
- xf.setTopBorderColor(getColorInt(x));
- updateXf(xf);
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderBottomColor(int x) {
- Xf xf = cloneXf(myxf);
- xf.setBottomBorderColor(x);
- updateXf(xf);
- }
-
- /**
- * Set the top border color
- *
- * @param color
- * constant
- */
- public void setBorderBottomColor(Color x) {
- Xf xf = cloneXf(myxf);
- xf.setBottomBorderColor(getColorInt(x));
- updateXf(xf);
- }
-
- /**
- * Returns true if the value should be red due to a combination of a format
- * pattern and a negative number
- *
- * @return
- */
- public boolean isRedWhenNegative() {
- String pattern = myxf.getFormatPattern();
- if (pattern.indexOf("Red") > -1)
- return true;
- return false;
- }
-
- /**
- * Get the Right border color
- *
- * @return color constant
- */
- public Color getBorderBottomColor() {
- if (myxf.getBottomBorderLineStyle() == 0)
- return null;
- int x = myxf.getBottomBorderColor();
- if (x < this.getWorkBook().getColorTable().length)
- return this.getWorkBook().getColorTable()[x];
- else
- return this.getWorkBook().getColorTable()[0]; // black i'm afraid
-
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setTopBorderLineStyle(int x) {
- Xf xf = cloneXf(myxf);
- xf.setTopBorderLineStyle((short) x);
- updateXf(xf);
- }
-
- /**
- * Get the border line style
- *
- * @return line style constant
- */
- public int getTopBorderLineStyle() {
- return myxf.getTopBorderLineStyle();
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setBottomBorderLineStyle(int x) {
- Xf xf = cloneXf(myxf);
- xf.setBottomBorderLineStyle((short) x);
- updateXf(xf);
- }
-
- /**
- * Get the border line style
- *
- * @return line style constant
- */
- public int getBottomBorderLineStyle() {
- return myxf.getBottomBorderLineStyle();
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setLeftBorderLineStyle(int x) {
- Xf xf = cloneXf(myxf);
- xf.setLeftBorderLineStyle((short) x);
- updateXf(xf);
- }
-
- /**
- * Get the border line style
- *
- * @return line style constant
- */
- public int getLeftBorderLineStyle() {
- return myxf.getLeftBorderLineStyle();
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setRightBorderLineStyle(int x) {
- Xf xf = cloneXf(myxf);
- xf.setRightBorderLineStyle((short) x);
- updateXf(xf);
- }
-
- /**
- * Get the border line style
- *
- * @return line style constant
- */
- public int getRightBorderLineStyle() {
- return myxf.getRightBorderLineStyle();
- }
-
- /**
- * Sets the border line style using static BORDER_ shorts within
- * FormatHandle
- *
- * @param line
- * style constant
- */
- public void setBorderLineStyle(int x) {
- Xf xf = cloneXf(myxf);
- xf.setBorderLineStyle((short) x);
- updateXf(xf);
- }
-
- /**
- * set border line styles via array of ints representing border styles
- * order= left, right, top, bottom, [diagonal]
- *
- *
- *
- * @param b
- * int[]
- */
- public void setBorderLineStyle(int[] b) {
- myxf.setAllBorderLineStyles(b);
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setBorderLineStyle(short x) {
- Xf xf = cloneXf(myxf);
- xf.setBorderLineStyle(x);
- updateXf(xf);
- }
-
- /**
- * return the 5 border lines styles (l, r, t, b, diag)
- *
- * @return
- */
- public int[] getAllBorderLineStyles() {
- int[] ret = new int[5];
- ret[0] = myxf.getLeftBorderLineStyle();
- ret[1] = myxf.getRightBorderLineStyle();
- ret[2] = myxf.getTopBorderLineStyle();
- ret[3] = myxf.getBottomBorderLineStyle();
- ret[4] = myxf.getDiagBorderLineStyle();
- return ret;
- }
-
- /**
- * return the 5 border line colors (l, r, t, b, diag)
- *
- * @return
- */
- public int[] getAllBorderColors() {
- int[] ret = new int[5];
- ret[0] = myxf.getLeftBorderColor();
- ret[1] = myxf.getRightBorderColor();
- ret[2] = myxf.getTopBorderColor();
- ret[3] = myxf.getBottomBorderColor();
- ret[4] = myxf.getDiagBorderColor();
- return ret;
- }
-
- /**
- * Set the border line style
- *
- * @param line
- * style constant
- */
- public void setBorderDiagonal(int x) {
- Xf xf = cloneXf(myxf);
- xf.setBorderDiag(x);
- updateXf(xf);
- }
-
- /**
- * Set a column handle on this format handle, so all changes applied to this
- * format will be applied to the entire column
- *
- * @param c
- */
- public void setColHandle(ColHandle c) {
- mycol = c;
- }
-
- /**
- * Set a row handle on this format handle, so all changes applied to this
- * format will be applied to the entire row
- *
- * @param c
- */
- public void setRowHandle(RowHandle c) {
- myrow = c;
- }
-
- /**
- * Create a copy of this FormatHandle with its own Xf
- *
- * @return the copied FormatHandle
- */
- public Object clone() {
- FormatHandle ret = null;
- if (wbh == null) { // who knew???
- wkbook = myxf.getWorkBook(); // Changed to myxf since myfont is no
- // longer
- ret = new FormatHandle();
- ret.myxf = myxf;
- ret.xfe = myxf.getIdx();
- ret.wkbook = wkbook;
- } else {
- ret = new FormatHandle(wbh, myxf); // no need to duplicate it - just
- // use all formatting of
- // original xf
- }
-
- return ret;
- }
-
- public String toString() {
- return myxf.toString();
- }
-
- public FormatHandle(io.starter.OpenXLS.WorkBook book, String fontname,
- int fontstyle, int fontsize) {
- this(book);
- setFont(fontname, fontstyle, fontsize);
- }
-
- /**
- * Jan 27, 2011
- *
- * @param workBook
- * @param i
- */
- public FormatHandle(io.starter.OpenXLS.WorkBook workBook, int i) {
- this(workBook.getWorkBook(), i);
- wbh = workBook;
- }
-
- /**
- * /** Set the weight of the font in 1/20 point units 100-1000 range. 400 is
- * normal, 700 is bold.
- *
- * @param wt
- */
- public void setFontWeight(int wt) {
- Font f = cloneFont(myxf.getFont());
- f.setFontWeight(wt);
- updateFont(f);
- }
-
- /**
- * Get the font weight the weight of the font is in 1/20 point units
- *
- * @return
- */
- public int getFontWeight() {
- return myxf.getFont().getFontWeight();
- }
-
- /**
- * Set the Font for this Format.
- *
- * As adding a new Font and format increases the file size, try using this
- * once for each distinct font used in the file, then use 'setFormatId' to
- * share this font with other Cells.
- *
- * Roughly matches the functionality of the java.awt.Font class. Currently
- * the style parameter is only useful for bold/normal weights. Italics,
- * underlines, etc must be modified elsewhere.
- *
- * Note that in order to maintain java.awt.Font compatibility for
- * bold/normal styles, defaults for weight/style have been mapped to 0 =
- * normal (excel 200 weight) and 1 = bold (excel 700 weight)
- *
- * @param String
- * font name
- * @param int font style
- * @param int font size
- */
- public void setFont(Font f) {
- setXFToFont(f);
- }
-
- /**
- * Set new font to XF, handling duplication and caching ...
- *
- * @param Font
- * f
- */
- private void setXFToFont(Font f) {
- int fti = addFontIfNecessary(f);
- if (myxf == null) { // shouldn't!!
- myxf = duplicateXf(null);
- myxf.setFont(fti);
- } else if (myxf.getIfnt() != fti) { // if not using font already,
- // duplicate xf and set to new font
- Xf xf = cloneXf(myxf);
- xf.setFont(fti);
- updateXf(xf);
- }
-
- }
-
- /**
- * Sets this format handle to a font
- * @param fn font name e.g. 'Arial'
- * @param stl font style either Font.PLAIN or Font.BOLD
- * @param sz font size or height in 1/20 point units
- *
- */
- public void setFont(String fn, int stl, double sz) {
- sz *= 20;
- if (stl == 0)
- stl = 200;
- if (stl == 1)
- stl = 700;
- Font f = new Font(fn, stl, (int) sz);
- setXFToFont(f);
- }
-
- /**
- * add font to record streamer if cant find exact font already in there
- * @param f
- * @return
- */
- private int addFontIfNecessary(Font f) {
- if (wkbook == null) {
- Logger.logErr("AddFontIfNecessary: workbook is null");
- return -1;
- }
- int fti = wkbook.getFontIdx(f);
- // don't use the built-ins.
- if (fti == 3)
- fti = 0; // use initial default font instead of last ...
- if (fti == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- fti = wkbook.insertFont(f) + 1;
- } else
- f.setIdx(fti);
- return fti;
- }
-
- /**
- * adds a font to the global font store only if exact font is not already
- * present
- *
- * @param f
- * Font
- * @param bk
- * WorkBookHandle
- */
- public static int addFont(Font f, WorkBookHandle bk) {
- if (bk == null) {
- Logger.logErr("addFont: workbook is null");
- }
- int fti = bk.getWorkBook().getFontIdx(f);
- // if (fti > 3) {// don't use the built-ins.
- if (fti == 3)
- fti = 0; // use initial default font instead of last ... 20070827
- // KSC
- if (fti == -1) { // font doesn't exist yet, add to streamer
- f.setIdx(-1); // flag to insert
- fti = bk.getWorkBook().insertFont(f) + 1;
- } else
- f.setIdx(fti);
- return fti;
- }
-
- /**
- * Adds a font internally to the workbook
- *
- * @param f
- *
- * private void addFont(Font f) {
- *
- * }
- */
-
- /**
- * Apply this Format to a Range of Cells
- *
- * @param CellRange
- * to apply the format to
- */
- public void addCellRange(CellRange cr) {
- CellHandle[] crcells = cr.getCells();
- for (int t = 0; t < crcells.length; t++) {
- addCell(crcells[t]);
- }
- }
-
- /**
- * Apply this Format to a Range of Cells
- *
- * @param CellHandle
- * array to apply the format to
- */
- public void addCellArray(CellHandle[] crcells) {
- for (int t = 0; t < crcells.length; t++) {
- addCell(crcells[t]);
- }
- }
-
- /**
- * add a Cell to this FormatHandle thus applying the Format to the Cell
- *
- * @param CellHandle
- * to apply the format to
- */
- public void addCell(CellHandle c) {
- c.setFormatHandle(this);
- }
-
- /**
- * Add a List of Cells to this FormatHandle
- *
- *
- * @param cx
- */
- public void addCells(List> cx) {
- Iterator> itx = cx.iterator();
- while (itx.hasNext()) {
- addCell((BiffRec) itx.next());
- mycells.add((BiffRec) itx.next());
- }
- }
-
- void addCell(BiffRec c) {
- if (myxf != null) {
- c.setXFRecord(myxf.getIdx());
- } else {
- Logger.logWarn("FormatHandle.addCell() - You MUST call setFont() to initialize the FormatHandle's font before adding Cells.");
- }
- mycells.add(c);
- }
-
- /**
- * Applies the format to a cell without establishing a relationship. The
- * format represented by this FormatHandle will be applied to
- * the cell but it will not be updated with any future changes. If you want
- * that behavior use {@link #addCell(CellHandle) addCell} instead.
- */
- public void stamp(CellHandle cell) {
- cell.setFormatId(xfe);
- }
-
- /** Applies the format to a cell range without establishing a relationship.
- * The format represented by this FormatHandle will be applied
- * to the cells but they will not be updated with any future changes. If you
- * want that behavior use {@link #addCell(CellHandle) addCell} instead.
- */
- public void stamp(CellRange range) {
- try {
- range.setFormatID(xfe);
- } catch (Exception e) {
- // This can't actually happen
- }
- }
-
- /**
- * set the Background Pattern for this Format
- *
- * @param int Excel color constant
- */
- public void setBackgroundPattern(int t) {
- Xf xf = cloneXf(myxf);
- // 20080103 KSC: handle solid (=filled) backgrounds, in which Excel
- // switches fg and bg colors (!!!)
- if (t != FormatConstants.PATTERN_FILLED)
- xf.setPattern(t);
- else {
- int bg = xf.getBackgroundColor();
- xf.setBackgroundSolid();
- xf.setForeColor(bg, null);
- }
- updateXf(xf);
- }
-
- /**
- * returns whether this Format is formatted as a Date
- *
- * @return boolean true if this Format is formatted as a Date
- */
- public boolean isDate() {
- if (myxf == null)
- return false;
- return myxf.isDatePattern();
- }
-
- /**
- * returns whether this Format is formatted as a Currency
- *
- * @return boolean true if this Format is formatted as a currency
- */
- public boolean isCurrency() {
- if (myxf == null)
- return false;
- return myxf.isCurrencyPattern();
- }
-
- /**
- * set the underline style for this font
- *
- * @param int u underline style one of the Font.STYLE_UNDERLINE constants
- *
- */
- public void setUnderlineStyle(int u) {
- Font f = cloneFont(myxf.getFont());
- f.setUnderlineStyle((byte) u);
- updateFont(f);
- }
-
- /**
- * super/sub (0 = none, 1 = super, 2 = sub)
- *
- * @param int script type for Format Font
- */
- public void setScript(int ss) {
- if (ss > 2)
- ss = 2; // deal with invalid numbers
- if (ss < 0)
- ss = 0; // deal with invalid numbers
- myxf.getFont().setScript(ss);
- }
-
- /**
- * set the Font Color for this Format via indexed color constant
- *
- * @param int Excel color constant
- */
- public void setFontColor(int t) {
- Font f = cloneFont(myxf.getFont());
- f.setColor(t);
- updateFont(f);
- }
-
- /**
- * set the Font Color for this Format
- *
- * @param AWT
- * Color color constant
- */
- public void setFontColor(Color colr) {
- Font f = cloneFont(myxf.getFont());
- f.setColor(colr);
- updateFont(f);
- }
-
- /**
- * sets the Font color for this Format via web Hex String
- * @param clr
- */
- public void setFontColor(String clr) {
- Font f = cloneFont(myxf.getFont());
- f.setColor(clr);
- updateFont(f);
- }
-
- /**
- * Get the Font foreground (text) color as a java.awt.Color
- *
- *
- * @return
- */
- public Color getFontColor() {
- return myxf.getFont().getColorAsColor();
- }
-
-
- public String getFontColorAsHex() {
- return myxf.getFont().getColorAsHex();
- }
-
-
- /**
- * set the Foreground Color for this Format NOTE: Foreground color = the
- * CELL BACKGROUND color color for all patterns and Background color= the
- * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
- * color=CELL BACKGROUND color and Background Color=64 (white).
- *
- * @param int Excel color constant
- */
- public void setForegroundColor(int t) {
- Xf xf = cloneXf(myxf);
- xf.setForeColor(t, null);
- updateXf(xf);
- }
-
- /**
- * set the foreground Color for this Format NOTE: Foreground color = the
- * CELL BACKGROUND color color for all patterns and Background color= the
- * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
- * color=CELL BACKGROUND color and Background Color=64 (white).
- *
- * @param AWT
- * Color constant
- */
- public void setForegroundColor(Color colr) {
- Xf xf = cloneXf(myxf);
- int clrz = getColorInt(colr);
- xf.setForeColor(clrz, colr);
- updateXf(xf);
- }
-
- /**
- * set the background color for this Format NOTE: Foreground color = the
- * CELL BACKGROUND color color for all patterns and Background color= the
- * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
- * color=CELL BACKGROUND color and Background Color=64 (white).
- *
- * @param t Excel color constant
- */
- public void setBackgroundColor(int t) {
- Xf xf = cloneXf(myxf);
- if (xf.getFillPattern() == Xf.PATTERN_SOLID)
- xf.setForeColor(t, null);
- else
- xf.setBackColor(t, null);
-
- updateXf(xf);
- }
-
- /**
- * set the Cell Background Color for this Format
- *
- * NOTE: Foreground color = the CELL BACKGROUND color color for all patterns
- * and Background color= the PATTERN color for all patterns != Solid For
- * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
- * Color=64 (white).
- *
- * @param awt
- * Color color constant
- */
- public void setCellBackgroundColor(Color colr) {
- int clrz = getColorInt(colr);
- setCellBackgroundColor(clrz);
-
- }
-
- /**
- * makes the cell a solid pattern background if no pattern was already
- * present NOTE: Foreground color = the CELL BACKGROUND color color for all
- * patterns and Background color= the PATTERN color for all patterns !=
- * Solid For PATTERN_SOLID, Foreground color=CELL BACKGROUND color and
- * Background Color=64 (white).
- *
- * @param int Excel color constant
- */
- public void setCellBackgroundColor(int t) {
- Xf xf = cloneXf(myxf);
-
- if (xf.getFillPattern() == 0)
- xf.setBackgroundSolid();
-
- if (xf.getFillPattern() == Xf.PATTERN_SOLID)
- xf.setForeColor(t, null);
- else
- xf.setBackColor(t, null);
- updateXf(xf);
- }
-
- /**
- * sets this fill pattern from an existing OOXML (2007v) fill element
- *
- * @param f
- */
- protected void setFill(Fill f) {
- Xf xf = cloneXf(myxf);
- xf.setFill(f);
- updateXf(xf);
- }
-
- /**
- * sets the fill for this format handle if fill==Xf.PATTERN_SOLID then fg is
- * the PATTERN color i.e the CELL BG COLOR
- *
- * @param fillpattern
- * @param fg
- * @param bg
- */
- public void setFill(int fillpattern, int fg, int bg) {
- Xf xf = cloneXf(myxf);
-
- xf.setPattern(fillpattern);
-
- /**
- * If the fill style is solid: When solid is specified, the foreground
- * color (fgColor) is the only color rendered, even when a background
- * color (bgColor) is also specified.
- */
- if (xf.getFillPattern() == Xf.PATTERN_SOLID) { // is reversed
- xf.setForeColor(bg, null);
- xf.setBackColor(64, null);
- } else {
- /**
- * or cell fills with patterns specified, then the cell fill color
- * is specified by the bgColor element
- */
- xf.setForeColor(fg, null);
- xf.setBackColor(bg, null);
- }
- updateXf(xf);
- }
-
- /**
- * Get the Pattern Background Color for this Format Pattern
- *
- * @return the Excel color constant
- */
- public int getBackgroundColor() {
- return myxf.getBackgroundColor();
- }
-
- /**
- * get the Pattern Background Color for this Format Pattern as a hex string
- *
- * @return Hex Color String
- *
- */
- public String getBackgroundColorAsHex() {
- return myxf.getBackgroundColorHEX();
- }
-
- /**
- * get the Pattern Background Color for this Format Pattern as an awt.Color
- *
- * @return background Color
- *
- */
- public java.awt.Color getBackgroundColorAsColor() {
- return HexStringToColor(this.getBackgroundColorAsHex());
- }
-
-
- /**
- * returns the foreground color setting regardless of format pattern (which
- * can switch fg and bg)
- *
- * @return
- */
- public int getTrueForegroundColor() {
- return myxf.getForegroundColor(); // 20080814 KSC: getForegroundColor() does the swapping so use base method
- }
-
- /**
- * get the Pattern Background Color for this Formatted Cell
- *
- * This method handles display of conditional formats for the cell
- *
- * checks for conditional format, then applies it if conditions are true.
- *
- * @return the Excel color constant
- */
- public int getCellBackgroundColor() {
- int fp = getFillPattern();
-
- if (fp == Xf.PATTERN_SOLID)
- return myxf.getForegroundColor(); // this.getForegroundColor() does
- // the swapping so use base
- // method
- else
- return myxf.getBackgroundColor();
- }
-
- /**
- * get the Pattern Background Color for this Format as a Hex Color String
- *
- * @return Hex Color String
- */
- public String getCellBackgroundColorAsHex() {
- int fp = getFillPattern();
-
- if (fp == Xf.PATTERN_SOLID)
- return myxf.getForegroundColorHEX(); // this.getForegroundColor() does
- else
- return myxf.getBackgroundColorHEX();
- }
-
- /**
- * get the Pattern Background Color for this Format as an awt.Color
- *
- * @return cell background color
- */
- public java.awt.Color getCellBackgroundColorAsColor() {
- return HexStringToColor(this.getCellBackgroundColorAsHex());
- }
-
- /**
- * get the Background Color for this Format NOTE: Foreground color = the
- * CELL BACKGROUND color color for all patterns and Background color= the
- * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
- * color=CELL BACKGROUND color and Background Color=64 (white).
- *
- * @return the Excel color constant
- */
- public int getForegroundColor() {
- // if it's SOLID pattern, fg/bg are swapped
- if (getFillPattern() == Xf.PATTERN_SOLID)
- return myxf.getBackgroundColor();
-
- return myxf.getForegroundColor();
- }
-
- /**
- * get the Background Color for this Format as a Hex Color String NOTE:
- * Foreground color = the CELL BACKGROUND color color for all patterns and
- * Background color= the PATTERN color for all patterns != Solid For
- * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
- * Color=64 (white).
- *
- * @return Hex Color String
- */
- public String getForegroundColorAsHex() {
- if (getFillPattern() == Xf.PATTERN_SOLID) // if it's SOLID pattern,
- return myxf.getBackgroundColorHEX();
-
- return myxf.getForegroundColorHEX();
- }
-
- /**
- * get the Background Color for this Format as a Color NOTE:
- * Foreground color = the CELL BACKGROUND color color for all patterns and
- * Background color= the PATTERN color for all patterns != Solid For
- * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
- * Color=64 (white).
- *
- * @return Hex Color String
- */
- public Color getForegroundColorAsColor() {
- return HexStringToColor(this.getForegroundColorAsHex());
- }
-
- /**
- * set the Background Color for this Format NOTE: Foreground color = the
- * CELL BACKGROUND color color for all patterns and Background color= the
- * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
- * color=CELL BACKGROUND color and Background Color=64 (white).
- *
- * @param awt
- * Color color constant
- */
- public void setBackgroundColor(Color colr) {
- Xf xf = cloneXf(myxf);
- int clrz = getColorInt(colr);
- xf.setBackColor(clrz, colr);
- updateXf(xf);
- }
-
- /**
- * Set the format handle to use standard bold text
- *
- * @param boolean isBold
- */
- public void setBold(boolean isBold) {
- Font f = cloneFont(myxf.getFont());
- f.setBold(isBold);
- updateFont(f);
- }
-
- /**
- * Get if this format is bold or not
- *
- * @return boolean whether the cell font format is bold
- */
- public boolean getIsBold() {
- return myxf.getFont().getIsBold();
- }
-
- /**
- * Return an int representing the underline style
- *
- * These map to the STYLE_UNDERLINE static integers *
- *
- * @return int underline style
- */
- public int getUnderlineStyle() {
- return myxf.getFont().getUnderlineStyle();
- }
-
- /**
- * Get the font height in points
- *
- * @return font height
- */
- public double getFontHeightInPoints() {
- return getFont().getFontHeightInPoints();
- }
-
- /**
- * Returns the Font's height in 1/20th point increment
- *
- * @return font height
- */
- public int getFontHeight() {
- return getFont().getFontHeight();
- }
-
- /**
- * Set the Font's height in 1/20th point increment
- *
- * @param new font height
- */
- public void setFontHeight(int fontHeight) {
- Font f = cloneFont(myxf.getFont());
- f.setFontHeight(fontHeight);
- updateFont(f);
- }
-
- /**
- * Returns the Font's name
- *
- * @return font name
- */
- public String getFontName() {
- return getFont().getFontName();
- }
-
- /**
- * Set the Font's name
- *
- * To be valid, this font name must be available on the client system.
- *
- * @param font
- * name
- */
- public void setFontName(String fontName) {
- Font f = cloneFont(myxf.getFont());
- f.setFontName(fontName);
- updateFont(f);
- }
-
- /**
- * Determine if the format handle refers to a font stricken out
- *
- * @return boolean representing if the FormatHandle is striking out a cell.
- */
- public boolean getStricken() {
- if (myxf.getFont() == null)
- return false;
- return myxf.getFont().getStricken();
- }
-
- /**
- * Set if the format handle is stricken out
- *
- * @param isStricken
- * boolean representing if the formatted cell should be stricken
- * out.
- */
- public void setStricken(boolean isStricken) {
- Font f = cloneFont(myxf.getFont());
- f.setStricken(isStricken);
- updateFont(f);
- }
-
- /**
- * Get if the font is italic
- *
- * @return boolean representing if the formatted cell is italic.
- */
- public boolean getItalic() {
- if (myxf.getFont() == null)
- return false;
- return myxf.getFont().getItalic();
- }
-
- /**
- * Set if the font is italic
- *
- * @param isItalic
- * boolean representing if the formatted cell should be italic.
- */
- public void setItalic(boolean isItalic) {
- Font f = cloneFont(myxf.getFont());
- f.setItalic(isItalic);
- updateFont(f);
- }
-
- /**
- * Get if the font is underlined
- *
- * @return boolean representing if the formatted cell is underlined.
- */
- public boolean getUnderlined() {
- if (myxf.getFont() == null)
- return underlined;
- return myxf.getFont().getUnderlined();
- }
-
- /**
- * Set underline attribute on the font
- *
- *
- * @param isUnderlined
- * boolean representing if the formatted cell should be
- * underlined
- */
- public void setUnderlined(boolean isUnderlined) {
- Font f = cloneFont(myxf.getFont());
- f.setUnderlined(isUnderlined);
- updateFont(f);
-
- }
-
- /**
- * Get if the font is bold
- *
- * @return boolean representing if the formatted cell is bold
- */
- public boolean getBold() {
- return myxf.getFont().getBold();
- }
-
- /**
- * returns the existing font record for this Format
- *
- * Font is an internal record and should not be accessed by end users
- *
- * @return the XLS Font record associated with this Format
- */
- public io.starter.formats.XLS.Font getFont() {
- // should this be a protected method?
- if (myxf != null) // shouldn't!
- return myxf.getFont();
- return null;
- }
-
- /**
- * Sets the number format pattern for this format. All Excel built-in number
- * formats are supported. Custom formats will not be applied by OpenXLS
- * (e.g. {@link CellHandle#getFormattedStringVal}) but they will be written
- * correctly to the output file. For more information on number format
- * patterns see Microsoft
- * KB264372 .
- *
- * @param pat
- * the Excel number format pattern to apply
- * @see FormatConstantsImpl#getBuiltinFormats
- */
- public void setFormatPattern(String pat) {
- Xf xf = cloneXf(myxf);
- xf.setFormatPattern(pat);
- updateXf(xf);
- }
-
- public void setPattern(int pat) {
- Xf xf = cloneXf(myxf);
- xf.setPattern(pat);
- updateXf(xf);
- }
-
- /**
- * The format ID allows setting of the format for a Cell without adding it
- * to the Format's Cell Collection.
- *
- * Use to decrease memory requirements when dealing with large collections
- * of cells.
- *
- * Usage:
- *
- * mycell.setFormatId(myformat.getFormatId());
- *
- * @return the format ID for this Format
- */
- public int getFormatId() {
- return xfe;
- }
-
- /**
- * Gets the number format pattern for this format, if set. For more
- * information on number format patterns see Microsoft KB264372 .
- *
- * @return the Excel number format pattern for this cell or
- * null if none is applied
- */
- public String getFormatPattern() {
- return myxf.getFormatPattern();
- }
-
- /**
- * get the fill pattern for this format
- *
- */
- public int getFillPattern() {
- return myxf.getFillPattern();
- }
-
- /**
- * returns the index of the Color within the Colortable
- *
- *
- * @param the
- * index of the color in the colortable
- * @return the color
- */
- public static Color getColor(int col) {
- if (col > -1 && col < FormatHandle.COLORTABLE.length)
- return FormatHandle.COLORTABLE[col];
- return FormatHandle.COLORTABLE[0];
- }
-
- /**
- * returns the index of the Color within the Colortable
- *
- * @param col
- * the color
- * @return the index of the color in the colortable
- */
- public static int getColorInt(Color col) {
- for (int i = 0; i < FormatHandle.COLORTABLE.length; i++) {
- if (col.equals(FormatHandle.COLORTABLE[i])) {
- return i;
- }
- }
- int R = col.getRed();
- int G = col.getGreen();
- int B = col.getBlue();
- int colorMatch = -1;
- double colorDiff = Integer.MAX_VALUE;
- for (int i = 0; i < FormatHandle.COLORTABLE.length; i++) {
- double curDif=
- Math.pow(R-FormatHandle.COLORTABLE[i].getRed(), 2)
- + Math.pow(G - FormatHandle.COLORTABLE[i].getGreen(), 2)
- + Math.pow(B - FormatHandle.COLORTABLE[i].getBlue(), 2);
- if (curDif < colorDiff) {
- colorDiff = curDif;
- colorMatch = i;
- }
- }
- return colorMatch;
- }
-
- /**
- * Sets the internal format to the FormatHandle. For internal use only, not
- * supported.
- */
- public void setXf(Xf xrec) {
- myxf = xrec;
- }
-
- /**
- * Set the horizontal alignment for this FormatHandle
- *
- * @param align
- * - an int representing the alignment. Please review the
- * FormatHandle.ALIGN*** static int's
- */
- public void setHorizontalAlignment(int align) {
- Xf xf = cloneXf(myxf);
- xf.setHorizontalAlignment(align);
- updateXf(xf);
- }
-
- /**
- * Returns an int representing the current horizontal alignment in this
- * FormatHandle. These values are mapped to the FormatHandle.ALIGN*** static
- * int's
- */
- public int getHorizontalAlignment() {
- return myxf.getHorizontalAlignment();
- }
-
- /**
- * set indent (1= 3 spaces)
- * @param indent
- */
- public void setIndent(int indent) {
- Xf xf = cloneXf(myxf);
- xf.setIndent(indent);
- updateXf(xf);
- }
-
- /**
- * increase or decrease the precision of this numeric or curerncy format pattern
- * If the format pattern is "General", converts to a basic number pattern
- * If the precision is already 0 and !increase, this method does nothing
- * @param increase true if increase the precsion (number of decimals to display)
- */
- public void adjustPrecision(boolean increase) {
- // TODO: if decimal is contained within quotes ...
- String pat = getFormatPattern();
- if (pat.equals("General") && increase) {
- pat= "0.0"; // the most basic numeric pattern
- this.setFormatPattern(pat);
- return;
- }
-
- try {
- // split pattern and deal with positive, negative, zero and text separately
- // for each, find decimal place and increment/decrement; if not found, find last digit placeholder
- String[] pats= pat.split(";");
- String newPat= "";
- for (int i= 0; i < pats.length; i++) {
- if (i > 0) newPat+=';';
- int z= pats[i].indexOf('.'); // position of decimal
- boolean foundit= false;
- if (z!=-1) { // found decimal place
- z++;
- for (; z < pats[i].length(); z++) {
- char c= pats[i].charAt(z);
- if ((c=='0' || c=='#' || c=='?')) // numeric placeholders
- foundit= true;
- else if (foundit && !(c=='0' || c=='#' || c=='?')) // numeric placeholders. if hit last one, either inc or dec
- break;
- }
- if (increase)
- newPat+= new StringBuffer(pats[i]).insert(z, "0").toString(); //pats[i].substring(0, z) + "0" + pats[i].substring(z+1);
- else {
- if (pats[i].charAt(z-2)!='.') {
- newPat+= new StringBuffer(pats[i]).deleteCharAt(z-1).toString(); // .pats[i].substring(0, z-1) + pats[i].substring(z+1);
- } else {
- newPat+= new StringBuffer(pats[i]).delete(z-2, z).toString();
- }
- }
-
- } else if (increase) { // no decimal yet. If decrease, ignore. if increase, add
- z= pats[i].length()-1;
- for (; z >= 0; z--) {
- char c= pats[i].charAt(z);
- if ((c=='0' || c=='#' || c=='?')) { // found last numeric placeholder
- foundit= true;
- break;
- }
- }
- if (foundit) // if had ANY numeric placeholders
- newPat+= new StringBuffer(pats[i]).insert(z+1, ".0").toString(); //pats[i].substring(0, z) + ".0" + pats[i].substring(z+1);
- else
- newPat+= pats[i]; // keep original
- } else // if decrease and no decimal found, leave alone
- newPat+= pats[i]; // leave alone
- }
-
- //io.starter.OpenXLS.util.Logger.log("Old Style" + pat + ". New Style: " + newPat + ". Increase?" + (increase?"yes":"no")); // KSC: TESETING: TAKE OUT WHEN DONE
- this.setFormatPattern(newPat);
- } catch (Exception e) {
- Logger.logErr("Error setting style"); // KSC: TESETING: TAKE OUT WHEN DONE
- }
- }
-
- /**
- * return indent (1 = 3 spaces)
- *
- * @return
- */
- public int getIndent() {
- return myxf.getIndent();
- }
-
- /**
- * sets the Right to Left Text Direction or reading order of this style
- * @param rtl possible values:
- * 0=Context Dependent
- * 1=Left-to-Right
- * 2=Right-to-Let
- *
- * @param rtl
- * possible values:
- * 0=Context Dependent
- * 1=Left-to-Right
- * 2=Right-to-Let
- *
- */
- public void setRightToLeftReadingOrder(int rtl) {
- Xf xf = cloneXf(myxf);
- xf.setRightToLeftReadingOrder(rtl);
- updateXf(xf);
- }
-
- /**
- * returns true if this style is set to Right-to-Left text direction
- * (reading order)
- *
- * @return
- */
- public int getRightToLetReadingOrder() {
- return myxf.getRightToLeftReadingOrder();
- }
-
- /**
- * Set the Vertical alignment for this FormatHandle
- *
- * @param align
- * - an int representing the alignment. Please review the
- * FormatHandle.ALIGN*** static int's
- */
- public void setVerticalAlignment(int align) {
- Xf xf = cloneXf(myxf);
- xf.setVerticalAlignment(align);
- updateXf(xf);
- }
-
- /**
- * Returns an int representing the current Vertical alignment in this
- * FormatHandle. These values are mapped to the FormatHandle.ALIGN*** static
- * int's
- */
- public int getVerticalAlignment() {
- return myxf.getVerticalAlignment();
- }
-
- /**
- * DEPRECATED and non functional. Not neccesary as this occurs automatically
- *
- * Consolidates this Format with other identical formats in workbook
- *
- *
- * There is a limit to the number of distinct formats in an Excel workbook.
- *
- * This method allows you to share Formats between identically formatted
- * cells.
- *
- * @deprecated
- * @return
- */
- public FormatHandle pack() {
- return this; // wkbook.cache.get(this);
- }
-
- /**
- * Set the workbook for this FormatHandle
- *
- *
- * @param bk
- */
- public void setWorkBook(io.starter.formats.XLS.WorkBook bk) {
- wkbook = bk;
- }
-
- /**
- * Set the cell wrapping behavior for this FormatHandle. Default is false
- */
- public void setWrapText(boolean wrapit) {
- Xf xf = cloneXf(myxf);
- xf.setWrapText(wrapit);
- updateXf(xf);
- }
-
- /**
- * Get the cell wrapping behavior for this FormatHandle. Default is false
- */
- public boolean getWrapText() {
- return myxf.getWrapText();
- }
-
-
-
-
- /**
- * Set the rotation of the cell in degrees. Values 0-90 represent rotation
- * up, 0-90degrees. Values 91-180 represent rotation down, 0-90 degrees.
- * Value 255 is vertical
- *
- * @param align
- * - an int representing the rotation.
- */
- public void setCellRotation(int align) {
- Xf xf = cloneXf(myxf);
- xf.setRotation(align);
- updateXf(xf);
- }
-
- /**
- * Get the rotation of the cell. Value 0 means no rotation (horizontal
- * text). Values 1-90 mean rotation up (couter-clockwise) by 1-90 degrees.
- * Values 91-180 mean rotation down (clockwise) by 1-90 degrees. Value 255
- * means vertical text.
- */
- public int getCellRotation() {
- return myxf.getRotation();
- }
-
- /**
- * Get a JSON representation of the format
- *
- *
- * @param cr
- * @return
- */
- public String getJSON(int XFNum) {
- return getJSONObject(XFNum).toString();
- }
-
- /**
- * Get a JSON representation of the format
- *
- * font height is represented as HTML pt size
- *
- * @param cr
- * @return
- */
- public JSONObject getJSONObject(int XFNum) {
- Font myf = getFont();
- JSONObject theStyle = new JSONObject();
- try {
- theStyle.put("style", XFNum);
- // handle the font
- JSONObject theFont = new JSONObject();
- theFont.put("name", myf.getFontName());
-
- // round out the font size...
- long sz = Math.round(myf.getFontHeight() / 22.0);
-
- theFont.put("size", sz); // adjust smaller
- theFont.put("color", colorToHexString(myf.getColorAsColor()));
- theFont.put("weight", myf.getFontWeight());
- if (getIsBold()) {
- theFont.put("bold", "1");
- }
- if (this.getUnderlined()) {
- theFont.put("underline", "1");
- } else {
- theFont.put("underline", "0");
- }
-
- if (getItalic()) {
- theFont.put("italic", "1");
- }
-
- theStyle.put("font", theFont);
-
- //
- JSONObject border = new JSONObject();
- if (getRightBorderLineStyle() != 0) {
- JSONObject rBorder = new JSONObject();
- rBorder.put("style",
- BORDER_STYLES_JSON[getRightBorderLineStyle()]);
- rBorder.put("color", colorToHexString(getBorderRightColor()));
- border.put("right", rBorder);
- }
- if (getBottomBorderLineStyle() != 0) {
- JSONObject bBorder = new JSONObject();
- bBorder.put("style",
- BORDER_STYLES_JSON[getBottomBorderLineStyle()]);
- bBorder.put("color", colorToHexString(getBorderBottomColor()));
- border.put("bottom", bBorder);
- }
- if (getLeftBorderLineStyle() != 0) {
- JSONObject lBorder = new JSONObject();
- lBorder.put("style",
- BORDER_STYLES_JSON[getLeftBorderLineStyle()]);
- lBorder.put("color", colorToHexString(getBorderLeftColor()));
- border.put("left", lBorder);
- }
- if (getTopBorderLineStyle() != 0) {
- JSONObject tBorder = new JSONObject();
- tBorder.put("style",
- BORDER_STYLES_JSON[getTopBorderLineStyle()]);
- tBorder.put("color", colorToHexString(getBorderTopColor()));
- border.put("top", tBorder);
- }
- theStyle.put("borders", border);
-
- //
- JSONObject alignment = new JSONObject();
- alignment.put("horizontal",
- HORIZONTAL_ALIGNMENTS[getHorizontalAlignment()]);
- alignment.put("vertical",
- VERTICAL_ALIGNMENTS[getVerticalAlignment()]);
- if (getWrapText()) {
- alignment.put("wrap", "1");
- }
- theStyle.put("alignment", alignment);
-
- if (getIndent() != 0) {
- theStyle.put("indent", getIndent());
- }
- // colors + background patterns
- if (getFillPattern() >= 0) { // KSC: added >= 0 as some conditional formats have patternFillStyle==0 even though they have a pattern block and
- JSONObject interior = new JSONObject();
- // weird black/white case
- if (myxf.getForegroundColor() == 65) {
- interior.put("color", "#FFFFFF");
- } else {
- // KSC: use color string if it exists; create if doesn't
- interior.put("color", myxf.getForegroundColorHEX());
- }
- interior.put("pattern", myxf.getFillPattern());
- interior.put("fg", myxf.getForegroundColor()); // Excel-2003 Color Table index
- interior.put("patterncolor", myxf.getBackgroundColorHEX());
- interior.put("bg", myxf.getBackgroundColor()); // Excel-2003 Color Table index
- theStyle.put("interior", interior);
- }
-
- if (myxf.getIfmt() != 0) { // only input user defined formats ...
- JSONObject nFormat = new JSONObject();
- String fmtpat = getFormatPattern();
- try {
- if (!fmtpat.equals("General")) {
- nFormat.put("format", fmtpat); // convertXMLChars?
- nFormat.put("formatid", myxf.getIfmt());
- if (isDate())
- nFormat.put("isdate", "1");
- if (isCurrency())
- nFormat.put("iscurrency", "1");
- if (isRedWhenNegative())
- nFormat.put("isrednegative", "1");
- }
-
- } catch (Exception e) { // it's possible that getFormatPattern
- // returns null
- }
- theStyle.put("numberformat", nFormat);
- }
- //
- JSONObject protection = new JSONObject();
- try {
- if (this.myxf.isLocked())
- protection.put("Protected", true);
- if (this.myxf.isFormulaHidden())
- protection.put("HideFormula", true);
- } catch (Exception e) {
- }
- theStyle.put("protection", protection);
-
- } catch (JSONException e) {
- Logger.logErr("Error getting cellRange JSON: " + e);
- }
- return theStyle;
- }
-
- /**
- * Returns an XML fragment representing the FormatHandle
- */
- public String getXML(int XFNum) {
- return getXML(XFNum, false);
- }
-
- /**
- * Returns an XML fragment representing the FormatHandle
- *
- * @param convertToUnicodeFont
- * if true, font family will be changed to ArialUnicodeMS
- * (standard unicode) for non-ascii fonts
- */
- public String getXML(int XFNum, boolean convertToUnicodeFont) {
- Font myf = getFont();
- // ");
- return sb.toString();
- }
-
- /**
- * Gets the Excel format ID for this format's number format pattern.
- *
- * @return the Excel format identifier number for the number format pattern
- */
- public int getFormatPatternId() {
- return myxf.getIfmt();
- }
-
- /**
- * Sets the number format pattern based on the format ID number. This method
- * is recommended for advanced users only. In most cases you should use
- * {@link #setFormatPattern(String)} instead.
- *
- * @param fmt
- * the format ID number for the desired number format pattern
- */
- public void setFormatPatternId(int fmt) {
- myxf.setFormat((short) fmt);
- }
-
- /**
- * Convert a java.awt.Color to a hex string.
- *
- * @return String representation of a Color
- */
- public static String colorToHexString(Color c) {
- int r = c.getRed();
- int g = c.getGreen();
- int b = c.getBlue();
- String rh = Integer.toHexString(r);
- if (rh.length() < 2) {
- rh = "0" + rh;
- }
- String gh = Integer.toHexString(g);
- if (gh.length() < 2) {
- gh = "0" + gh;
- }
- String bh = Integer.toHexString(b);
- if (bh.length() < 2) {
- bh = "0" + bh;
- }
- return ("#" + rh + gh + bh).toUpperCase();
- }
-
-
- public static short colorFONT = 0;
- public static short colorBACKGROUND = 1;
- public static short colorFOREGROUND = 2;
- public static short colorBORDER = 3;
-
- /**
- * convert hex string RGB to Excel colortable int format if an exact match
- * is not find, does color-matching to try and obtain closest match
- *
- * @param s
- * @param colorType
- * @return
- */
- public static int HexStringToColorInt(String s, short colorType) {
- if (s.length() > 7)
- s = "#" + s.substring(s.length() - 6);
- if (s.indexOf("#") == -1)
- s = "#" + s;
- if (s.length() == 7) {
- String rs = s.substring(1, 3);
- int r = Integer.parseInt(rs, 16);
- String gs = s.substring(3, 5);
- int g = Integer.parseInt(gs, 16);
- String bs = s.substring(5, 7);
- int b = Integer.parseInt(bs, 16);
- // Handle exceptions for black, white and color indexes 9 (see
- // FormatConstants for more info)
-
- if (r == 255 && r == g && r == b) {
- if (colorType == colorFONT)
- return 9;
- }
-
- Color c = new Color(r, g, b);
- return getColorInt(c);
- }
- return 0;
- }
-
- /**
- * convert hex string RGB to Excel colortable int format if no exact match
- * is found returns -1
- *
- * @param s
- * HTML color string (#XXXXXX) format or (#FFXXXXXX - OOXML-style
- * format)
- * @param colorType
- * @return index into color table or -1 if not found
- */
- public static int HexStringToColorIntExact(String s, short colorType) {
- if (s.length() > 7)
- s = "#" + s.substring(s.length() - 6);
- if (s.indexOf("#") == -1)
- s = "#" + s;
- if (s.length() == 7) {
- String rs = s.substring(1, 3);
- int r = Integer.parseInt(rs, 16);
- String gs = s.substring(3, 5);
- int g = Integer.parseInt(gs, 16);
- String bs = s.substring(5, 7);
- int b = Integer.parseInt(bs, 16);
-
- // Handle exceptions for black, white and color indexes 9 (see
- // FormatConstants for more info)
- if (r == 255 && r == g && r == b) {
- if (colorType == colorFONT)
- return 9;
- }
-
- Color c = new Color(r, g, b);
- for (int i = 0; i < FormatHandle.COLORTABLE.length; i++) {
- if (c.equals(FormatHandle.COLORTABLE[i])) {
- return i;
- }
- }
- }
- return -1; // match NOT FOUND
- }
-
- /**
- * convert hex string RGB to a Color
- *
- *
- * @param s web-style hex color string, including #, or OOXML-style color string, FFXXXXXX
- * @return Color
- * @see Color
- */
- public static Color HexStringToColor(String s) {
- if (s.length() > 7){ // transform OOXML-style color strings to Web-style
- s = "#" + s.substring(s.length() - 6);
- }
- Color c = null;
- if (s.length() == 7) {
- String rs = s.substring(1, 3);
- int r = Integer.parseInt(rs, 16);
- String gs = s.substring(3, 5);
- int g = Integer.parseInt(gs, 16);
- String bs = s.substring(5, 7);
- int b = Integer.parseInt(bs, 16);
- c = new Color(r, g, b);
- } else
- c = new Color(0, 0, 0); // default to black?
- return c;
- }
-
- /**
- * interpret color table special entries
- *
- * @param clr
- * color index in range of 0x41-0x4F (charts) 0x40 ...
- * @return index into color table
- */
- public static short interpretSpecialColorIndex(int clr) {
- switch (clr) {
- case 0x0041: // Default background color. This is the window background
- // color in the sheet display and is the default
- // background color for a cell.
- case 0x004E: // Default chart background color. This is the window
- // background color in the chart display.
- case 0x0050: // WHAT IS THIS ONE????????
- return FormatConstants.COLOR_WHITE;
- case 0x0040: // Default foreground color
- case 0x004F: // Chart neutral color which is black, an RGB value of
- // (0,0,0).
- case 0x004D: // Default chart foreground color. This is the window text
- // color in the chart display.
- case 0x0051: // ToolTip text color. This is the automatic font color for
- // comments.
- case 0x7FFF: // Font automatic color. This is the window text color
- return FormatConstants.COLOR_BLACK;
- default: // 67(=0x43) ???
- return FormatConstants.COLOR_WHITE;
- }
-
- /*
- * switch (icvFore) { case 0x40: // default fg color return
- * FormatConstants.COLOR_WHITE; case 0x41: // default bg color return
- * FormatConstants.COLOR_WHITE; case 0x4D: // default CHART fg color --
- * INDEX SPECIFIC! return -1; // flag to map via series (bar) color
- * defaults case 0x4E: // default CHART fg color return icvFore; case
- * 0x4F: // chart neutral color == black return
- * FormatConstants.COLOR_BLACK; }
- *
- * switch (icvBack) { case 0x40: // default fg color return
- * FormatConstants.COLOR_WHITE; case 0x41: // default bg color return
- * FormatConstants.COLOR_WHITE; case 0x4D: // default CHART fg color --
- * INDEX SPECIFIC! return -1; // flag to map via series (bar) color
- * defaults case 0x4E: // default CHART bg color //return
- * FormatConstants.COLOR_WHITE; // is this correct? return icvBack; case
- * 0x4F: // chart neutral color == black return
- * FormatConstants.COLOR_BLACK; }
- */
- }
-
- public static int BorderStringToInt(String s) {
- for (int i = 0; i < FormatConstants.BORDER_NAMES.length; i++) {
- if (FormatConstants.BORDER_NAMES[i].equals(s))
- return i;
- }
- return 0;
- }
-
- // 20060412 KSC: added for access
- public io.starter.formats.XLS.WorkBook getWorkBook() {
- return wkbook;
- }
-
- /**
- * return truth of "this Xf rec is a style xf"
- *
- * @return
- */
- public boolean isStyleXf() {
- return myxf.isStyleXf();
- }
-
- /**
- * creates a new font based on an existing one, adds to workbook recs
- */
- private Font createNewFont(Font f) {
- f.setIdx(-1); // flag to insert anew (see Font.setWorkBook)
- wkbook.insertFont(f);
- f.setWorkBook(wkbook);
- return f;
- }
-
- /**
- * create a new font based on existing font - does not add to workbook recs
- *
- * @param src
- * font
- * @return cloned font
- */
- private Font cloneFont(Font src) {
- Font f = new Font();
- f.setOpcode(io.starter.formats.XLS.XLSConstants.FONT);
- f.setData(src.getBytes()); // use default font as basis of new font
- f.setIdx(-2); // avoid adding to fonts array when call setW.b. below
- f.setWorkBook(this.getWorkBook());
- f.init();
- return f;
- }
-
- /**
- * update the font for this FormatHandle, including updating the xf if
- * necessary
- *
- * @param f
- */
- private void updateFont(Font f) {
- int idx = wkbook.getFontIdx(f);
- if (idx == -1) { // can't find it so add new
- f = createNewFont(f);
- } else
- f = wkbook.getFont(idx);
- if (f.getIdx()!=myxf.getIfnt()) { // then updated the font, must create new xf to link to
- Xf xf = cloneXf(myxf);
- xf.setFont(f.getIdx());
- updateXf(xf);
- }
- }
-
- /**
- * Create or Duplicate Xf rec so can alter (pattern, font, colrs ...)
- *
- * @param xf
- * xf to base off of, or null (will create new)
- * @return new Xf
- */
- private Xf duplicateXf(Xf xf) {
- int fidx = 0;
- if (xf != null)
- fidx = xf.getFont().getIdx();
- xf = Xf.updateXf(xf, fidx, wkbook); // clones/creates new based upon
- // original
- xfe = xf.getIdx(); // update the pointer
-// not used anymore canModify = true; // if duplicated, it's new and unlinked (thus far)
- return xf;
- }
-
- /**
- * adds all formatting represented by the sourceXf to this workbook, if not
- * already present
- * This is used internally for transferring formats from one workbook to
- * another
- *
- * @param xf
- * - sourceXf
- * @return ixfe of added Xf
- */
- public int addXf(Xf sourceXf) {
- // must handle font first in order to create xf below
- // check to see if the font needs to be added in current workbook
- int fidx = addFontIfNecessary(sourceXf.getFont());
-
- /** XF **/
- Xf localXf = FormatHandle.cloneXf(sourceXf, wkbook.getFont(fidx),
- wkbook); // clone xf so modifcations don't affect original
-
- /** NUMBER FORMAT **/
- String fmt = sourceXf.getFormatPattern(); // number format pattern
- if (fmt != null)
- localXf.setFormatPattern(fmt); // adds new format pattern if not // found
-
- // now check out to see if this particular xf pattern exists; if not, add
- updateXf(localXf);
- return xfe;
- }
-
- /**
- * if existing format matches, reuse. otherwise, create new Xf record and
- * add to cache
- *
- * @param xf
- */
- private void updateXf(Xf xf) {
- if (!myxf.toString().equals(xf.toString())) {
- if (myxf.getUseCount() <= 1 && xfe > 15) { // used only by one cell, OK to modify
- if (writeImmediate || wkbook.getFormatCache().get(xf.toString()) == null) {
- // myxf hasn't been used yet; modify bytes and re-init ***
- byte[] xfbytes = xf.getBytes();
- myxf.setData(xfbytes);
- if (xf.fill != null)
- myxf.fill = (io.starter.formats.OOXML.Fill) xf.fill.cloneElement();
- myxf.init();
- myxf.setFont(myxf.getIfnt()); // set font as well ..
- wkbook.updateFormatCache(myxf); // ensure new xf signature
- // is stored
- } else {
- if (myxf.getUseCount()>0)
- myxf.decUseCoount(); // flag original xf that 1 less record is referencing it
- myxf = (Xf) wkbook.getFormatCache().get(xf.toString());
- xfe = myxf.getIdx(); // update the pointer
- if (xfe == -1) // hasn't been added to wb yet - should this ever happen???
- myxf = duplicateXf(xf); // create a duplicate and leave original
- else
- myxf.incUseCount();
- }
- } else { // cannot modify original - either find matching or create new
- if (myxf.getUseCount()>0)
- myxf.decUseCoount(); // flag original xf that 1 less record is referencing it
- if (wkbook.getFormatCache().get(xf.toString()) == null) { // doesn't exist yet
- myxf = duplicateXf(xf); // create a duplicate and leave original
- } else {
- myxf = (Xf) (wkbook.getFormatCache().get(xf.toString()));
- xfe = myxf.getIdx(); // update the pointer
- if (xfe == -1) // hasn't been added to the record store yet // - should ever happen???
- myxf = duplicateXf(xf); // create a duplicate and leave original
- else
- myxf.incUseCount();
- }
- }
-
- for (int i = 0; i < mycells.size(); i++) {
- ((BiffRec) mycells.get(i)).setXFRecord(xfe); // make sure all linked cells are updated as well
- }
- if (mycol != null)
- mycol.setFormatId(xfe);
- if (myrow != null)
- myrow.setFormatId(xfe);
- }
- }
-
- /**
- * create a duplicate xf rec based on existing ...
- *
- * @param xf
- * @return cloned xf
- */
- private Xf cloneXf(Xf xf) {
- Xf clone = new Xf(xf.getFont().getIdx(), wkbook);
- byte[] data = xf.getBytesAt(0, xf.getLength() - 4);
- clone.setData(data);
- if (xf.fill != null)
- clone.fill = (io.starter.formats.OOXML.Fill) xf.fill.cloneElement();
- clone.init();
- return clone;
- }
-
- /**
- * static version of cloneXf
- *
- * @param xf
- * @param wkbook
- * @return
- */
- public static Xf cloneXf(Xf xf, io.starter.formats.XLS.WorkBook wkbook) {
- Xf clone = new Xf(xf.getFont().getIdx(), wkbook);
- byte[] data = xf.getBytesAt(0, xf.getLength() - 4);
- clone.setData(data);
- clone.init();
- return clone;
- }
-
- /**
- * static version of cloneXf
- *
- * @param xf
- * @param wkbook
- * @return
- */
- public static Xf cloneXf(Xf xf, Font f,
- io.starter.formats.XLS.WorkBook wkbook) {
- Xf clone = new Xf(f, wkbook);
- byte[] data = xf.getBytesAt(0, xf.getLength() - 4);
- clone.setData(data);
- clone.setFont(f.getIdx()); // font idx is overwritten by xf data; must reset
- clone.init();
- return clone;
- }
-
- /**
- * set the pointer to the XFE or Conditional format
- *
- *
- * @param xfe
- */
- public void setFormatId(int x) {
- this.xfe = x;
- }
-
- /**
- * clear out object references
- */
- public void close() {
- mycells.clear();
- mycells = new CompatibleVector(); // all the Cells sharing this format
- myxf = null;
- mycol = null;
- myrow = null;
- wkbook = null;
- wbh = null;
- }
-
- protected void finalize() throws Throwable {
- try {
- close(); // close open files
- } finally {
- super.finalize();
- }
- }
-
- /**
- * For internal usage only, return the internal XF record that
- * represents this FormatHandle
- * @return the myxf
- */
- protected Xf getXf() {
- return myxf;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/FormatHandle.kt b/src/main/java/io/starter/OpenXLS/FormatHandle.kt
new file mode 100644
index 0000000..a2f200e
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/FormatHandle.kt
@@ -0,0 +1,3011 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.OOXML.Fill
+import io.starter.formats.XLS.Font
+import io.starter.formats.XLS.*
+import io.starter.toolkit.CompatibleVector
+import io.starter.toolkit.Logger
+import io.starter.toolkit.StringTool
+import org.json.JSONException
+import org.json.JSONObject
+
+import java.awt.Color
+import java.util.*
+
+/**
+ * Provides methods for querying and changing cell formatting information. Cell
+ * formating includes fonts, borders, text alignment, background colors, cell
+ * protection (locking), etc.
+ *
+ *
+ * The mutator methods of a FormatHandle object directly and immediately change
+ * the formatting of the cell(s) to which it is applied. Under no circumstances
+ * will a FormatHandle alter the formatting of cells to which it is not applied.
+ * The list of cells to which a FormatHandle applies may be queried with the
+ * [.getCells] method. Additional cells may be added with [.addCell]
+ * and related methods.
+ *
+ *
+ * A FormatHandle may also be obtained for a row or a column. In such a case the
+ * FormatHandle sets the default formats for the row or column. The default
+ * format for a row or column is the format which appears when no other formats
+ * for the cell are specified, such as for newly created cells.
+ */
+class FormatHandle : Handle, FormatConstants {
+
+ private var mycells = CompatibleVector() // all the Cells sharing this format e.g. CellRange
+ /**
+ * For internal usage only, return the internal XF record that
+ * represents this FormatHandle
+ *
+ * @return the myxf
+ */
+ /**
+ * Sets the internal format to the FormatHandle. For internal use only, not
+ * supported.
+ */
+ var xf: Xf? = null
+ /**
+ * The format ID allows setting of the format for a Cell without adding it
+ * to the Format's Cell Collection.
+ *
+ *
+ * Use to decrease memory requirements when dealing with large collections
+ * of cells.
+ *
+ *
+ * Usage:
+ *
+ *
+ * mycell.setFormatId(myformat.getFormatId());
+ *
+ * @return the format ID for this Format
+ */
+ /**
+ * set the pointer to the XFE or Conditional format
+ *
+ * @param xfe
+ */
+ var formatId: Int = 0
+ // see Xf.usedCount instead private boolean canModify = false;
+ private var mycol: ColHandle? = null
+ private var myrow: RowHandle? = null
+ private val writeImmediate = false
+ internal var underlined = false
+
+ // 20060412 KSC: added for access
+ /**
+ * Set the workbook for this FormatHandle
+ *
+ * @param bk
+ */
+ var workBook: io.starter.formats.XLS.WorkBook? = null
+ private var wbh: io.starter.OpenXLS.WorkBook? = null
+
+ /**
+ * returns whether this FormatHandle is set to hide formula strings
+ *
+ * @return true if the formula strings are hidden, false otherwise
+ */
+ /**
+ * sets the cell attached to this FormatHandle to hide or show formula
+ * strings;
+ *
+ * @param boolean b- true if formulas should be hidden for this FormatHandle
+ */
+ var isFormulaHidden: Boolean
+ get() = xf!!.isFormulaHidden
+ set(b) {
+ val xf = cloneXf(this.xf!!)
+ xf.isFormulaHidden = b
+ updateXf(xf)
+ }
+
+ /**
+ * returns whether this Format Handle specifies that cells are locked for
+ * changing
+ *
+ * @return true if cells are locked
+ */
+ /**
+ * Locks the cell attached to this FormatHandle for editing (makes
+ * read-only) lock cell and make read-only
+ *
+ * @param boolean locked - true if cells should be locked for this
+ * FormatHandle
+ */
+ var isLocked: Boolean
+ get() = xf!!.isLocked
+ set(locked) {
+ val xf = cloneXf(this.xf!!)
+ xf.isLocked = locked
+ updateXf(xf)
+ }
+
+ /**
+ * provides a mapping between Excel formats and Java formats
+ * see: [http://java.sun.com/docs/books/tutorial/i18n/format
+ * /decimalFormat.html](tutorial)
+ *
+ *
+ * Note there are slight Excel-specific differences in the format strings
+ * returned. Several numeric and currency formats in excel have different
+ * formatting for postive and negative numbers. In these cases, the java
+ * format string is split by semicolons and may contain text [Red] which is
+ * to specify the negative number should be displayed in red. Remove this
+ * from the string before passing into the Format class;
+ *
+ *
+ * G Era designator Text AD
+ * y Year Year 1996; 96
+ * M Month in year Month July; Jul; 07
+ * w Week in year Number 27
+ * W Week in month Number 2
+ * D Day in year Number 189
+ * d Day in month Number 10
+ * F Day of week in month Number 2
+ * E Day in week Text Tuesday; Tue
+ * a Am/pm marker Text PM
+ * H Hour in day (0-23) Number 0
+ * k Hour in day (1-24) Number 24
+ * K Hour in am/pm (0-11) Number 0
+ * h Hour in am/pm (1-12) Number 12
+ * m Minute in hour Number 30
+ * s Second in minute Number 55
+ * S Millisecond Number 978
+ * z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
+ * Z Time zone RFC 822 time zone -0800
+ *
+ *
+ * @return String the formatting pattern for the cell
+ */
+ // toLowerCase is a simplistic way to implement the case insensitivity
+ // of the pattern tokens. It could cause issues with string literals.
+ /*
+ * If we reached here, we don't have a mapping for this particular
+ * format. Send a warning to the system then make sure the pattern we
+ * are sending back is valid. Many excel patterns have 4 patterns
+ * separated by semicolons. We only can pass 2 into the formatter
+ * (positive and negative). This usually works out to be the first two
+ * patterns in the string.
+ */// yet another hackaround -jm
+ val javaFormatString: String?
+ get() {
+ var pat = formatPattern ?: return null
+ var patty: Any? = convertFormatString(pat!!.toLowerCase())
+ if (patty != null)
+ patty = StringTool.qualifyPatternString(patty.toString())
+ if (xf!!.isDatePattern) {
+ return if (patty != null)
+ patty as String?
+ else
+ "M/d/yy h:mm"
+ }
+ if (patty != null)
+ return patty as String?
+ pat = StringTool.qualifyPatternString(pat)
+ val firstParens = pat!!.indexOf(";")
+ if (firstParens != -1) {
+ val secondParens = pat!!.indexOf(";", firstParens + 1)
+ if (secondParens != -1) {
+ pat = pat!!.substring(0, secondParens)
+ } else {
+ pat = pat!!.substring(firstParens + 2, pat!!.length - 1)
+ }
+ }
+ return pat
+ }
+
+ /**
+ * Get the Right border color
+ *
+ * @return color constant
+ */
+ // black i'm afraid
+ val borderRightColor: Color?
+ get() {
+ if (xf!!.rightBorderLineStyle.toInt() == 0)
+ return null
+ val x = xf!!.rightBorderColor.toInt()
+ return if (x < this.workBook!!.colorTable.size)
+ this.workBook!!.colorTable[x]
+ else
+ this.workBook!!.colorTable[0]
+ }
+
+ /**
+ * returns Border Colors of Cell ie: top, left, bottom, right
+ *
+ *
+ * returns null or 1 color for each of 4 sides
+ *
+ *
+ * 1,1,1,1 represents a border all around the cell 1,1,0,0 represents on the
+ * top left edge of the cell
+ *
+ * @return int array representing Cell borders
+ */
+ /*
+ * FIXME: Border Issues (marker)
+ *
+ * The methods to set individual border line styles do not follow a
+ * consistent naming convention with the rest of the border methods.
+ *
+ * There are no methods for getting or setting the inside borders. I don't
+ * know whether this is a problem or a design choice. It depends on whether
+ * the inside borders are stored in the format record or as separate cell
+ * formats.
+ *
+ * There are no methods to get the diagonal borders. There is a method to
+ * set the diagonal border line style, but it affects both diagonals.
+ */
+
+ /**
+ * sets the border color for all borders (top, left, bottom and right) from
+ * a Color array
+ *
+ *
+ * NOTE: this setting will affect every cell which refers to this
+ * FormatHandle
+ *
+ * @param java .awt.Color array - 4-element array of desired border colors
+ * [T, L, B, R]
+ */
+ var borderColors: Array
+ get() {
+ val colors = arrayOfNulls(4)
+ colors[0] = borderTopColor
+ colors[1] = borderLeftColor
+ colors[2] = borderBottomColor
+ colors[3] = borderRightColor
+ return colors
+ }
+ set(bordercolors) {
+ val xf = cloneXf(this.xf!!)
+ if (bordercolors[0] != null)
+ xf.topBorderColor = getColorInt(bordercolors[0])
+ if (bordercolors[1] != null)
+ xf.leftBorderColor = getColorInt(bordercolors[1])
+ if (bordercolors[2] != null)
+ xf.bottomBorderColor = getColorInt(bordercolors[2])
+ if (bordercolors[3] != null)
+ xf.setRightBorderColor(getColorInt(bordercolors[3]))
+ updateXf(xf)
+ }
+
+ /**
+ * Get the Left border color
+ *
+ * @return color constant
+ */
+ val borderLeftColor: Color?
+ get() = if (xf!!.leftBorderLineStyle.toInt() == 0) null else this.workBook!!.colorTable[xf!!.leftBorderColor]
+
+ /**
+ * Get the Top border color
+ *
+ * @return color constant
+ */
+ // guards
+ val borderTopColor: Color?
+ get() {
+ if (xf!!.topBorderLineStyle.toInt() == 0)
+ return null
+ var xt = xf!!.topBorderColor
+ if (xt > this.workBook!!.colorTable.size)
+ xt = 0
+ return this.workBook!!.colorTable[xt]
+ }
+
+ /**
+ * Returns true if the value should be red due to a combination of a format
+ * pattern and a negative number
+ *
+ * @return
+ */
+ val isRedWhenNegative: Boolean
+ get() {
+ val pattern = xf!!.formatPattern
+ return pattern!!.indexOf("Red") > -1
+ }
+
+ /**
+ * Get the Right border color
+ *
+ * @return color constant
+ */
+ // black i'm afraid
+ val borderBottomColor: Color?
+ get() {
+ if (xf!!.bottomBorderLineStyle.toInt() == 0)
+ return null
+ val x = xf!!.bottomBorderColor
+ return if (x < this.workBook!!.colorTable.size)
+ this.workBook!!.colorTable[x]
+ else
+ this.workBook!!.colorTable[0]
+
+ }
+
+ /**
+ * Get the border line style
+ *
+ * @return line style constant
+ */
+ /**
+ * Set the border line style
+ *
+ * @param line style constant
+ */
+ var topBorderLineStyle: Int
+ get() = xf!!.topBorderLineStyle.toInt()
+ set(x) {
+ val xf = cloneXf(this.xf!!)
+ xf.topBorderLineStyle = x.toShort()
+ updateXf(xf)
+ }
+
+ /**
+ * Get the border line style
+ *
+ * @return line style constant
+ */
+ /**
+ * Set the border line style
+ *
+ * @param line style constant
+ */
+ var bottomBorderLineStyle: Int
+ get() = xf!!.bottomBorderLineStyle.toInt()
+ set(x) {
+ val xf = cloneXf(this.xf!!)
+ xf.bottomBorderLineStyle = x.toShort()
+ updateXf(xf)
+ }
+
+ /**
+ * Get the border line style
+ *
+ * @return line style constant
+ */
+ /**
+ * Set the border line style
+ *
+ * @param line style constant
+ */
+ var leftBorderLineStyle: Int
+ get() = xf!!.leftBorderLineStyle.toInt()
+ set(x) {
+ val xf = cloneXf(this.xf!!)
+ xf.leftBorderLineStyle = x.toShort()
+ updateXf(xf)
+ }
+
+ /**
+ * Get the border line style
+ *
+ * @return line style constant
+ */
+ /**
+ * Set the border line style
+ *
+ * @param line style constant
+ */
+ var rightBorderLineStyle: Int
+ get() = xf!!.rightBorderLineStyle.toInt()
+ set(x) {
+ val xf = cloneXf(this.xf!!)
+ xf.rightBorderLineStyle = x.toShort()
+ updateXf(xf)
+ }
+
+ /**
+ * return the 5 border lines styles (l, r, t, b, diag)
+ *
+ * @return
+ */
+ val allBorderLineStyles: IntArray
+ get() {
+ val ret = IntArray(5)
+ ret[0] = xf!!.leftBorderLineStyle.toInt()
+ ret[1] = xf!!.rightBorderLineStyle.toInt()
+ ret[2] = xf!!.topBorderLineStyle.toInt()
+ ret[3] = xf!!.bottomBorderLineStyle.toInt()
+ ret[4] = xf!!.diagBorderLineStyle.toInt()
+ return ret
+ }
+
+ /**
+ * return the 5 border line colors (l, r, t, b, diag)
+ *
+ * @return
+ */
+ val allBorderColors: IntArray
+ get() {
+ val ret = IntArray(5)
+ ret[0] = xf!!.leftBorderColor
+ ret[1] = xf!!.rightBorderColor.toInt()
+ ret[2] = xf!!.topBorderColor
+ ret[3] = xf!!.bottomBorderColor
+ ret[4] = xf!!.diagBorderColor.toInt()
+ return ret
+ }
+
+/**
+ * Get the font weight the weight of the font is in 1/20 point units
+ *
+ * @return
+ */
+/**
+ * /** Set the weight of the font in 1/20 point units 100-1000 range. 400 is
+ * normal, 700 is bold.
+ *
+ * @param wt
+*/
+var fontWeight:Int
+get() {
+return xf!!.font!!.fontWeight
+}
+set(wt) {
+val f = cloneFont(xf!!.font!!)
+f.fontWeight = wt
+updateFont(f)
+}
+
+/**
+ * returns whether this Format is formatted as a Date
+ *
+ * @return boolean true if this Format is formatted as a Date
+*/
+val isDate:Boolean
+get() {
+if (xf == null)
+return false
+return xf!!.isDatePattern
+}
+
+/**
+ * returns whether this Format is formatted as a Currency
+ *
+ * @return boolean true if this Format is formatted as a currency
+*/
+val isCurrency:Boolean
+get() {
+if (xf == null)
+return false
+return xf!!.isCurrencyPattern
+}
+
+/**
+ * Get the Font foreground (text) color as a java.awt.Color
+ *
+ * @return
+*/
+val fontColor:Color
+get() {
+return xf!!.font!!.colorAsColor
+}
+
+
+val fontColorAsHex:String
+get() {
+return xf!!.font!!.colorAsHex
+}
+
+/**
+ * Get the Pattern Background Color for this Format Pattern
+ *
+ * @return the Excel color constant
+*/
+/**
+ * set the background color for this Format NOTE: Foreground color = the
+ * CELL BACKGROUND color color for all patterns and Background color= the
+ * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
+ * color=CELL BACKGROUND color and Background Color=64 (white).
+ *
+ * @param t Excel color constant
+*/
+var backgroundColor:Int
+get() {
+return xf!!.backgroundColor.toInt()
+}
+set(t) {
+val xf = cloneXf(this.xf!!)
+if (xf.fillPattern == Xf.PATTERN_SOLID)
+xf.setForeColor(t, null)
+else
+xf.setBackColor(t, null)
+
+updateXf(xf)
+}
+
+/**
+ * get the Pattern Background Color for this Format Pattern as a hex string
+ *
+ * @return Hex Color String
+*/
+val backgroundColorAsHex:String?
+get() {
+return xf!!.backgroundColorHEX
+}
+
+/**
+ * get the Pattern Background Color for this Format Pattern as an awt.Color
+ *
+ * @return background Color
+*/
+val backgroundColorAsColor:java.awt.Color
+get() {
+return HexStringToColor(this.backgroundColorAsHex!!)
+}
+
+
+/**
+ * returns the foreground color setting regardless of format pattern (which
+ * can switch fg and bg)
+ *
+ * @return
+*/
+// 20080814 KSC: getForegroundColor() does the swapping so use base method
+val trueForegroundColor:Int
+get() {
+return xf!!.foregroundColor.toInt()
+}
+
+/**
+ * get the Pattern Background Color for this Formatted Cell
+ *
+ *
+ * This method handles display of conditional formats for the cell
+ *
+ *
+ * checks for conditional format, then applies it if conditions are true.
+ *
+ * @return the Excel color constant
+*/
+// this.getForegroundColor() does
+// the swapping so use base
+// method
+val cellBackgroundColor:Int
+get() {
+val fp = fillPattern
+
+if (fp == Xf.PATTERN_SOLID)
+return xf!!.foregroundColor.toInt()
+else
+return xf!!.backgroundColor.toInt()
+}
+
+/**
+ * get the Pattern Background Color for this Format as a Hex Color String
+ *
+ * @return Hex Color String
+*/
+// this.getForegroundColor() does
+val cellBackgroundColorAsHex:String?
+get() {
+val fp = fillPattern
+
+if (fp == Xf.PATTERN_SOLID)
+return xf!!.foregroundColorHEX
+else
+return xf!!.backgroundColorHEX
+}
+
+/**
+ * get the Pattern Background Color for this Format as an awt.Color
+ *
+ * @return cell background color
+*/
+val cellBackgroundColorAsColor:java.awt.Color
+get() {
+return HexStringToColor(this.cellBackgroundColorAsHex!!)
+}
+
+/**
+ * get the Background Color for this Format NOTE: Foreground color = the
+ * CELL BACKGROUND color color for all patterns and Background color= the
+ * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
+ * color=CELL BACKGROUND color and Background Color=64 (white).
+ *
+ * @return the Excel color constant
+*/
+/**
+ * set the Foreground Color for this Format NOTE: Foreground color = the
+ * CELL BACKGROUND color color for all patterns and Background color= the
+ * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
+ * color=CELL BACKGROUND color and Background Color=64 (white).
+ *
+ * @param int Excel color constant
+*/
+// if it's SOLID pattern, fg/bg are swapped
+var foregroundColor:Int
+get() {
+if (fillPattern == Xf.PATTERN_SOLID)
+return xf!!.backgroundColor.toInt()
+
+return xf!!.foregroundColor.toInt()
+}
+set(t) {
+val xf = cloneXf(this.xf!!)
+xf.setForeColor(t, null)
+updateXf(xf)
+}
+
+/**
+ * get the Background Color for this Format as a Hex Color String NOTE:
+ * Foreground color = the CELL BACKGROUND color color for all patterns and
+ * Background color= the PATTERN color for all patterns != Solid For
+ * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
+ * Color=64 (white).
+ *
+ * @return Hex Color String
+*/
+// if it's SOLID pattern,
+val foregroundColorAsHex:String?
+get() {
+if (fillPattern == Xf.PATTERN_SOLID)
+return xf!!.backgroundColorHEX
+
+return xf!!.foregroundColorHEX
+}
+
+/**
+ * get the Background Color for this Format as a Color NOTE:
+ * Foreground color = the CELL BACKGROUND color color for all patterns and
+ * Background color= the PATTERN color for all patterns != Solid For
+ * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
+ * Color=64 (white).
+ *
+ * @return Hex Color String
+*/
+val foregroundColorAsColor:Color
+get() {
+return HexStringToColor(this.foregroundColorAsHex!!)
+}
+
+/**
+ * Get if this format is bold or not
+ *
+ * @return boolean whether the cell font format is bold
+*/
+val isBold:Boolean
+get() {
+return xf!!.font!!.isBold
+}
+
+/**
+ * Return an int representing the underline style
+ *
+ *
+ * These map to the STYLE_UNDERLINE static integers *
+ *
+ * @return int underline style
+*/
+/**
+ * set the underline style for this font
+ *
+ * @param int u underline style one of the Font.STYLE_UNDERLINE constants
+*/
+var underlineStyle:Int
+get() {
+return xf!!.font!!.underlineStyle
+}
+set(u) {
+val f = cloneFont(xf!!.font!!)
+f.setUnderlineStyle(u.toByte())
+updateFont(f)
+}
+
+/**
+ * Get the font height in points
+ *
+ * @return font height
+*/
+val fontHeightInPoints:Double
+get() {
+return font!!.fontHeightInPoints
+}
+
+/**
+ * Returns the Font's height in 1/20th point increment
+ *
+ * @return font height
+*/
+/**
+ * Set the Font's height in 1/20th point increment
+ *
+ * @param new font height
+*/
+var fontHeight:Int
+get() {
+return font!!.fontHeight
+}
+set(fontHeight) {
+val f = cloneFont(xf!!.font!!)
+f.fontHeight = fontHeight
+updateFont(f)
+}
+
+/**
+ * Returns the Font's name
+ *
+ * @return font name
+*/
+/**
+ * Set the Font's name
+ *
+ *
+ * To be valid, this font name must be available on the client system.
+ *
+ * @param font name
+*/
+var fontName:String?
+get() {
+return font!!.getFontName()
+}
+set(fontName) {
+val f = cloneFont(xf!!.font!!)
+f.setFontName(fontName)
+updateFont(f)
+}
+
+/**
+ * Determine if the format handle refers to a font stricken out
+ *
+ * @return boolean representing if the FormatHandle is striking out a cell.
+*/
+/**
+ * Set if the format handle is stricken out
+ *
+ * @param isStricken boolean representing if the formatted cell should be stricken
+ * out.
+*/
+var stricken:Boolean
+get() {
+if (xf!!.font == null)
+return false
+return xf!!.font!!.stricken
+}
+set(isStricken) {
+val f = cloneFont(xf!!.font!!)
+f.stricken = isStricken
+updateFont(f)
+}
+
+/**
+ * Get if the font is italic
+ *
+ * @return boolean representing if the formatted cell is italic.
+*/
+/**
+ * Set if the font is italic
+ *
+ * @param isItalic boolean representing if the formatted cell should be italic.
+*/
+var italic:Boolean
+get() {
+if (xf!!.font == null)
+return false
+return xf!!.font!!.italic
+}
+set(isItalic) {
+val f = cloneFont(xf!!.font!!)
+f.italic = isItalic
+updateFont(f)
+}
+
+/**
+ * Get if the font is bold
+ *
+ * @return boolean representing if the formatted cell is bold
+*/
+/**
+ * Set the format handle to use standard bold text
+ *
+ * @param boolean isBold
+*/
+var bold:Boolean
+get() {
+return xf!!.font!!.bold
+}
+set(isBold) {
+val f = cloneFont(xf!!.font!!)
+f.bold = isBold
+updateFont(f)
+}
+
+/**
+ * returns the existing font record for this Format
+ *
+ *
+ * Font is an internal record and should not be accessed by end users
+ *
+ * @return the XLS Font record associated with this Format
+*/
+/**
+ * Set the Font for this Format.
+ *
+ *
+ * As adding a new Font and format increases the file size, try using this
+ * once for each distinct font used in the file, then use 'setFormatId' to
+ * share this font with other Cells.
+ *
+ *
+ * Roughly matches the functionality of the java.awt.Font class. Currently
+ * the style parameter is only useful for bold/normal weights. Italics,
+ * underlines, etc must be modified elsewhere.
+ *
+ *
+ * Note that in order to maintain java.awt.Font compatibility for
+ * bold/normal styles, defaults for weight/style have been mapped to 0 =
+ * normal (excel 200 weight) and 1 = bold (excel 700 weight)
+ *
+ * @param String font name
+ * @param int font style
+ * @param int font size
+*/
+// should this be a protected method?
+// shouldn't!
+var font:io.starter.formats.XLS.Font?
+get() {
+if (xf != null)
+return xf!!.font
+return null
+}
+set(f) {
+setXFToFont(f)
+}
+
+/**
+ * Gets the number format pattern for this format, if set. For more
+ * information on number format patterns see [Microsoft KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @return the Excel number format pattern for this cell or
+ * `null` if none is applied
+*/
+/**
+ * Sets the number format pattern for this format. All Excel built-in number
+ * formats are supported. Custom formats will not be applied by OpenXLS
+ * (e.g. [CellHandle.getFormattedStringVal]) but they will be written
+ * correctly to the output file. For more information on number format
+ * patterns see [Microsoft
+ * KB264372](http://support.microsoft.com/kb/264372).
+ *
+ * @param pat the Excel number format pattern to apply
+ * @see FormatConstantsImpl.getBuiltinFormats
+*/
+var formatPattern:String?
+get() {
+return xf!!.formatPattern
+}
+set(pat) {
+val xf = cloneXf(this.xf!!)
+xf.formatPattern = pat
+updateXf(xf)
+}
+
+/**
+ * get the fill pattern for this format
+*/
+val fillPattern:Int
+get() {
+return xf!!.fillPattern
+}
+
+/**
+ * Returns an int representing the current horizontal alignment in this
+ * FormatHandle. These values are mapped to the FormatHandle.ALIGN*** static
+ * int's
+*/
+/**
+ * Set the horizontal alignment for this FormatHandle
+ *
+ * @param align - an int representing the alignment. Please review the
+ * FormatHandle.ALIGN*** static int's
+*/
+var horizontalAlignment:Int
+get() {
+return xf!!.horizontalAlignment
+}
+set(align) {
+val xf = cloneXf(this.xf!!)
+xf.horizontalAlignment = align
+updateXf(xf)
+}
+
+/**
+ * return indent (1 = 3 spaces)
+ *
+ * @return
+*/
+/**
+ * set indent (1= 3 spaces)
+ *
+ * @param indent
+*/
+var indent:Int
+get() {
+return xf!!.indent
+}
+set(indent) {
+val xf = cloneXf(this.xf!!)
+xf.indent = indent
+updateXf(xf)
+}
+
+/**
+ * returns true if this style is set to Right-to-Left text direction
+ * (reading order)
+ *
+ * @return
+*/
+val rightToLetReadingOrder:Int
+get() {
+return xf!!.rightToLeftReadingOrder
+}
+
+/**
+ * Returns an int representing the current Vertical alignment in this
+ * FormatHandle. These values are mapped to the FormatHandle.ALIGN*** static
+ * int's
+*/
+/**
+ * Set the Vertical alignment for this FormatHandle
+ *
+ * @param align - an int representing the alignment. Please review the
+ * FormatHandle.ALIGN*** static int's
+*/
+var verticalAlignment:Int
+get() {
+return xf!!.verticalAlignment
+}
+set(align) {
+val xf = cloneXf(this.xf!!)
+xf.verticalAlignment = align
+updateXf(xf)
+}
+
+/**
+ * Get the cell wrapping behavior for this FormatHandle. Default is false
+*/
+/**
+ * Set the cell wrapping behavior for this FormatHandle. Default is false
+*/
+var wrapText:Boolean
+get() {
+return xf!!.wrapText
+}
+set(wrapit) {
+val xf = cloneXf(this.xf!!)
+xf.wrapText = wrapit
+updateXf(xf)
+}
+
+/**
+ * Get the rotation of the cell. Value 0 means no rotation (horizontal
+ * text). Values 1-90 mean rotation up (couter-clockwise) by 1-90 degrees.
+ * Values 91-180 mean rotation down (clockwise) by 1-90 degrees. Value 255
+ * means vertical text.
+*/
+/**
+ * Set the rotation of the cell in degrees. Values 0-90 represent rotation
+ * up, 0-90degrees. Values 91-180 represent rotation down, 0-90 degrees.
+ * Value 255 is vertical
+ *
+ * @param align - an int representing the rotation.
+*/
+var cellRotation:Int
+get() {
+return xf!!.rotation
+}
+set(align) {
+val xf = cloneXf(this.xf!!)
+xf.rotation = align
+updateXf(xf)
+}
+
+/**
+ * Gets the Excel format ID for this format's number format pattern.
+ *
+ * @return the Excel format identifier number for the number format pattern
+*/
+/**
+ * Sets the number format pattern based on the format ID number. This method
+ * is recommended for advanced users only. In most cases you should use
+ * [.setFormatPattern] instead.
+ *
+ * @param fmt the format ID number for the desired number format pattern
+*/
+var formatPatternId:Int
+get() {
+return xf!!.ifmt.toInt()
+}
+set(fmt) {
+xf!!.setFormat(fmt.toShort())
+}
+
+/**
+ * return truth of "this Xf rec is a style xf"
+ *
+ * @return
+*/
+val isStyleXf:Boolean
+get() {
+return xf!!.isStyleXf
+}
+
+/**
+ * Nullary constructor for use in bean context. **This is not part of the
+ * public API and should not be called.**
+*/
+constructor() {}
+
+/**
+ * Constructs a FormatHandle for the given WorkBook and format record.
+ * **This is not part of the public API and should not be called.**
+*/
+constructor(book:io.starter.OpenXLS.WorkBook?, xfr:Xf) {
+xf = xfr
+formatId = xf!!.idx
+wbh = book
+if (book != null)
+{
+workBook = book!!.workBook
+}
+else
+{
+if (xfr.workBook != null)
+{
+workBook = xfr.workBook
+}
+else
+{
+Logger.logErr("FormatHandle constructed with null WorkBook.")
+}
+}
+}
+
+/**
+ * Constructs a FormatHandle for the given WorkBook's default format.
+*/
+constructor(book:io.starter.OpenXLS.WorkBook) : this(book, book.workBook.defaultIxfe) {}
+
+/**
+ * Constructs a FormatHandle for the given format ID and WorkBook.
+ * This is useful for creating a FormatHandle with the same parameters as
+ * a cell that does not refer to the cell. For example:
+ *
+ * CellHandle cell = <get cell here>;
+ * FormatHandle format = new FormatHandle(
+ * cell.getWorkBook(), cell.getFormatId() );
+ *
+ *
+ * @param book the WorkBook from which the format should be retrieved
+ * @param xfnum the ID of the format
+*/
+constructor(book:io.starter.formats.XLS.WorkBook, xfnum:Int) {
+workBook = book
+if (xfnum > -1 && xfnum < workBook!!.numXfs)
+{
+xf = workBook!!.getXf(xfnum)
+formatId = xf!!.idx
+}
+if (xf == null)
+{ // add new xf if necessary
+xf = duplicateXf(null)
+}
+xf!!.font // will set to default (0th) font if not already set
+}
+
+/** Constructs a FormatHandle for the given format ID and WorkBook.
+ * This is useful for creating a FormatHandle with the same parameters as
+ * a cell that does not refer to the cell. For example:
+ *
+ * CellHandle cell = <get cell here>;
+ * FormatHandle format = new FormatHandle(
+ * cell.getWorkBook(), cell.getFormatId() );
+ *
+ *
+ * @param book
+ * the WorkBook from which the format should be retrieved
+ * @param xfnum
+ * the ID of the format public FormatHandle(WorkBook book, int
+ * xfnum ,int x) { this(book.getWorkBook(),xfnum); wbh = book; }
+*/
+
+/**
+ * Constructs a FormatHandle for the given format index and WorkBook.
+ * **This is not part of the public API and should not be called.**
+*/
+/*
+ * This constructor is just used from XML parsing, due to some dedupe
+ * errors. possibly errors in .xlsx too?
+*/
+protected constructor(book:io.starter.OpenXLS.WorkBook, xfnum:Int,
+dedupe:Boolean) : this(book, xfnum) {
+writeImmediate = dedupe
+}
+
+/**
+ * Constructs a dummy FormatHandle for the given conditional format. **This
+ * is not part of the public API and should not be called.**
+ *
+ *
+ * This unique flavor of FormatHandle is only used to display the formatting
+ * values of a Conditional format record.
+ *
+ *
+ * Creates a dummy Xf to store values, otherwise has no effect on the
+ * WorkBook record stream which are manipulated through CellHandle.
+ *
+ * @param book containing the conditional formats
+ * @param the index to the conditional format in the book collection
+*/
+constructor(cx:Condfmt, book:io.starter.OpenXLS.WorkBook,
+xfnum:Int, c:CellHandle?) {
+var c = c
+cx.formatHandle = this
+formatId = xfnum
+wbh = book
+workBook = book.workBook
+if (c == null)
+{
+// ok, this is a horrible hack, as its only correct if the top left
+// cell of the range has the same background format
+// as the cell a user is hitting. Lame, but i've been handed this at
+// the last moment and am patching things. weak effort guys.
+try
+{
+val rc = cx.encompassingRange
+c = CellHandle(cx.sheet!!.getCell(rc[0], rc[1]),
+book)
+}
+catch (e:Exception) {}
+
+}
+xf = duplicateXf(book.workBook.getXf(c!!.formatId))
+
+// set the format from the cf
+val lx = cx.rules
+val itx = lx.iterator()
+while (itx.hasNext())
+{
+val format = itx.next() as Cf
+this.updateFromCF(format, book)
+}
+}
+
+/**
+ * updates this format handle via a Cf rule
+ *
+ * @param cf Cf rule
+ * @param book workbook
+*/
+fun updateFromCF(cf:Cf, book:io.starter.OpenXLS.WorkBook) {
+// border colors
+val clr = cf.borderColors
+if (clr != null)
+borderColors = clr
+
+// line style
+val xs = cf.borderStyles
+if (xs != null)
+this.setBorderLineStyle(xs)
+
+/*
+ * // cf.getBorderSizes() int[] b = cf.getBorderSizes(); if(b!=null)
+ * setBorderLineStyle(b);
+*/
+// cf.getFont()
+val f = cf.getFont()
+if (f != null)
+font = f
+else
+this.fontHeight = 180 // why????????
+
+if (cf.fontItalic)
+this.italic = true
+
+if (cf.fontStriken)
+this.stricken = true
+
+val fsup = cf.fontEscapement
+// super/sub (0 = none, 1 = super, 2 = sub)
+if (fsup > -1)
+this.setScript(fsup)
+
+// handle underlines
+val us = cf.getFontUnderlineStyle()
+
+if (us > -1)
+{
+this.underlineStyle = us
+this.setUnderlined(true)
+}
+
+// number cf
+if (cf.formatPattern != null)
+formatPattern = cf.formatPattern
+
+if (cf.fill != null)
+{
+this.setFill(cf.fill)
+}
+else
+{
+val fill = cf.getPatternFillStyle() // Now -1 is a valid entry:
+if (fill > -1)
+{
+/* If the fill style is solid: When solid is specified, the
+foreground color (fgColor) is the only color rendered,
+even when a background color (bgColor) is also
+specified. */
+val bg = cf.getPatternFillColorBack()
+val fg = cf.getPatternFillColor()
+this.setFill(fill, fg, bg)
+}
+else
+{
+val fg = cf.foregroundColor
+if (fg > -1)
+foregroundColor = fg
+}
+}
+}
+
+/**
+ * Creates a FormatHandle for the given cell. **This is not part of the
+ * public API and should not be called.** Customers should use
+ * [CellHandle.getFormatHandle] instead.
+*/
+constructor(c:CellHandle) {
+workBook = c.cell!!.workBook
+if (c.cell!!.xfRec != null)
+{
+xf = c.cell!!.xfRec
+formatId = xf!!.idx // update the pointer - 20071010 KSC
+}
+else
+{ // ?? create new
+// 20090512 KSC: Shigeo NPE error formaterror646694, create new
+// rather than outputting warning
+// Logger.logWarn("No XF for cell " + c.toString());
+xf = workBook!!.getXf(c.cell!!.ixfe)
+formatId = xf!!.idx
+}
+// 20101201 KSC: only add to cache when adding xf's addToCache();
+}
+
+/**
+ * overrides the equals method to perform equality based on format
+ * properties ------------------------------------------------------------
+ *
+ * @param Object another - the FormatHandle to compare with this FormatHandle
+ * @return true if this FormatHandle equals another
+*/
+public override fun equals(another:Any?):Boolean {
+return another!!.toString() == toString()
+}
+
+/**
+ * remove borders for this format
+*/
+fun removeBorders() {
+val xf = cloneXf(this.xf!!)
+xf.removeBorders()
+updateXf(xf)
+}
+
+/**
+ * sets the border color for all borders (top, left, bottom and right) from
+ * an int array containing color constants
+ *
+ *
+ *
+ * NOTE: this setting will affect every cell which refers to this
+ * FormatHandle
+ *
+ * @param int[] bordercolors - 4-element array of desired border color
+ * constants [T, L, B, R]
+ * @see FormatHandle.COLOR_* constants
+*/
+fun setBorderColors(bordercolors:IntArray) {
+val xf = cloneXf(this.xf!!)
+xf.topBorderColor = bordercolors[0]
+xf.leftBorderColor = bordercolors[1]
+xf.bottomBorderColor = bordercolors[2]
+xf.setRightBorderColor(bordercolors[3])
+updateXf(xf)
+
+}
+
+/**
+ * set the border color for all borders (top, left, bottom, and right) to
+ * one color via color constant
+ *
+ *
+ *
+ * NOTE: this setting will affect every cell which refers to this
+ * FormatHandle
+ *
+ * @param int x - color constant which represents the color to set all
+ * border sides
+ * @see FormatHandle.COLOR_* constants
+*/
+fun setBorderColor(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setRightBorderColor(x.toShort().toInt())
+xf.setLeftBorderColor(x.toShort())
+xf.topBorderColor = x.toShort()
+xf.bottomBorderColor = x.toShort()
+updateXf(xf)
+
+}
+
+/**
+ * set the border color for all borders (top, left, bottom, and right) to
+ * one java.awt.Color
+ *
+ *
+ * NOTE: this setting will affect every cell which refers to this
+ * FormatHandle
+ *
+ * @param Color col - color to set all border sides
+*/
+fun setBorderColor(col:Color) {
+val xf = cloneXf(this.xf!!)
+val x = getColorInt(col).toShort()
+xf.setRightBorderColor(x.toInt())
+xf.setLeftBorderColor(x)
+xf.topBorderColor = x
+xf.bottomBorderColor = x
+updateXf(xf)
+
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderRightColor(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setRightBorderColor(x.toShort().toInt())
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderRightColor(x:Color) {
+val xf = cloneXf(this.xf!!)
+xf.setRightBorderColor(getColorInt(x).toShort().toInt())
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderLeftColor(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setLeftBorderColor(x.toShort())
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderLeftColor(x:Color) {
+val xf = cloneXf(this.xf!!)
+xf.setLeftBorderColor(getColorInt(x).toShort())
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderTopColor(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.topBorderColor = x
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderTopColor(x:Color) {
+val xf = cloneXf(this.xf!!)
+xf.topBorderColor = getColorInt(x)
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderBottomColor(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.bottomBorderColor = x
+updateXf(xf)
+}
+
+/**
+ * Set the top border color
+ *
+ * @param color constant
+*/
+fun setBorderBottomColor(x:Color) {
+val xf = cloneXf(this.xf!!)
+xf.bottomBorderColor = getColorInt(x)
+updateXf(xf)
+}
+
+/**
+ * Sets the border line style using static BORDER_ shorts within
+ * FormatHandle
+ *
+ * @param line style constant
+*/
+fun setBorderLineStyle(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setBorderLineStyle(x.toShort())
+updateXf(xf)
+}
+
+/**
+ * set border line styles via array of ints representing border styles
+ * order= left, right, top, bottom, [diagonal]
+ *
+ * @param b int[]
+*/
+fun setBorderLineStyle(b:IntArray) {
+xf!!.setAllBorderLineStyles(b)
+}
+
+/**
+ * Set the border line style
+ *
+ * @param line style constant
+*/
+fun setBorderLineStyle(x:Short) {
+val xf = cloneXf(this.xf!!)
+xf.setBorderLineStyle(x)
+updateXf(xf)
+}
+
+/**
+ * Set the border line style
+ *
+ * @param line style constant
+*/
+fun setBorderDiagonal(x:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setBorderDiag(x)
+updateXf(xf)
+}
+
+/**
+ * Set a column handle on this format handle, so all changes applied to this
+ * format will be applied to the entire column
+ *
+ * @param c
+*/
+fun setColHandle(c:ColHandle) {
+mycol = c
+}
+
+/**
+ * Set a row handle on this format handle, so all changes applied to this
+ * format will be applied to the entire row
+ *
+ * @param c
+*/
+fun setRowHandle(c:RowHandle) {
+myrow = c
+}
+
+/**
+ * Create a copy of this FormatHandle with its own Xf
+ *
+ * @return the copied FormatHandle
+*/
+fun clone():Any {
+var ret:FormatHandle? = null
+if (wbh == null)
+{ // who knew???
+workBook = xf!!.workBook // Changed to myxf since myfont is no
+// longer
+ret = FormatHandle()
+ret!!.xf = xf
+ret!!.formatId = xf!!.idx
+ret!!.workBook = workBook
+}
+else
+{
+ret = FormatHandle(wbh, xf) // no need to duplicate it - just
+// use all formatting of
+// original xf
+}
+
+return ret
+}
+
+public override fun toString():String {
+return xf!!.toString()
+}
+
+constructor(book:io.starter.OpenXLS.WorkBook, fontname:String,
+fontstyle:Int, fontsize:Int) : this(book) {
+setFont(fontname, fontstyle, fontsize.toDouble())
+}
+
+/**
+ * Jan 27, 2011
+ *
+ * @param workBook
+ * @param i
+*/
+constructor(workBook:io.starter.OpenXLS.WorkBook, i:Int) : this(workBook.workBook, i) {
+wbh = workBook
+}
+
+/**
+ * Set new font to XF, handling duplication and caching ...
+ *
+ * @param Font f
+*/
+private fun setXFToFont(f:Font) {
+val fti = addFontIfNecessary(f)
+if (xf == null)
+{ // shouldn't!!
+xf = duplicateXf(null)
+xf!!.setFont(fti)
+}
+else if (xf!!.ifnt.toInt() != fti)
+{ // if not using font already,
+// duplicate xf and set to new font
+val xf = cloneXf(this.xf!!)
+xf.setFont(fti)
+updateXf(xf)
+}
+
+}
+
+/**
+ * Sets this format handle to a font
+ *
+ * @param fn font name e.g. 'Arial'
+ * @param stl font style either Font.PLAIN or Font.BOLD
+ * @param sz font size or height in 1/20 point units
+*/
+fun setFont(fn:String, stl:Int, sz:Double) {
+var stl = stl
+var sz = sz
+sz *= 20.0
+if (stl == 0)
+stl = 200
+if (stl == 1)
+stl = 700
+val f = Font(fn, stl, sz.toInt())
+setXFToFont(f)
+}
+
+/**
+ * add font to record streamer if cant find exact font already in there
+ *
+ * @param f
+ * @return
+*/
+private fun addFontIfNecessary(f:Font?):Int {
+if (workBook == null)
+{
+Logger.logErr("AddFontIfNecessary: workbook is null")
+return -1
+}
+var fti = workBook!!.getFontIdx(f)
+// don't use the built-ins.
+if (fti == 3)
+fti = 0 // use initial default font instead of last ...
+if (fti == -1)
+{ // font doesn't exist yet, add to streamer
+f!!.idx = -1 // flag to insert
+fti = workBook!!.insertFont(f) + 1
+}
+else
+f!!.idx = fti
+return fti
+}
+
+/**
+ * Adds a font internally to the workbook
+ *
+ * @param f
+ *
+ * private void addFont(Font f) {
+ *
+ * }
+*/
+
+/**
+ * Apply this Format to a Range of Cells
+ *
+ * @param CellRange to apply the format to
+*/
+fun addCellRange(cr:CellRange) {
+val crcells = cr.getCells()
+for (t in crcells!!.indices)
+{
+addCell(crcells!![t])
+}
+}
+
+/**
+ * Apply this Format to a Range of Cells
+ *
+ * @param CellHandle array to apply the format to
+*/
+fun addCellArray(crcells:Array) {
+for (t in crcells.indices)
+{
+addCell(crcells[t])
+}
+}
+
+/**
+ * add a Cell to this FormatHandle thus applying the Format to the Cell
+ *
+ * @param CellHandle to apply the format to
+*/
+fun addCell(c:CellHandle) {
+c.formatHandle = this
+}
+
+/**
+ * Add a List of Cells to this FormatHandle
+ *
+ * @param cx
+*/
+fun addCells(cx:List<*>) {
+val itx = cx.iterator()
+while (itx.hasNext())
+{
+addCell(itx.next() as BiffRec)
+mycells.add(itx.next())
+}
+}
+
+internal fun addCell(c:BiffRec) {
+if (xf != null)
+{
+c.setXFRecord(xf!!.idx)
+}
+else
+{
+Logger.logWarn("FormatHandle.addCell() - You MUST call setFont() to initialize the FormatHandle's font before adding Cells.")
+}
+mycells.add(c)
+}
+
+/**
+ * Applies the format to a cell without establishing a relationship. The
+ * format represented by this `FormatHandle` will be applied to
+ * the cell but it will not be updated with any future changes. If you want
+ * that behavior use [addCell][.addCell] instead.
+*/
+fun stamp(cell:CellHandle) {
+cell.formatId = formatId
+}
+
+/**
+ * Applies the format to a cell range without establishing a relationship.
+ * The format represented by this `FormatHandle` will be applied
+ * to the cells but they will not be updated with any future changes. If you
+ * want that behavior use [addCell][.addCell] instead.
+*/
+fun stamp(range:CellRange) {
+try
+{
+range.setFormatID(formatId)
+}
+catch (e:Exception) {
+// This can't actually happen
+}
+
+}
+
+/**
+ * set the Background Pattern for this Format
+ *
+ * @param int Excel color constant
+*/
+fun setBackgroundPattern(t:Int) {
+val xf = cloneXf(this.xf!!)
+// 20080103 KSC: handle solid (=filled) backgrounds, in which Excel
+// switches fg and bg colors (!!!)
+if (t != FormatConstants.PATTERN_FILLED)
+xf.setPattern(t)
+else
+{
+val bg = xf.backgroundColor.toInt()
+xf.setBackgroundSolid()
+xf.setForeColor(bg, null)
+}
+updateXf(xf)
+}
+
+/**
+ * super/sub (0 = none, 1 = super, 2 = sub)
+ *
+ * @param int script type for Format Font
+*/
+fun setScript(ss:Int) {
+var ss = ss
+if (ss > 2)
+ss = 2 // deal with invalid numbers
+if (ss < 0)
+ss = 0 // deal with invalid numbers
+xf!!.font!!.script = ss
+}
+
+/**
+ * set the Font Color for this Format via indexed color constant
+ *
+ * @param int Excel color constant
+*/
+fun setFontColor(t:Int) {
+val f = cloneFont(xf!!.font!!)
+f.color = t
+updateFont(f)
+}
+
+/**
+ * set the Font Color for this Format
+ *
+ * @param AWT Color color constant
+*/
+fun setFontColor(colr:Color) {
+val f = cloneFont(xf!!.font!!)
+f.setColor(colr)
+updateFont(f)
+}
+
+/**
+ * sets the Font color for this Format via web Hex String
+ *
+ * @param clr
+*/
+fun setFontColor(clr:String) {
+val f = cloneFont(xf!!.font!!)
+f.setColor(clr)
+updateFont(f)
+}
+
+/**
+ * set the foreground Color for this Format NOTE: Foreground color = the
+ * CELL BACKGROUND color color for all patterns and Background color= the
+ * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
+ * color=CELL BACKGROUND color and Background Color=64 (white).
+ *
+ * @param AWT Color constant
+*/
+fun setForegroundColor(colr:Color) {
+val xf = cloneXf(this.xf!!)
+val clrz = getColorInt(colr)
+xf.setForeColor(clrz, colr)
+updateXf(xf)
+}
+
+/**
+ * set the Cell Background Color for this Format
+ *
+ *
+ * NOTE: Foreground color = the CELL BACKGROUND color color for all patterns
+ * and Background color= the PATTERN color for all patterns != Solid For
+ * PATTERN_SOLID, Foreground color=CELL BACKGROUND color and Background
+ * Color=64 (white).
+ *
+ * @param awt Color color constant
+*/
+fun setCellBackgroundColor(colr:Color) {
+val clrz = getColorInt(colr)
+setCellBackgroundColor(clrz)
+
+}
+
+/**
+ * makes the cell a solid pattern background if no pattern was already
+ * present NOTE: Foreground color = the CELL BACKGROUND color color for all
+ * patterns and Background color= the PATTERN color for all patterns !=
+ * Solid For PATTERN_SOLID, Foreground color=CELL BACKGROUND color and
+ * Background Color=64 (white).
+ *
+ * @param int Excel color constant
+*/
+fun setCellBackgroundColor(t:Int) {
+val xf = cloneXf(this.xf!!)
+
+if (xf.fillPattern == 0)
+xf.setBackgroundSolid()
+
+if (xf.fillPattern == Xf.PATTERN_SOLID)
+xf.setForeColor(t, null)
+else
+xf.setBackColor(t, null)
+updateXf(xf)
+}
+
+/**
+ * sets this fill pattern from an existing OOXML (2007v) fill element
+ *
+ * @param f
+*/
+protected fun setFill(f:Fill?) {
+val xf = cloneXf(this.xf!!)
+xf.setFill(f!!)
+updateXf(xf)
+}
+
+/**
+ * sets the fill for this format handle if fill==Xf.PATTERN_SOLID then fg is
+ * the PATTERN color i.e the CELL BG COLOR
+ *
+ * @param fillpattern
+ * @param fg
+ * @param bg
+*/
+fun setFill(fillpattern:Int, fg:Int, bg:Int) {
+val xf = cloneXf(this.xf!!)
+
+xf.setPattern(fillpattern)
+
+/**
+ * If the fill style is solid: When solid is specified, the foreground
+ * color (fgColor) is the only color rendered, even when a background
+ * color (bgColor) is also specified.
+*/
+if (xf.fillPattern == Xf.PATTERN_SOLID)
+{ // is reversed
+xf.setForeColor(bg, null)
+xf.setBackColor(64, null)
+}
+else
+{
+/**
+ * or cell fills with patterns specified, then the cell fill color
+ * is specified by the bgColor element
+*/
+xf.setForeColor(fg, null)
+xf.setBackColor(bg, null)
+}
+updateXf(xf)
+}
+
+/**
+ * set the Background Color for this Format NOTE: Foreground color = the
+ * CELL BACKGROUND color color for all patterns and Background color= the
+ * PATTERN color for all patterns != Solid For PATTERN_SOLID, Foreground
+ * color=CELL BACKGROUND color and Background Color=64 (white).
+ *
+ * @param awt Color color constant
+*/
+fun setBackgroundColor(colr:Color) {
+val xf = cloneXf(this.xf!!)
+val clrz = getColorInt(colr)
+xf.setBackColor(clrz, colr)
+updateXf(xf)
+}
+
+/**
+ * Get if the font is underlined
+ *
+ * @return boolean representing if the formatted cell is underlined.
+*/
+fun getUnderlined():Boolean {
+if (xf!!.font == null)
+return underlined
+return xf!!.font!!.underlined
+}
+
+/**
+ * Set underline attribute on the font
+ *
+ * @param isUnderlined boolean representing if the formatted cell should be
+ * underlined
+*/
+fun setUnderlined(isUnderlined:Boolean) {
+val f = cloneFont(xf!!.font!!)
+f.underlined = isUnderlined
+updateFont(f)
+
+}
+
+fun setPattern(pat:Int) {
+val xf = cloneXf(this.xf!!)
+xf.setPattern(pat)
+updateXf(xf)
+}
+
+/**
+ * increase or decrease the precision of this numeric or curerncy format pattern
+ * If the format pattern is "General", converts to a basic number pattern
+ * If the precision is already 0 and !increase, this method does nothing
+ *
+ * @param increase true if increase the precsion (number of decimals to display)
+*/
+fun adjustPrecision(increase:Boolean) {
+// TODO: if decimal is contained within quotes ...
+var pat = formatPattern
+if (pat == "General" && increase)
+{
+pat = "0.0" // the most basic numeric pattern
+this.formatPattern = pat
+return
+}
+
+try
+{
+// split pattern and deal with positive, negative, zero and text separately
+// for each, find decimal place and increment/decrement; if not found, find last digit placeholder
+val pats = pat!!.split((";").toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
+var newPat = ""
+for (i in pats.indices)
+{
+if (i > 0) newPat += ';'.toString()
+var z = pats[i].indexOf('.') // position of decimal
+var foundit = false
+if (z != -1)
+{ // found decimal place
+z++
+while (z < pats[i].length)
+{
+val c = pats[i].get(z)
+if ((c == '0' || c == '#' || c == '?'))
+// numeric placeholders
+foundit = true
+else if (foundit && !(c == '0' || c == '#' || c == '?'))
+// numeric placeholders. if hit last one, either inc or dec
+break
+z++
+}
+if (increase)
+newPat += StringBuffer(pats[i]).insert(z, "0").toString() //pats[i].substring(0, z) + "0" + pats[i].substring(z+1);
+else
+{
+if (pats[i].get(z - 2) != '.')
+{
+newPat += StringBuffer(pats[i]).deleteCharAt(z - 1).toString() // .pats[i].substring(0, z-1) + pats[i].substring(z+1);
+}
+else
+{
+newPat += StringBuffer(pats[i]).delete(z - 2, z).toString()
+}
+}
+
+}
+else if (increase)
+{ // no decimal yet. If decrease, ignore. if increase, add
+z = pats[i].length - 1
+while (z >= 0)
+{
+val c = pats[i].get(z)
+if ((c == '0' || c == '#' || c == '?'))
+{ // found last numeric placeholder
+foundit = true
+break
+}
+z--
+}
+if (foundit)
+// if had ANY numeric placeholders
+newPat += StringBuffer(pats[i]).insert(z + 1, ".0").toString() //pats[i].substring(0, z) + ".0" + pats[i].substring(z+1);
+else
+newPat += pats[i] // keep original
+}
+else
+// if decrease and no decimal found, leave alone
+newPat += pats[i] // leave alone
+}
+
+//io.starter.toolkit.Logger.log("Old Style" + pat + ". New Style: " + newPat + ". Increase?" + (increase?"yes":"no")); // KSC: TESETING: TAKE OUT WHEN DONE
+this.formatPattern = newPat
+}
+catch (e:Exception) {
+Logger.logErr("Error setting style") // KSC: TESETING: TAKE OUT WHEN DONE
+}
+
+}
+
+/**
+ * sets the Right to Left Text Direction or reading order of this style
+ *
+ * @param rtl possible values:
+ * 0=Context Dependent
+ * 1=Left-to-Right
+ * 2=Right-to-Let
+ * @param rtl possible values:
+ * 0=Context Dependent
+ * 1=Left-to-Right
+ * 2=Right-to-Let
+*/
+fun setRightToLeftReadingOrder(rtl:Int) {
+val xf = cloneXf(this.xf!!)
+xf.rightToLeftReadingOrder = rtl
+updateXf(xf)
+}
+
+/**
+ * DEPRECATED and non functional. Not neccesary as this occurs automatically
+ *
+ *
+ * Consolidates this Format with other identical formats in workbook
+ *
+ *
+ *
+ *
+ * There is a limit to the number of distinct formats in an Excel workbook.
+ *
+ *
+ * This method allows you to share Formats between identically formatted
+ * cells.
+ *
+ * @return
+*/
+@Deprecated("")
+fun pack():FormatHandle {
+return this // wkbook.cache.get(this);
+}
+
+/**
+ * Get a JSON representation of the format
+ *
+ * @param cr
+ * @return
+*/
+fun getJSON(XFNum:Int):String {
+return getJSONObject(XFNum).toString()
+}
+
+/**
+ * Get a JSON representation of the format
+ *
+ *
+ * font height is represented as HTML pt size
+ *
+ * @param cr
+ * @return
+*/
+fun getJSONObject(XFNum:Int):JSONObject {
+val myf = font
+val theStyle = JSONObject()
+try
+{
+theStyle.put("style", XFNum)
+// handle the font
+val theFont = JSONObject()
+theFont.put("name", myf!!.getFontName())
+
+// round out the font size...
+val sz = Math.round(myf!!.fontHeight / 22.0)
+
+theFont.put("size", sz) // adjust smaller
+theFont.put("color", colorToHexString(myf!!.colorAsColor))
+theFont.put("weight", myf!!.fontWeight)
+if (isBold)
+{
+theFont.put("bold", "1")
+}
+if (this.getUnderlined())
+{
+theFont.put("underline", "1")
+}
+else
+{
+theFont.put("underline", "0")
+}
+
+if (italic)
+{
+theFont.put("italic", "1")
+}
+
+theStyle.put("font", theFont)
+
+//
+val border = JSONObject()
+if (rightBorderLineStyle != 0)
+{
+val rBorder = JSONObject()
+rBorder.put("style",
+FormatConstants.BORDER_STYLES_JSON[rightBorderLineStyle])
+rBorder.put("color", colorToHexString(borderRightColor!!))
+border.put("right", rBorder)
+}
+if (bottomBorderLineStyle != 0)
+{
+val bBorder = JSONObject()
+bBorder.put("style",
+FormatConstants.BORDER_STYLES_JSON[bottomBorderLineStyle])
+bBorder.put("color", colorToHexString(borderBottomColor!!))
+border.put("bottom", bBorder)
+}
+if (leftBorderLineStyle != 0)
+{
+val lBorder = JSONObject()
+lBorder.put("style",
+FormatConstants.BORDER_STYLES_JSON[leftBorderLineStyle])
+lBorder.put("color", colorToHexString(borderLeftColor!!))
+border.put("left", lBorder)
+}
+if (topBorderLineStyle != 0)
+{
+val tBorder = JSONObject()
+tBorder.put("style",
+FormatConstants.BORDER_STYLES_JSON[topBorderLineStyle])
+tBorder.put("color", colorToHexString(borderTopColor!!))
+border.put("top", tBorder)
+}
+theStyle.put("borders", border)
+
+//
+val alignment = JSONObject()
+alignment.put("horizontal",
+FormatConstants.HORIZONTAL_ALIGNMENTS[horizontalAlignment])
+alignment.put("vertical",
+FormatConstants.VERTICAL_ALIGNMENTS[verticalAlignment])
+if (wrapText)
+{
+alignment.put("wrap", "1")
+}
+theStyle.put("alignment", alignment)
+
+if (indent != 0)
+{
+theStyle.put("indent", indent)
+}
+// colors + background patterns
+if (fillPattern >= 0)
+{ // KSC: added >= 0 as some conditional formats have patternFillStyle==0 even though they have a pattern block and
+val interior = JSONObject()
+// weird black/white case
+if (xf!!.foregroundColor.toInt() == 65)
+{
+interior.put("color", "#FFFFFF")
+}
+else
+{
+// KSC: use color string if it exists; create if doesn't
+interior.put("color", xf!!.foregroundColorHEX)
+}
+interior.put("pattern", xf!!.fillPattern)
+interior.put("fg", xf!!.foregroundColor.toInt()) // Excel-2003 Color Table index
+interior.put("patterncolor", xf!!.backgroundColorHEX)
+interior.put("bg", xf!!.backgroundColor.toInt()) // Excel-2003 Color Table index
+theStyle.put("interior", interior)
+}
+
+if (xf!!.ifmt.toInt() != 0)
+{ // only input user defined formats ...
+val nFormat = JSONObject()
+val fmtpat = formatPattern
+try
+{
+if (fmtpat != "General")
+{
+nFormat.put("format", fmtpat) // convertXMLChars?
+nFormat.put("formatid", xf!!.ifmt.toInt())
+if (isDate)
+nFormat.put("isdate", "1")
+if (isCurrency)
+nFormat.put("iscurrency", "1")
+if (isRedWhenNegative)
+nFormat.put("isrednegative", "1")
+}
+
+}
+catch (e:Exception) { // it's possible that getFormatPattern
+// returns null
+}
+
+theStyle.put("numberformat", nFormat)
+}
+//
+val protection = JSONObject()
+try
+{
+if (this.xf!!.isLocked)
+protection.put("Protected", true)
+if (this.xf!!.isFormulaHidden)
+protection.put("HideFormula", true)
+}
+catch (e:Exception) {}
+
+theStyle.put("protection", protection)
+
+}
+catch (e:JSONException) {
+Logger.logErr("Error getting cellRange JSON: " + e)
+}
+
+return theStyle
+}
+
+/**
+ * Returns an XML fragment representing the FormatHandle
+ *
+ * @param convertToUnicodeFont if true, font family will be changed to ArialUnicodeMS
+ * (standard unicode) for non-ascii fonts
+*/
+@JvmOverloads fun getXML(XFNum:Int, convertToUnicodeFont:Boolean = false):String {
+val myf = font
+// ")
+return sb.toString()
+}
+
+/**
+ * creates a new font based on an existing one, adds to workbook recs
+*/
+private fun createNewFont(f:Font):Font {
+f.idx = -1 // flag to insert anew (see Font.setWorkBook)
+workBook!!.insertFont(f)
+f.workBook = workBook
+return f
+}
+
+/**
+ * create a new font based on existing font - does not add to workbook recs
+ *
+ * @param src font
+ * @return cloned font
+*/
+private fun cloneFont(src:Font):Font {
+val f = Font()
+f.opcode = io.starter.formats.XLS.XLSConstants.FONT
+f.setData(src.bytes) // use default font as basis of new font
+f.idx = -2 // avoid adding to fonts array when call setW.b. below
+f.workBook = this.workBook
+f.init()
+return f
+}
+
+/**
+ * update the font for this FormatHandle, including updating the xf if
+ * necessary
+ *
+ * @param f
+*/
+private fun updateFont(f:Font) {
+var f = f
+val idx = workBook!!.getFontIdx(f)
+if (idx == -1)
+{ // can't find it so add new
+f = createNewFont(f)
+}
+else
+f = workBook!!.getFont(idx)
+if (f.idx != xf!!.ifnt.toInt())
+{ // then updated the font, must create new xf to link to
+val xf = cloneXf(this.xf!!)
+xf.setFont(f.idx)
+updateXf(xf)
+}
+}
+
+/**
+ * Create or Duplicate Xf rec so can alter (pattern, font, colrs ...)
+ *
+ * @param xf xf to base off of, or null (will create new)
+ * @return new Xf
+*/
+private fun duplicateXf(xf:Xf?):Xf {
+var xf = xf
+var fidx = 0
+if (xf != null)
+fidx = xf!!.font!!.idx
+xf = Xf.updateXf(xf, fidx, workBook) // clones/creates new based upon
+// original
+formatId = xf!!.idx // update the pointer
+// not used anymore canModify = true; // if duplicated, it's new and unlinked (thus far)
+return xf
+}
+
+/**
+ * adds all formatting represented by the sourceXf to this workbook, if not
+ * already present
+ * This is used internally for transferring formats from one workbook to
+ * another
+ *
+ * @param xf - sourceXf
+ * @return ixfe of added Xf
+*/
+fun addXf(sourceXf:Xf):Int {
+// must handle font first in order to create xf below
+// check to see if the font needs to be added in current workbook
+val fidx = addFontIfNecessary(sourceXf.font)
+
+/** XF */
+val localXf = FormatHandle.cloneXf(sourceXf, workBook!!.getFont(fidx),
+workBook) // clone xf so modifcations don't affect original
+
+/** NUMBER FORMAT */
+val fmt = sourceXf.formatPattern // number format pattern
+if (fmt != null)
+localXf.formatPattern = fmt // adds new format pattern if not // found
+
+// now check out to see if this particular xf pattern exists; if not, add
+updateXf(localXf)
+return formatId
+}
+
+/**
+ * if existing format matches, reuse. otherwise, create new Xf record and
+ * add to cache
+ *
+ * @param xf
+*/
+private fun updateXf(xf:Xf) {
+if (this.xf!!.toString() != xf.toString())
+{
+if (this.xf!!.useCount <= 1 && formatId > 15)
+{ // used only by one cell, OK to modify
+if (writeImmediate || workBook!!.formatCache.get(xf.toString()) == null)
+{
+// myxf hasn't been used yet; modify bytes and re-init ***
+val xfbytes = xf.bytes
+this.xf!!.setData(xfbytes)
+if (xf.fill != null)
+this.xf!!.fill = xf.fill!!.cloneElement() as io.starter.formats.OOXML.Fill
+this.xf!!.init()
+this.xf!!.setFont(this.xf!!.ifnt.toInt()) // set font as well ..
+workBook!!.updateFormatCache(this.xf!!) // ensure new xf signature
+// is stored
+}
+else
+{
+if (this.xf!!.useCount > 0)
+this.xf!!.decUseCoount() // flag original xf that 1 less record is referencing it
+this.xf = workBook!!.formatCache.get(xf.toString()) as Xf
+formatId = this.xf!!.idx // update the pointer
+if (formatId == -1)
+// hasn't been added to wb yet - should this ever happen???
+this.xf = duplicateXf(xf) // create a duplicate and leave original
+else
+this.xf!!.incUseCount()
+}
+}
+else
+{ // cannot modify original - either find matching or create new
+if (this.xf!!.useCount > 0)
+this.xf!!.decUseCoount() // flag original xf that 1 less record is referencing it
+if (workBook!!.formatCache.get(xf.toString()) == null)
+{ // doesn't exist yet
+this.xf = duplicateXf(xf) // create a duplicate and leave original
+}
+else
+{
+this.xf = (workBook!!.formatCache.get(xf.toString())) as Xf
+formatId = this.xf!!.idx // update the pointer
+if (formatId == -1)
+// hasn't been added to the record store yet // - should ever happen???
+this.xf = duplicateXf(xf) // create a duplicate and leave original
+else
+this.xf!!.incUseCount()
+}
+}
+
+for (i in mycells.indices)
+{
+(mycells.get(i) as BiffRec).setXFRecord(formatId) // make sure all linked cells are updated as well
+}
+if (mycol != null)
+mycol!!.formatId = formatId
+if (myrow != null)
+myrow!!.formatId = formatId
+}
+}
+
+/**
+ * create a duplicate xf rec based on existing ...
+ *
+ * @param xf
+ * @return cloned xf
+*/
+private fun cloneXf(xf:Xf):Xf {
+val clone = Xf(xf.font!!.idx, workBook)
+val data = xf.getBytesAt(0, xf.length - 4)
+clone.setData(data)
+if (xf.fill != null)
+clone.fill = xf.fill!!.cloneElement() as io.starter.formats.OOXML.Fill
+clone.init()
+return clone
+}
+
+/**
+ * clear out object references
+*/
+fun close() {
+mycells.clear()
+mycells = CompatibleVector() // all the Cells sharing this format
+xf = null
+mycol = null
+myrow = null
+workBook = null
+wbh = null
+}
+
+@Throws(Throwable::class)
+protected fun finalize() {
+try
+{
+close() // close open files
+}
+
+finally
+{
+super.finalize()
+}
+}
+
+companion object {
+
+val numericFormatMap:Map
+val currencyFormatMap:Map
+val dateFormatMap:Map
+
+init{
+val formats = HashMap()
+for (formatArr in FormatConstants.NUMERIC_FORMATS)
+{
+if (formatArr.size == 3)
+{
+formats.put(formatArr[0].toLowerCase(), formatArr[2])
+}
+}
+numericFormatMap = Collections.unmodifiableMap(formats)
+
+formats = HashMap()
+for (formatArr in FormatConstants.CURRENCY_FORMATS)
+{
+if (formatArr.size == 3)
+{
+formats.put(formatArr[0].toLowerCase(), formatArr[2])
+}
+}
+currencyFormatMap = Collections.unmodifiableMap(formats)
+
+formats = HashMap()
+for (formatArr in FormatConstants.DATE_FORMATS)
+{
+if (formatArr.size == 3)
+{
+formats.put(formatArr[0].toLowerCase(), formatArr[2])
+}
+else
+{
+// only 2 elements in date format string array: pattern and hex id
+formats.put(formatArr[0].toLowerCase(), formatArr[0])
+}
+}
+dateFormatMap = Collections.unmodifiableMap(formats)
+}
+
+/**
+ * converts an Excel-style format string to a Java Format string.
+ *
+ * @param String pattern - Excel Format String
+ * @return String that can be used with the Java Format classes.
+ * @see getJavaFormatString
+*/
+fun convertFormatString(pattern:String):String? {
+var ret:String? = numericFormatMap.get(pattern)
+if (ret != null)
+return ret
+ret = currencyFormatMap.get(pattern)
+if (ret != null)
+return ret
+ret = dateFormatMap.get(pattern)
+return ret
+}
+
+/**
+ * adds a font to the global font store only if exact font is not already
+ * present
+ *
+ * @param f Font
+ * @param bk WorkBookHandle
+*/
+fun addFont(f:Font, bk:WorkBookHandle?):Int {
+if (bk == null)
+{
+Logger.logErr("addFont: workbook is null")
+}
+var fti = bk!!.workBook!!.getFontIdx(f)
+// if (fti > 3) {// don't use the built-ins.
+if (fti == 3)
+fti = 0 // use initial default font instead of last ... 20070827
+// KSC
+if (fti == -1)
+{ // font doesn't exist yet, add to streamer
+f.idx = -1 // flag to insert
+fti = bk!!.workBook!!.insertFont(f) + 1
+}
+else
+f.idx = fti
+return fti
+}
+
+/**
+ * returns the index of the Color within the Colortable
+ *
+ * @param the index of the color in the colortable
+ * @return the color
+*/
+fun getColor(col:Int):Color {
+if (col > -1 && col < FormatHandle.COLORTABLE.size)
+return FormatHandle.COLORTABLE[col]
+return FormatHandle.COLORTABLE[0]
+}
+
+/**
+ * returns the index of the Color within the Colortable
+ *
+ * @param col the color
+ * @return the index of the color in the colortable
+*/
+fun getColorInt(col:Color):Int {
+for (i in FormatHandle.COLORTABLE.indices)
+{
+if (col == FormatHandle.COLORTABLE[i])
+{
+return i
+}
+}
+val R = col.getRed()
+val G = col.getGreen()
+val B = col.getBlue()
+var colorMatch = -1
+var colorDiff = Integer.MAX_VALUE.toDouble()
+for (i in FormatHandle.COLORTABLE.indices)
+{
+val curDif = (Math.pow((R - FormatHandle.COLORTABLE[i].getRed()).toDouble(), 2.0)
++ Math.pow((G - FormatHandle.COLORTABLE[i].getGreen()).toDouble(), 2.0)
++ Math.pow((B - FormatHandle.COLORTABLE[i].getBlue()).toDouble(), 2.0))
+if (curDif < colorDiff)
+{
+colorDiff = curDif
+colorMatch = i
+}
+}
+return colorMatch
+}
+
+/**
+ * Convert a java.awt.Color to a hex string.
+ *
+ * @return String representation of a Color
+*/
+fun colorToHexString(c:Color):String {
+val r = c.getRed()
+val g = c.getGreen()
+val b = c.getBlue()
+var rh = Integer.toHexString(r)
+if (rh.length < 2)
+{
+rh = "0" + rh
+}
+var gh = Integer.toHexString(g)
+if (gh.length < 2)
+{
+gh = "0" + gh
+}
+var bh = Integer.toHexString(b)
+if (bh.length < 2)
+{
+bh = "0" + bh
+}
+return ("#" + rh + gh + bh).toUpperCase()
+}
+
+
+var colorFONT:Short = 0
+var colorBACKGROUND:Short = 1
+var colorFOREGROUND:Short = 2
+var colorBORDER:Short = 3
+
+/**
+ * convert hex string RGB to Excel colortable int format if an exact match
+ * is not find, does color-matching to try and obtain closest match
+ *
+ * @param s
+ * @param colorType
+ * @return
+*/
+fun HexStringToColorInt(s:String, colorType:Short):Int {
+var s = s
+if (s.length > 7)
+s = "#" + s.substring(s.length - 6)
+if (s.indexOf("#") == -1)
+s = "#" + s
+if (s.length == 7)
+{
+val rs = s.substring(1, 3)
+val r = Integer.parseInt(rs, 16)
+val gs = s.substring(3, 5)
+val g = Integer.parseInt(gs, 16)
+val bs = s.substring(5, 7)
+val b = Integer.parseInt(bs, 16)
+// Handle exceptions for black, white and color indexes 9 (see
+// FormatConstants for more info)
+
+if (r == 255 && r == g && r == b)
+{
+if (colorType == colorFONT)
+return 9
+}
+
+val c = Color(r, g, b)
+return getColorInt(c)
+}
+return 0
+}
+
+/**
+ * convert hex string RGB to Excel colortable int format if no exact match
+ * is found returns -1
+ *
+ * @param s HTML color string (#XXXXXX) format or (#FFXXXXXX - OOXML-style
+ * format)
+ * @param colorType
+ * @return index into color table or -1 if not found
+*/
+fun HexStringToColorIntExact(s:String, colorType:Short):Int {
+var s = s
+if (s.length > 7)
+s = "#" + s.substring(s.length - 6)
+if (s.indexOf("#") == -1)
+s = "#" + s
+if (s.length == 7)
+{
+val rs = s.substring(1, 3)
+val r = Integer.parseInt(rs, 16)
+val gs = s.substring(3, 5)
+val g = Integer.parseInt(gs, 16)
+val bs = s.substring(5, 7)
+val b = Integer.parseInt(bs, 16)
+
+// Handle exceptions for black, white and color indexes 9 (see
+// FormatConstants for more info)
+if (r == 255 && r == g && r == b)
+{
+if (colorType == colorFONT)
+return 9
+}
+
+val c = Color(r, g, b)
+for (i in FormatHandle.COLORTABLE.indices)
+{
+if (c == FormatHandle.COLORTABLE[i])
+{
+return i
+}
+}
+}
+return -1 // match NOT FOUND
+}
+
+/**
+ * convert hex string RGB to a Color
+ *
+ * @param s web-style hex color string, including #, or OOXML-style color string, FFXXXXXX
+ * @return Color
+ * @see Color
+*/
+fun HexStringToColor(s:String):Color {
+var s = s
+if (s.length > 7)
+{ // transform OOXML-style color strings to Web-style
+s = "#" + s.substring(s.length - 6)
+}
+var c:Color? = null
+if (s.length == 7)
+{
+val rs = s.substring(1, 3)
+val r = Integer.parseInt(rs, 16)
+val gs = s.substring(3, 5)
+val g = Integer.parseInt(gs, 16)
+val bs = s.substring(5, 7)
+val b = Integer.parseInt(bs, 16)
+c = Color(r, g, b)
+}
+else
+c = Color(0, 0, 0) // default to black?
+return c
+}
+
+/**
+ * interpret color table special entries
+ *
+ * @param clr color index in range of 0x41-0x4F (charts) 0x40 ...
+ * @return index into color table
+*/
+fun interpretSpecialColorIndex(clr:Int):Short {
+when (clr) {
+0x0041 // Default background color. This is the window background
+,
+// color in the sheet display and is the default
+// background color for a cell.
+0x004E // Default chart background color. This is the window
+,
+// background color in the chart display.
+0x0050 // WHAT IS THIS ONE????????
+-> return FormatConstants.COLOR_WHITE.toShort()
+0x0040 // Default foreground color
+, 0x004F // Chart neutral color which is black, an RGB value of
+,
+// (0,0,0).
+0x004D // Default chart foreground color. This is the window text
+,
+// color in the chart display.
+0x0051 // ToolTip text color. This is the automatic font color for
+,
+// comments.
+0x7FFF // Font automatic color. This is the window text color
+-> return FormatConstants.COLOR_BLACK.toShort()
+else // 67(=0x43) ???
+-> return FormatConstants.COLOR_WHITE.toShort()
+}
+
+/*
+ * switch (icvFore) { case 0x40: // default fg color return
+ * FormatConstants.COLOR_WHITE; case 0x41: // default bg color return
+ * FormatConstants.COLOR_WHITE; case 0x4D: // default CHART fg color --
+ * INDEX SPECIFIC! return -1; // flag to map via series (bar) color
+ * defaults case 0x4E: // default CHART fg color return icvFore; case
+ * 0x4F: // chart neutral color == black return
+ * FormatConstants.COLOR_BLACK; }
+ *
+ * switch (icvBack) { case 0x40: // default fg color return
+ * FormatConstants.COLOR_WHITE; case 0x41: // default bg color return
+ * FormatConstants.COLOR_WHITE; case 0x4D: // default CHART fg color --
+ * INDEX SPECIFIC! return -1; // flag to map via series (bar) color
+ * defaults case 0x4E: // default CHART bg color //return
+ * FormatConstants.COLOR_WHITE; // is this correct? return icvBack; case
+ * 0x4F: // chart neutral color == black return
+ * FormatConstants.COLOR_BLACK; }
+*/
+}
+
+fun BorderStringToInt(s:String):Int {
+for (i in FormatConstants.BORDER_NAMES.indices)
+{
+if (FormatConstants.BORDER_NAMES[i] == s)
+return i
+}
+return 0
+}
+
+/**
+ * static version of cloneXf
+ *
+ * @param xf
+ * @param wkbook
+ * @return
+*/
+fun cloneXf(xf:Xf, wkbook:io.starter.formats.XLS.WorkBook):Xf {
+val clone = Xf(xf.font!!.idx, wkbook)
+val data = xf.getBytesAt(0, xf.length - 4)
+clone.setData(data)
+clone.init()
+return clone
+}
+
+/**
+ * static version of cloneXf
+ *
+ * @param xf
+ * @param wkbook
+ * @return
+*/
+fun cloneXf(xf:Xf, f:Font,
+wkbook:io.starter.formats.XLS.WorkBook):Xf {
+val clone = Xf(f, wkbook)
+val data = xf.getBytesAt(0, xf.length - 4)
+clone.setData(data)
+clone.setFont(f.idx) // font idx is overwritten by xf data; must reset
+clone.init()
+return clone
+}
+}
+}/**
+ * Returns an XML fragment representing the FormatHandle
+ */
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/FormulaHandle.java b/src/main/java/io/starter/OpenXLS/FormulaHandle.java
deleted file mode 100644
index 4a662f9..0000000
--- a/src/main/java/io/starter/OpenXLS/FormulaHandle.java
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-import java.util.Iterator;
-import java.util.List;
-
-import io.starter.formats.XLS.*;
-import io.starter.formats.XLS.formulas.CalculationException;
-import io.starter.formats.XLS.formulas.FunctionConstants;
-import io.starter.formats.XLS.formulas.Ptg;
-import io.starter.formats.XLS.formulas.PtgArea;
-import io.starter.formats.XLS.formulas.PtgName;
-import io.starter.formats.XLS.formulas.PtgRef;
-import io.starter.formats.XLS.formulas.FormulaParser;
-import io.starter.toolkit.Logger;
-
-
-
-/** Formula Handle allows for manipulation of Formulas within a WorkBook.
-
- @see WorkBookHandle
- @see WorkSheetHandle
- @see CellHandle
-*/
-public class FormulaHandle
-{
- public static String[][] getSupportedFunctions() {
- return FunctionConstants.recArr;
- }
-
- private WorkBook bk;
-
- /** Sets the location lock on the Cell Reference at the
- * specified location
- *
- * Used to prevent updating of the Cell Reference when
- * Cells are moved.
- *
- * @param location of the Cell Reference to be locked/unlocked
- * @param lock status setting
- * @return boolean whether the Cell Reference was found and modified
- */
- public boolean setLocationLocked(String loc, boolean l){
- int x = Ptg.PTG_LOCATION_POLICY_UNLOCKED;
- if(l)x = Ptg.PTG_LOCATION_POLICY_LOCKED;
- return form.setLocationPolicy(loc, x);
- }
-
- private Formula form;
-
- /** Sets the location lock on the Cell Reference at the
- * specified location
- *
- * Used to prevent updating of the Cell Reference when
- * Cells are moved.
- *
- * @param location of the Cell Reference to be locked/unlocked
- * @param lock status setting
- * @return boolean whether the Cell Reference was found and modified
- */
- public boolean setLocationPolicy(String loc, int l){
- return form.setLocationPolicy(loc,l);
- }
-
- /** Create a new FormulaHandle from an Excel Formula
-
- @param Formula - the formula to create a handle for.
- */
- protected FormulaHandle(Formula f, WorkBook book){
- this.bk = book;
- form = f;
- }
-
-
- /**
- * Returns the cell Address of the formula
- */
- public String getCellAddress(){
- return form.getCellAddress();
- }
-
- /** Returns the Human-Readable Formula String
-
- @return String the Formula in Human-readable format
- */
- public String getFormulaString(){
- return form.getFormulaString();
- }
-
- /** If the Formula evaluates to a String, return
- the value as a String.
-
- @return String - value of the Formula if stored as a String.
- */
- public String getStringVal()
- throws FunctionNotSupportedException{
- //this.form.init();
- return form.getStringVal();
- }
-
- /** Converts a cell value to a form suitable for the public API.
- * Currently this converts cached errors ({@link CalculationException}s)
- * to the corresponding error string.
- */
- static Object sanitizeValue (Object val) {
- if (val instanceof CalculationException)
- return ((CalculationException)val).getName();
- return val;
- }
-
- /** Return the value of the Formula
-
- @return Object - value of the Formula
- */
- public Object getVal()
- throws FunctionNotSupportedException{
- return sanitizeValue( form.calculateFormula() );
- }
-
- /** Return the cached value of the Formula.
- *
- * This method returns the value as cached by OpenXLS or Excel of the formula. Please note
- * that cases could exist where a cached value does not exist. In this case getCachedVal will not try and calculate
- * the formula, it will return null.
-
- @return Object - cached value of the Formula as a String or a Double dependent on data type.
-
- public Object getCachedVal() {
- return form.getCachedVal();
- } */
-
-
- /**
- * Calculate the value of the formula and return it as an object
- *
- * Calling calculate will ignore the WorkBook formula calculation flags
- * and forces calculation of the entire formula stack
- */
- public Object calculate()
- throws FunctionNotSupportedException{
- form.clearCachedValue();
-
- return sanitizeValue( form.calculate() );
- }
-
-
- /**
- * Sets the formula to a string passed in excel formula format.
- * @param formulaString - String formatted as an excel formula, like Sum(A3+4)
- */
-
- public void setFormula(String formulaString)
- throws FunctionNotSupportedException{
- form = FormulaParser.setFormula(form, formulaString, new int[] { form.getRowNumber(), form.getColNumber()});
- }
-
- /** If the Formula evaluates to a String, there
- will be a Stringrec attached to the Formula
- which contains the latest value.
-
- @return boolean whether this Formula evaluates to a String
- */
- public boolean evaluatesToString(){
- return (form.calculateFormula() instanceof String);
- }
-
- /** If the Formula evaluates to a float, return
- the value as an float.
-
- If the workbook level flag CALCULATE_EXPLICIT is set
- then the cached value of the formula (if available) will be returned,
- otherwise the latest calculated value will be returned
-
- @return float - value of the Formula if available as a float. If the
- value cannot be returned as a float NaN will be returned.
- */
- public float getFloatVal()
- throws FunctionNotSupportedException{
- return form.getFloatVal();
- }
-
- /** If the Formula evaluates to a double, return
- the value as an double.
-
- If the workbook level flag CALCULATE_EXPLICIT is set
- then the cached value of the formula (if available) will be returned,
- otherwise the latest calculated value will be returned
-
- @return double - value of the Formula if available as a double. If the
- value cannot be returned as a double NaN will be returned.
- */
- public double getDoubleVal()
- throws FunctionNotSupportedException{
- return form.getDblVal();
- }
-
- /** If the Formula evaluates to an int, return
- the value as an int.
-
- If the workbook level flag CALCULATE_EXPLICIT is set
- then the cached value of the formula (if available) will be returned,
- otherwise the latest calculated value will be returned
-
- @return int - value of the Formula if available as a int. If the value returned can not be
- represented by an int or is a float/double with a non-zero mantissa a runtime NumberFormatException
- will be thrown
- */
- public int getIntVal()
- throws FunctionNotSupportedException{
- return form.getIntVal();
- }
-
- /** get CellRange strings referenced by this formula
- *
- * @return
- * @throws FormulaNotFoundException
- */
- public String[] getRanges()
- throws FormulaNotFoundException{
- Ptg[] locptgs = form.getCellRangePtgs();
- String[] ret = new String[locptgs.length];
- for(int x=0; x dx = form.getPtgsByLocation(formulaLoc);
- Iterator> lx=dx.iterator();
- while(lx.hasNext()){
- try{
- Ptg thisptg = (Ptg)lx.next();
- ReferenceTracker.updateAddressPerPolicy(thisptg, newaddr);
- form.setCachedValue(null); // flag to recalculate
- return true;
- }catch(Exception e){
- Logger.logInfo("updating Formula reference failed:" + e.toString());
- return false;
- }
- }
- return true;
- }
-
- /** Changes a range in a formula to expand until it includes the
- cell address from CellHandle.
-
- Example:
-
- CellHandle cell = new Cellhandle("D4") Formula = SUM(A1:B2)
- addCellToRange("A1:B2",cell); would change the formula to look like"SUM(A1:D4)"
-
- Returns false if formula does not contain the formulaLoc range.
-
- @param String - the Cell Range as a String to add the Cell to
- @param CellHandle - the CellHandle to add to the range
- */
- public boolean addCellToRange(String formulaLoc, CellHandle handle)
- throws FormulaNotFoundException{
- List> dx = form.getPtgsByLocation(formulaLoc);
- Iterator> lx=dx.iterator();
- boolean b=false;
- while(lx.hasNext()){
- Ptg ptg = (Ptg)lx.next();
- if (ptg == null)return false;
- int[] formulaaddr = ExcelTools.getRangeRowCol(formulaLoc);
- String handleaddr = handle.getCellAddress();
- int[] celladdr = ExcelTools.getRowColFromString(handleaddr);
-
- // check existing range and set new range vals if the new Cell is outside
- if(celladdr[0] > formulaaddr[2])formulaaddr[2] = celladdr[0];
- if(celladdr[0] < formulaaddr[0])formulaaddr[0] = celladdr[0];
- if(celladdr[1] > formulaaddr[3])formulaaddr[3] = celladdr[1];
- if(celladdr[1] < formulaaddr[1])formulaaddr[1] = celladdr[1];
- String newaddr = ExcelTools.formatRange(formulaaddr);
- b = this.changeFormulaLocation(formulaLoc, newaddr);
-
- }
- return b;
- }
-
- /** Copy the formula references with offsets
- *
- * @param int[row,col] offsets to move the references
- * @return
- *
- */
- public static void moveCellRefs(FormulaHandle fmh, int[] offsets) throws FormulaNotFoundException {
- // get the current offsets from the FMH references
- String [] celladdys = fmh.getRanges();
-
- // iterate
- for(int x=0;x-1) { // separate out addresses within a range
- secondAddress= range.substring(rangeIdx+1);
- range= range.substring(0, rangeIdx);
- }
- int[] orig = ExcelTools.getRowColFromString(range);
- boolean relCol= !(range.startsWith("$")); // 20100603 KSC: handle relative refs
- boolean relRow= !(range.length()>0 && range.substring(1).indexOf('$')>-1);
- if (relRow) // only move if relative ref
- orig[0] += offsets[0]; //row
- if (relCol)// only move if relative ref
- orig[1]+= offsets[1]; //col
- String newAddress= ExcelTools.formatLocation(orig, relRow, relCol);
- if(orig[0]<0||orig[1]<0)newAddress="#REF!";
- if (secondAddress!=null) {
- orig = ExcelTools.getRowColFromString(secondAddress);
- relCol= !(secondAddress.startsWith("$")); // handle relative refs
- relRow= !(secondAddress.length()>0 && secondAddress.substring(1).indexOf('$')>-1);
- if (orig[0]>=0) {
- if (relRow) // only move if relative ref
- orig[0] += offsets[0]; //row
- }
- if (orig[1]>=0) { //if not wholerow/wholecol ref
- if (relCol)// only move if relative ref
- orig[1]+= offsets[1]; //col
- }
- String newAddress1 = ExcelTools.formatLocation(orig, relRow, relCol);
- newAddress= newAddress + ":" + newAddress1;
- }
- if (sh!=null) // TODO: handle refs with multiple sheets
- newAddress= sh + "!" + newAddress;
- if(! fmh.changeFormulaLocation(celladdys[x], newAddress)){
- Logger.logErr("Could not change Formula Reference: " + celladdys[x] +" to: " + newAddress);
- }
- }
- return;
- }
-
-
- public String toString()
- {
- return this.form.getCellAddress() + ":" + this.form.getFormulaString();
- }
-
- /**
- * return truth of "this formula is shared"
- * @return boolean
- */
- public boolean isSharedFormula() { return this.form.isSharedFormula(); }
-
- public boolean isArrayFormula() { return form.isArrayFormula(); }
- // 20090120 KSC: should be detected auto public void setIsArrayFormula(boolean b) { form.setIsArrayFormula(b); }
-
- /**
- * returns the low-level formula rec for this Formulahandle
- *
- *
- * @return
- */
- public Formula getFormulaRec() {
- return form;
- }
-
- /**
- * Utility method to determine if the calculation works out to an error value.
- *
- * The excel values that will cause this to be true are
- * #VALUE!, #N/A, #REF!, #DIV/0!, #NUM!, #NAME?, #NULL!
-
- *
- * @return
- */
- public boolean isErrorValue() {
- return (form.calculateFormula() instanceof CalculationException);
- }
-
- /**
- * return the "Calculate Always" setting for this formula
- * used for formulas that always need calculating such as TODAY
- * @return
- */
- public boolean getCalcAlways() {
- return form.getCalcAlways();
- }
-
- /**
- * set the "Calculate Always setting for this formula
- * used for formulas that always need calculating such as TODAY
- * @param fAlwaysCalc
- */
- public void setCalcAlways(boolean fAlwaysCalc) {
- form.setCalcAlways(fAlwaysCalc);
- }
-
- /**
- * generate the OOXML necessary to describe this formula
- * OOXML element
- * @return
- */
- // TODO: Deal with External References ... dataTables
- // common possible attributes:
- // aca= always calculate array, bx=name to assign formula to, ca=calculate cell, r1=data table cell1,
- // t=formula type shared, array, dataTable or normal=default
- public String getOOXML() {
- StringBuffer ooxml= new StringBuffer();
- // must have type of formula result
- Object val;
- try {
- val= this.getVal();
- if (val==null) {// means cache was cleared (in all cases???) MUST recalc
- if(this.form.getWorkBook().getCalcMode() != WorkBookHandle.CALCULATE_EXPLICIT) {
- this.calculate();
- val= this.getVal();
- } else {
- val = new CalculationException(CalculationException.VALUE );
- }
- } else if (val instanceof String && ((String) val).startsWith("#"))
- val= new CalculationException(CalculationException.getErrorCode((String)val));
- } catch (Exception e) {
- val = new CalculationException(CalculationException.VALUE );
- }
- if (val==null) {
- Logger.logErr("FormulaHandle.getOOXML: unexpected null encountered when calculating formula: " + this.getCellAddress());
- }
- // Handle attributes for special cached values
- if (val instanceof String) {
- ooxml.append(" t=\"str\"");
- val= OOXMLAdapter.stripNonAscii((String) val); // TODO: how can we strip non-ascii? What about Japanese cell text? ans: has to be XML-compliant is all ...
- } else if (val instanceof Boolean) {
- ooxml.append(" t=\"b\"");
- if (((Boolean)val).booleanValue()) val= "1";
- else val= "0";
- } else if (val instanceof Double) {
- ooxml.append(" t=\"n\"");
- } else if (val instanceof CalculationException) {
- ooxml.append(" t=\"e\"");
- }
-
- String fs= "=";
- try {
- fs= this.getFormulaString();
- } catch (Exception e) {
- Logger.logErr("FormulaHandle.getOOXML: error obtaining formula string: " + e.toString());
- }
- fs= OOXMLAdapter.stripNonAscii(fs).toString(); // handle non-standard xml chars -- ummm what about Japanese? -- it's all ok
- if (!this.isArrayFormula()) {
- ooxml.append(">"); // only output value info
- }
- }
- if (this.isSharedFormula()) {
- // TODO: FINISH 00XML SHARED FORMULAS
- // TODO: need si= shared formula index; when referencing (after shared formula is defined) don't need to include "fs" just the si= ****
- try {
- // 20091022 KSC: Shared Formulas do not work 2003->2007
- //ooxml.append(" t=\"shared\" ref=\"" + this.getFormulaRec().getSharedFormula().getCellRange() + "\"");
- } catch (Exception e) { }
- }
- if (this.getCalcAlways()) ooxml.append(" ca=\"1\"");
- if (fs!=null) // can happen if not a parent array formula
- ooxml.append(">" + fs + " ");
- ooxml.append("" + val + " ");
- return ooxml.toString();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/FormulaHandle.kt b/src/main/java/io/starter/OpenXLS/FormulaHandle.kt
new file mode 100644
index 0000000..a8d656a
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/FormulaHandle.kt
@@ -0,0 +1,569 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.*
+import io.starter.formats.XLS.formulas.*
+import io.starter.toolkit.Logger
+
+
+/**
+ * Formula Handle allows for manipulation of Formulas within a WorkBook.
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see CellHandle
+ */
+class FormulaHandle
+/**
+ * Create a new FormulaHandle from an Excel Formula
+ *
+ * @param Formula - the formula to create a handle for.
+ */
+(f: Formula, private val bk: WorkBook) {
+
+ // 20090120 KSC: should be detected auto public void setIsArrayFormula(boolean b) { form.setIsArrayFormula(b); }
+
+ /**
+ * returns the low-level formula rec for this Formulahandle
+ *
+ * @return
+ */
+ var formulaRec: Formula? = null
+ private set
+
+
+ /**
+ * Returns the cell Address of the formula
+ */
+ val cellAddress: String
+ get() = formulaRec!!.cellAddress
+
+ /**
+ * Returns the Human-Readable Formula String
+ *
+ * @return String the Formula in Human-readable format
+ */
+ val formulaString: String
+ get() = formulaRec!!.formulaString
+
+ /**
+ * If the Formula evaluates to a String, return
+ * the value as a String.
+ *
+ * @return String - value of the Formula if stored as a String.
+ */
+ //this.form.init();
+ val stringVal: String?
+ @Throws(FunctionNotSupportedException::class)
+ get() = formulaRec!!.stringVal
+
+ /**
+ * Return the value of the Formula
+ *
+ * @return Object - value of the Formula
+ */
+ val `val`: Any?
+ @Throws(FunctionNotSupportedException::class)
+ get() = sanitizeValue(formulaRec!!.calculateFormula())
+
+ /**
+ * If the Formula evaluates to a float, return
+ * the value as an float.
+ *
+ *
+ * If the workbook level flag CALCULATE_EXPLICIT is set
+ * then the cached value of the formula (if available) will be returned,
+ * otherwise the latest calculated value will be returned
+ *
+ * @return float - value of the Formula if available as a float. If the
+ * value cannot be returned as a float NaN will be returned.
+ */
+ val floatVal: Float
+ @Throws(FunctionNotSupportedException::class)
+ get() = formulaRec!!.floatVal
+
+ /**
+ * If the Formula evaluates to a double, return
+ * the value as an double.
+ *
+ *
+ * If the workbook level flag CALCULATE_EXPLICIT is set
+ * then the cached value of the formula (if available) will be returned,
+ * otherwise the latest calculated value will be returned
+ *
+ * @return double - value of the Formula if available as a double. If the
+ * value cannot be returned as a double NaN will be returned.
+ */
+ val doubleVal: Double
+ @Throws(FunctionNotSupportedException::class)
+ get() = formulaRec!!.dblVal
+
+ /**
+ * If the Formula evaluates to an int, return
+ * the value as an int.
+ *
+ *
+ * If the workbook level flag CALCULATE_EXPLICIT is set
+ * then the cached value of the formula (if available) will be returned,
+ * otherwise the latest calculated value will be returned
+ *
+ * @return int - value of the Formula if available as a int. If the value returned can not be
+ * represented by an int or is a float/double with a non-zero mantissa a runtime NumberFormatException
+ * will be thrown
+ */
+ val intVal: Int
+ @Throws(FunctionNotSupportedException::class)
+ get() = formulaRec!!.intVal
+
+ /**
+ * get CellRange strings referenced by this formula
+ *
+ * @return
+ * @throws FormulaNotFoundException
+ */
+ // need sheetname along with address; to ensure, must use explicit method:
+ // ret[x]=locptgs[x].getTextString();
+ //avoid NumberFormatExceptions on parsing missing Named Ranges
+ val ranges: Array
+ @Throws(FormulaNotFoundException::class)
+ get() {
+ val locptgs = formulaRec!!.cellRangePtgs
+ val ret = arrayOfNulls(locptgs.size)
+ for (x in locptgs.indices) {
+ try {
+ ret[x] = (locptgs[x] as PtgRef).locationWithSheet
+ } catch (e: Exception) {
+ if (locptgs[x] is PtgName) {
+ ret[x] = locptgs[x].location
+ } else
+ ret[x] = locptgs[x].textString
+ }
+
+ }
+ return ret
+ }
+
+ /**
+ * Initialize CellRanges referenced by this formula
+ *
+ * @return
+ * @throws FormulaNotFoundException
+ */
+ //
+ val cellRanges: Array
+ @Throws(FormulaNotFoundException::class)
+ get() {
+ val crstrs = this.ranges
+ val crs = arrayOfNulls(crstrs.size)
+ for (x in crs.indices) {
+ crs[x] = CellRange(crstrs[x], bk, true)
+ try {
+ crs[x].init()
+ } catch (e: Exception) {
+ }
+
+ }
+ return crs
+ }
+
+ /**
+ * return truth of "this formula is shared"
+ *
+ * @return boolean
+ */
+ val isSharedFormula: Boolean
+ get() = this.formulaRec!!.isSharedFormula
+
+ val isArrayFormula: Boolean
+ get() = formulaRec!!.isArrayFormula
+
+ /**
+ * Utility method to determine if the calculation works out to an error value.
+ *
+ *
+ * The excel values that will cause this to be true are
+ * #VALUE!, #N/A, #REF!, #DIV/0!, #NUM!, #NAME?, #NULL!
+ *
+ * @return
+ */
+ val isErrorValue: Boolean
+ get() = formulaRec!!.calculateFormula() is CalculationException
+
+ /**
+ * return the "Calculate Always" setting for this formula
+ * used for formulas that always need calculating such as TODAY
+ *
+ * @return
+ */
+ /**
+ * set the "Calculate Always setting for this formula
+ * used for formulas that always need calculating such as TODAY
+ *
+ * @param fAlwaysCalc
+ */
+ var calcAlways: Boolean
+ get() = formulaRec!!.calcAlways
+ set(fAlwaysCalc) {
+ formulaRec!!.calcAlways = fAlwaysCalc
+ }
+
+ /**
+ * generate the OOXML necessary to describe this formula
+ * OOXML element
+ *
+ * @return
+ */
+ // TODO: Deal with External References ... dataTables
+ // common possible attributes:
+ // aca= always calculate array, bx=name to assign formula to, ca=calculate cell, r1=data table cell1,
+ // t=formula type shared, array, dataTable or normal=default
+ // must have type of formula result
+ // means cache was cleared (in all cases???) MUST recalc
+ // Handle attributes for special cached values
+ // TODO: how can we strip non-ascii? What about Japanese cell text? ans: has to be XML-compliant is all ...
+ // handle non-standard xml chars -- ummm what about Japanese? -- it's all ok
+ // ignore =
+ // array formulas
+ // it's the parent
+ // remove "{= }"
+ // it's part of a multi-cell array formula therefore DO NOT add array info here
+ // only output value info
+ // TODO: FINISH 00XML SHARED FORMULAS
+ // TODO: need si= shared formula index; when referencing (after shared formula is defined) don't need to include "fs" just the si= ****
+ // 20091022 KSC: Shared Formulas do not work 2003->2007
+ //ooxml.append(" t=\"shared\" ref=\"" + this.getFormulaRec().getSharedFormula().getCellRange() + "\"");
+ // can happen if not a parent array formula
+ val ooxml: String
+ get() {
+ val ooxml = StringBuffer()
+ var `val`: Any?
+ try {
+ `val` = this.`val`
+ if (`val` == null) {
+ if (this.formulaRec!!.workBook!!.calcMode != WorkBookHandle.CALCULATE_EXPLICIT) {
+ this.calculate()
+ `val` = this.`val`
+ } else {
+ `val` = CalculationException(CalculationException.VALUE)
+ }
+ } else if (`val` is String && `val`.startsWith("#"))
+ `val` = CalculationException(CalculationException.getErrorCode(`val` as String?))
+ } catch (e: Exception) {
+ `val` = CalculationException(CalculationException.VALUE)
+ }
+
+ if (`val` == null) {
+ Logger.logErr("FormulaHandle.getOOXML: unexpected null encountered when calculating formula: " + this.cellAddress)
+ }
+ if (`val` is String) {
+ ooxml.append(" t=\"str\"")
+ `val` = OOXMLAdapter.stripNonAscii(`val` as String?)
+ } else if (`val` is Boolean) {
+ ooxml.append(" t=\"b\"")
+ if (`val`.booleanValue())
+ `val` = "1"
+ else
+ `val` = "0"
+ } else if (`val` is Double) {
+ ooxml.append(" t=\"n\"")
+ } else if (`val` is CalculationException) {
+ ooxml.append(" t=\"e\"")
+ }
+
+ var fs: String? = "="
+ try {
+ fs = this.formulaString
+ } catch (e: Exception) {
+ Logger.logErr("FormulaHandle.getOOXML: error obtaining formula string: $e")
+ }
+
+ fs = OOXMLAdapter.stripNonAscii(fs).toString()
+ if (!this.isArrayFormula) {
+ ooxml.append(">")
+ }
+ }
+ if (this.isSharedFormula) {
+ try {
+ } catch (e: Exception) {
+ }
+
+ }
+ if (this.calcAlways) ooxml.append(" ca=\"1\"")
+ if (fs != null)
+ ooxml.append(">$fs ")
+ ooxml.append("$`val` ")
+ return ooxml.toString()
+ }
+
+ /**
+ * Sets the location lock on the Cell Reference at the
+ * specified location
+ *
+ *
+ * Used to prevent updating of the Cell Reference when
+ * Cells are moved.
+ *
+ * @param location of the Cell Reference to be locked/unlocked
+ * @param lock status setting
+ * @return boolean whether the Cell Reference was found and modified
+ */
+ fun setLocationLocked(loc: String, l: Boolean): Boolean {
+ var x = Ptg.PTG_LOCATION_POLICY_UNLOCKED
+ if (l) x = Ptg.PTG_LOCATION_POLICY_LOCKED
+ return formulaRec!!.setLocationPolicy(loc, x)
+ }
+
+ /**
+ * Sets the location lock on the Cell Reference at the
+ * specified location
+ *
+ *
+ * Used to prevent updating of the Cell Reference when
+ * Cells are moved.
+ *
+ * @param location of the Cell Reference to be locked/unlocked
+ * @param lock status setting
+ * @return boolean whether the Cell Reference was found and modified
+ */
+ fun setLocationPolicy(loc: String, l: Int): Boolean {
+ return formulaRec!!.setLocationPolicy(loc, l)
+ }
+
+ init {
+ formulaRec = f
+ }
+
+ /** Return the cached value of the Formula.
+ *
+ * This method returns the value as cached by OpenXLS or Excel of the formula. Please note
+ * that cases could exist where a cached value does not exist. In this case getCachedVal will not try and calculate
+ * the formula, it will return null.
+ *
+ * @return Object - cached value of the Formula as a String or a Double dependent on data type.
+ *
+ * public Object getCachedVal() {
+ * return form.getCachedVal();
+ * }
+ */
+
+
+ /**
+ * Calculate the value of the formula and return it as an object
+ *
+ *
+ * Calling calculate will ignore the WorkBook formula calculation flags
+ * and forces calculation of the entire formula stack
+ */
+ @Throws(FunctionNotSupportedException::class)
+ fun calculate(): Any? {
+ formulaRec!!.clearCachedValue()
+
+ return sanitizeValue(formulaRec!!.calculate())
+ }
+
+
+ /**
+ * Sets the formula to a string passed in excel formula format.
+ *
+ * @param formulaString - String formatted as an excel formula, like Sum(A3+4)
+ */
+
+ @Throws(FunctionNotSupportedException::class)
+ fun setFormula(formulaString: String) {
+ formulaRec = FormulaParser.setFormula(formulaRec, formulaString, intArrayOf(formulaRec!!.rowNumber, formulaRec!!.colNumber.toInt()))
+ }
+
+ /**
+ * If the Formula evaluates to a String, there
+ * will be a Stringrec attached to the Formula
+ * which contains the latest value.
+ *
+ * @return boolean whether this Formula evaluates to a String
+ */
+ fun evaluatesToString(): Boolean {
+ return formulaRec!!.calculateFormula() is String
+ }
+
+ /**
+ * Takes a string as a current formula location, and changes
+ * that pointer in the formula to the new string that is sent.
+ * This can take single cells"A5" and cell ranges,"A3:d4"
+ * Returns true if the cell range specified in formulaLoc exists & can be changed
+ * else false. This also cannot change a cell pointer to a cell range or vice
+ * versa.
+ *
+ * @param String - range of Cells within Formula to modify
+ * @param String - new range of Cells within Formula
+ */
+ @Throws(FormulaNotFoundException::class)
+ fun changeFormulaLocation(formulaLoc: String, newaddr: String): Boolean {
+ val dx = formulaRec!!.getPtgsByLocation(formulaLoc)
+ val lx = dx.iterator()
+ while (lx.hasNext()) {
+ try {
+ val thisptg = lx.next() as Ptg
+ ReferenceTracker.updateAddressPerPolicy(thisptg, newaddr)
+ formulaRec!!.setCachedValue(null) // flag to recalculate
+ return true
+ } catch (e: Exception) {
+ Logger.logInfo("updating Formula reference failed:$e")
+ return false
+ }
+
+ }
+ return true
+ }
+
+ /**
+ * Changes a range in a formula to expand until it includes the
+ * cell address from CellHandle.
+ *
+ *
+ * Example:
+ *
+ *
+ * CellHandle cell = new Cellhandle("D4") Formula = SUM(A1:B2)
+ * addCellToRange("A1:B2",cell); would change the formula to look like"SUM(A1:D4)"
+ *
+ *
+ * Returns false if formula does not contain the formulaLoc range.
+ *
+ * @param String - the Cell Range as a String to add the Cell to
+ * @param CellHandle - the CellHandle to add to the range
+ */
+ @Throws(FormulaNotFoundException::class)
+ fun addCellToRange(formulaLoc: String, handle: CellHandle): Boolean {
+ val dx = formulaRec!!.getPtgsByLocation(formulaLoc)
+ val lx = dx.iterator()
+ var b = false
+ while (lx.hasNext()) {
+ val ptg = lx.next() as Ptg ?: return false
+ val formulaaddr = ExcelTools.getRangeRowCol(formulaLoc)
+ val handleaddr = handle.cellAddress
+ val celladdr = ExcelTools.getRowColFromString(handleaddr)
+
+ // check existing range and set new range vals if the new Cell is outside
+ if (celladdr[0] > formulaaddr[2]) formulaaddr[2] = celladdr[0]
+ if (celladdr[0] < formulaaddr[0]) formulaaddr[0] = celladdr[0]
+ if (celladdr[1] > formulaaddr[3]) formulaaddr[3] = celladdr[1]
+ if (celladdr[1] < formulaaddr[1]) formulaaddr[1] = celladdr[1]
+ val newaddr = ExcelTools.formatRange(formulaaddr)
+ b = this.changeFormulaLocation(formulaLoc, newaddr)
+
+ }
+ return b
+ }
+
+
+ override fun toString(): String {
+ return this.formulaRec!!.cellAddress + ":" + this.formulaRec!!.formulaString
+ }
+
+ companion object {
+ val supportedFunctions: Array>
+ get() = FunctionConstants.recArr
+
+ /**
+ * Converts a cell value to a form suitable for the public API.
+ * Currently this converts cached errors ([CalculationException]s)
+ * to the corresponding error string.
+ */
+ internal fun sanitizeValue(`val`: Any?): Any? {
+ return if (`val` is CalculationException) `val`.name else `val`
+ }
+
+ /**
+ * Copy the formula references with offsets
+ *
+ * @param int[row,col] offsets to move the references
+ * @return
+ */
+ @Throws(FormulaNotFoundException::class)
+ fun moveCellRefs(fmh: FormulaHandle, offsets: IntArray) {
+ // get the current offsets from the FMH references
+ val celladdys = fmh.ranges
+
+ // iterate
+ for (x in celladdys.indices) {
+ val s = ExcelTools.stripSheetNameFromRange(celladdys[x])
+ val sh = s[0] // sheet portion of address,if any
+ var range = s[1] // range or single address
+ val rangeIdx = range.indexOf(":")
+ var secondAddress: String? = null
+ if (rangeIdx > -1) { // separate out addresses within a range
+ secondAddress = range.substring(rangeIdx + 1)
+ range = range.substring(0, rangeIdx)
+ }
+ var orig = ExcelTools.getRowColFromString(range)
+ var relCol = !range.startsWith("$") // 20100603 KSC: handle relative refs
+ var relRow = !(range.length > 0 && range.substring(1).indexOf('$') > -1)
+ if (relRow)
+ // only move if relative ref
+ orig[0] += offsets[0] //row
+ if (relCol)
+ // only move if relative ref
+ orig[1] += offsets[1] //col
+ var newAddress = ExcelTools.formatLocation(orig, relRow, relCol)
+ if (orig[0] < 0 || orig[1] < 0) newAddress = "#REF!"
+ if (secondAddress != null) {
+ orig = ExcelTools.getRowColFromString(secondAddress)
+ relCol = !secondAddress.startsWith("$") // handle relative refs
+ relRow = !(secondAddress.length > 0 && secondAddress.substring(1).indexOf('$') > -1)
+ if (orig[0] >= 0) {
+ if (relRow)
+ // only move if relative ref
+ orig[0] += offsets[0] //row
+ }
+ if (orig[1] >= 0) { //if not wholerow/wholecol ref
+ if (relCol)
+ // only move if relative ref
+ orig[1] += offsets[1] //col
+ }
+ val newAddress1 = ExcelTools.formatLocation(orig, relRow, relCol)
+ newAddress = "$newAddress:$newAddress1"
+ }
+ if (sh != null)
+ // TODO: handle refs with multiple sheets
+ newAddress = "$sh!$newAddress"
+ if (!fmh.changeFormulaLocation(celladdys[x], newAddress)) {
+ Logger.logErr("Could not change Formula Reference: " + celladdys[x] + " to: " + newAddress)
+ }
+ }
+ return
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/GetInfo.java b/src/main/java/io/starter/OpenXLS/GetInfo.java
deleted file mode 100644
index 7a3db6d..0000000
--- a/src/main/java/io/starter/OpenXLS/GetInfo.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.io.IOException;
-import java.util.Properties;
-/** Prints various bits of information about this build.
- */
-public class GetInfo {
-
-private static Properties buildProps;
-
- private static final void loadBuildProps() {
- if (null == buildProps) {
- buildProps = new Properties();
- try {
- buildProps.load( GetInfo.class.getResourceAsStream(
- "build.properties" ) );
- } catch (IOException caught) {
- // don't care, it'll just be empty
- }
- }
- }
-
- private static String version;
-
- /** Return the version number of this installation of OpenXLS. */
- public static final String getVersion() {
- if (null == version) {
- loadBuildProps();
- version = buildProps.getProperty( "version", "unknown" );
-
- if (version.endsWith( "-SNAPSHOT" )) {
- version = version.substring( 0, version.length() - 9 );
-
- String timestamp = buildProps.getProperty( "timestamp" );
- String commit = buildProps.getProperty( "commit" );
- if ("UNKNOWN".equals( commit )) commit = null;
-
- if (null != timestamp)
- version += "-" + timestamp;
- else if (null != commit)
- version += "-unknown";
-
- if (null != commit)
- version += "-" + commit.substring( 0, 10 );
- }
- }
-
- return version;
- }
-
- public static void main(String[] args) {
- // Product name and version
- io.starter.OpenXLS.util.Logger.log ("This is OpenXLS " + getVersion());
- }
-}
diff --git a/src/main/java/io/starter/OpenXLS/GetInfo.kt b/src/main/java/io/starter/OpenXLS/GetInfo.kt
new file mode 100644
index 0000000..65d351a
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/GetInfo.kt
@@ -0,0 +1,83 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import java.io.IOException
+import java.util.Properties
+
+/**
+ * Prints various bits of information about this build.
+ */
+object GetInfo {
+
+ private var buildProps: Properties? = null
+
+ private var version: String? = null
+
+ private fun loadBuildProps() {
+ if (null == buildProps) {
+ buildProps = Properties()
+ try {
+ buildProps!!.load(GetInfo::class.java!!.getResourceAsStream(
+ "build.properties"))
+ } catch (caught: IOException) {
+ // don't care, it'll just be empty
+ }
+
+ }
+ }
+
+ /**
+ * Return the version number of this installation of OpenXLS.
+ */
+ fun getVersion(): String {
+ if (null == version) {
+ loadBuildProps()
+ version = buildProps!!.getProperty("version", "unknown")
+
+ if (version!!.endsWith("-SNAPSHOT")) {
+ version = version!!.substring(0, version!!.length - 9)
+
+ val timestamp = buildProps!!.getProperty("timestamp")
+ var commit: String? = buildProps!!.getProperty("commit")
+ if ("UNKNOWN" == commit) commit = null
+
+ if (null != timestamp)
+ version += "-$timestamp"
+ else if (null != commit)
+ version += "-unknown"
+
+ if (null != commit)
+ version += "-" + commit.substring(0, 10)
+ }
+ }
+
+ return version
+ }
+
+ @JvmStatic
+ fun main(args: Array) {
+ // Product name and version
+ io.starter.toolkit.Logger.log("This is OpenXLS " + getVersion())
+ }
+}
diff --git a/src/main/java/io/starter/OpenXLS/Handle.java b/src/main/java/io/starter/OpenXLS/Handle.java
deleted file mode 100644
index 7910bb1..0000000
--- a/src/main/java/io/starter/OpenXLS/Handle.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-/** A type that represents a component of a document.
- * This interface serves to distinguish such types from helper and other
- * non-content classes.
- */
-public interface Handle {
-}
diff --git a/src/main/java/io/starter/OpenXLS/Handle.kt b/src/main/java/io/starter/OpenXLS/Handle.kt
new file mode 100644
index 0000000..7fffc8e
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/Handle.kt
@@ -0,0 +1,30 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+/**
+ * A type that represents a component of a document.
+ * This interface serves to distinguish such types from helper and other
+ * non-content classes.
+ */
+interface Handle
diff --git a/src/main/java/io/starter/OpenXLS/ImageHandle.java b/src/main/java/io/starter/OpenXLS/ImageHandle.java
deleted file mode 100644
index 710878e..0000000
--- a/src/main/java/io/starter/OpenXLS/ImageHandle.java
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import java.io.*;
-
-import io.starter.formats.XLS.*;
-import io.starter.toolkit.*;
-
-import java.util.*;
-import java.awt.image.*;
-import javax.imageio.*;
-import javax.imageio.stream.*;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-//OOXML-specific structures
-import io.starter.formats.OOXML.*;
-
-
-/** The ImageHandle provides access to an Image embedded in a spreadsheet.
-
- Use the ImageHandle to work with images in spreadsheet.
-
- With an ImageHandle you can:
-
-
- insert images into your spreadsheet
- set the position of the image
- set the width and height of the image
- write spreadsheet image files to any outputstream
-
-
-
-
-
- @see io.starter.OpenXLS.WorkBookHandle
- @see io.starter.OpenXLS.WorkSheetHandle
-*/
-public class ImageHandle implements Serializable{
- /**
- * returns width divided by height for the aspect ratio
- *
- *
- *
- * @return the aspect ratio for the image
- */
- public double getAspectRatio(){
- double height, width;
- double aspectRatio = 0;
- height = getHeight() / 122.27; //(convert to in)
- width = getWidth() / 57.06; //(convert to in)
- aspectRatio = width / height;
- return aspectRatio;
- }
-
- /**
- *
- *
- */
- private static final long serialVersionUID = 3177017738178634238L;
- private byte[] imageBytes;
- private Boundsheet mysheet;
-
- // coordinates
- public static final int X= 0;
- public static final int Y= 1;
- public static final int WIDTH= 2;
- public static final int HEIGHT= 3;
-
- private String imageName = " ", shapeName= "";
- private short height , width;
- private short x, y;
- private int image_type = -1;
- private int DEBUGLEVEL = 0; // eventually will set!
-
- // OOXML-specific
- private SpPr imagesp;
- private String editMovement= null;
-
- private MSODrawing thisMsodrawing; //20070924 KSC: link to actual msodrawing rec that describes this image
- public void setMsgdrawing(MSODrawing rec) { thisMsodrawing= rec; }
- public MSODrawing getMsodrawing() { return thisMsodrawing; }
-
-
- /** Returns the image type
-
- *
- * @return
- */
- public String getType() {
- switch(image_type) {
- case io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_GIF:
- return "gif";
- case io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_JPG:
- return "jpeg";
- case io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_PNG:
- return "png";
- case io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_EMF:
- return "emf";
- default:
- return "undefined";
- }
- }
-
- /** Returns the image mime type
-
- *
- * @return
- */
- public String getMimeType() {
- return "image/" + getImageType();
- }
-
- /** Constructor which takes image file bytes and inserts into
- * specific sheet
-
- *
- * @param imageBytes
- * @param sheet
- */
- public ImageHandle(InputStream imagebytestream, WorkSheetHandle _sheet){
- this(imagebytestream,_sheet.getMysheet());
- }
-
- /**
- * Constructor which takes image file bytes and associates it with the
- * specified boundsheet
-
- *
- * @param imagebytestream
- * @param bs
- */
- public ImageHandle(InputStream imagebytestream, Boundsheet bs) {
- mysheet = bs;
- try{
- imageBytes = new byte[imagebytestream.available()];
- imagebytestream.read(imageBytes);
- }catch(Exception ex) {
- System.err.print("Failed to create new ImageHandle in sheet" + bs.getSheetName() + " from InputStream:" + ex.toString());
- }
- initialize();
- }
- /** Constructor which takes image file bytes and inserts into
- * specific sheet
-
- *
- * @param imageBytes
- * @param sheet
- */
- public ImageHandle(byte[] _imageBytes, Boundsheet sheet){
- mysheet = sheet;
- imageBytes = _imageBytes;
-
- initialize();
-
- }
-
- /** Override equals so that Sheet cannot contain dupes.
-
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- public boolean equals(Object another) {
- if(another.toString().equals(this.toString()))
- return true;
- return false;
- }
-
- private void initialize() {
- // after instantiating the image you should have
- // access to the width and height bounds
- String imageFormat = "";
- try{
- ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
-
- imageFormat = getImageFormat(bis);
- if (imageFormat==null) {
- // 20080128 KSC: Occurs when image format= EMF ????? We cannot interpret, will most likely crash file
- if(DEBUGLEVEL>WorkBook.DEBUG_LOW)
- Logger.logErr("ImageHandle.initialize: Unrecognized Image Format");
- return;
- }
- if(!(imageFormat.equalsIgnoreCase("jpeg") ||imageFormat.equalsIgnoreCase("png"))){
- bis.reset();
- imageBytes = convertData(bis);
- image_type = MSODrawingConstants.IMAGE_TYPE_PNG;
- }
- else{
- if(imageFormat.equalsIgnoreCase("jpeg"))image_type = MSODrawingConstants.IMAGE_TYPE_JPG;
- else this.image_type = MSODrawingConstants.IMAGE_TYPE_PNG;
-
- }
-
- try{
- BufferedImage bi = ImageIO.read(new ByteArrayInputStream(imageBytes));
- width = (short) bi.getWidth();
- height = (short) bi.getHeight();
- bi = null;
- }catch(IOException ex) {
- Logger.logWarn("Java ImageIO could not decode image bytes for " + imageName +":" + ex.toString());
- if(false) { // 20081028 KSC: don't overwrite original image bytes
- String imgname = "failed_image_read_"+this.imageName+"."+imageFormat;
- FileOutputStream outimg = new FileOutputStream(imgname);
- outimg.write(imageBytes);
- outimg.flush();
- outimg.close();
-
- }
- }
- // 20070924 KSC: bounds[2] = width;
- // "" bounds[3] = height;
- this.imageName = "UnnamedImage";
- }catch(Exception e){
- Logger.logWarn("Problem creating ImageHandle:" + e.toString() + " Please see BugTrack article: http://extentech.com/uimodules/docs/docs_detail.jsp?meme_id=1431&showall=true");
- if(false) { // debug image parse probs
- String imgname = "failed_image_read_"+this.imageName+"."+imageFormat;
- try{
- FileOutputStream outimg = new FileOutputStream(imgname);
- outimg.write(imageBytes);
- outimg.flush();
- outimg.close();
- }catch(Exception ex) {
- ;
- }
- }
- }
- }
- /**
- * update the underlying image record
- *
- */
- public void update() throws Exception{
- if (this.thisMsodrawing==null)
- throw new Exception("ImageHandle.Update: Image Not initialzed");
- this.thisMsodrawing.updateRecord(); //this.thisMsodrawing.getSPID());
- this.mysheet.getWorkBook().updateMsodrawingHeaderRec(this.mysheet);
- }
-
- /**
- * returns true if this drawing is active i.e. not deleted
- * Note this is experimental
- * @return
- */
- public boolean isActive() {
- if (this.thisMsodrawing!=null)
- return this.thisMsodrawing.isActive();
- return true; // default
- }
-
- /**
- * converts image data into byte array used by
- *
- * Jan 22, 2010
- * @param imagebytestream
- * @return
- */
- public byte[] convertData(InputStream imagebytestream){
- try{
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
- BufferedImage bi = ImageIO.read(imagebytestream);
-
- ImageIO.write(bi,"png",bos);
-
- return bos.toByteArray();
- }
- catch(Exception e){
- Logger.logErr("ImageHandle.convertData: "+e.toString());
- return null;
- }
-
- }
-
- /**
- * returns the format name of the image data
- *
- * Jan 22, 2010
- * @param imagebytestream
- * @return
- */
- public String getImageFormat(InputStream imagebytestream){
-
- try {
- // Create an image input stream on the image
- ImageInputStream iis = ImageIO.createImageInputStream(imagebytestream);
-
- // Find all image readers that recognize the image format
- Iterator> iter = ImageIO.getImageReaders(iis);
- if (!iter.hasNext()) {
-
- return null;
- }
-
- // Use the first reader
- ImageReader reader = (ImageReader)iter.next();
-
- // Close stream
- iis.close();
-
- // Return the format name
- return reader.getFormatName();
- } catch (IOException e) {
- }
- // The image could not be read
- return null;
- }
-
-
-
- /*
- * 20070924 KSC: image bounds are set via column/row # + offsets within the respective cell
- * added many position methods that access msodrawing for actual positions
- */
- /* position methods */
- /**
- * return the image bounds
- * images bounds are as follows:
- bounds[0]= column # of top left position (0-based) of the shape
- bounds[1]= x offset within the top-left column (0-1023)
- bounds[2]= row # for top left corner
- bounds[3]= y offset within the top-left corner (0-1023)
- bounds[4]= column # of the bottom right corner of the shape
- bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
- bounds[6]= row # for bottom-right corner of the shape
- bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
- */
- public short[] getBounds() {
- return thisMsodrawing.getBounds();
- }
-
- // short is not big enough to handle MAXROWS... correct? -jm
- /**
- * sets the image bounds
- * images bounds are as follows:
- bounds[0]= column # of top left position (0-based) of the shape
- bounds[1]= x offset within the top-left column (0-1023)
- bounds[2]= row # for top left corner
- bounds[3]= y offset within the top-left corner (0-1023)
- bounds[4]= column # of the bottom right corner of the shape
- bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
- bounds[6]= row # for bottom-right corner of the shape
- bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
- */
- public void setBounds(short[] bounds) {
- thisMsodrawing.setBounds(bounds);
- }
-
- /**
- * return the image bounds in x, y, width, height format in pixels
- * @return
- */
- public short[] getCoords() {
- if (thisMsodrawing!=null)
- return thisMsodrawing.getCoords();
- else
- return new short[] { x, y, width, height };
- }
-
- /**
- * set the image x, w, width and height in pixels
- * @param x
- * @param y
- * @param w
- * @param h
- */
- public void setCoords(int x, int y, int w, int h) {
- if (thisMsodrawing!=null)
- thisMsodrawing.setCoords(new short[] {(short) x, (short) y, (short) w, (short) h});
- else {// save for later
- this.x= (short) x;
- this.y= (short) y;
- this.width= (short) w;
- this.height= (short) h;
- }
- }
-
- /**
- * set the image upper x coordinate in pixels
- * @param x
- */
- public void setX(int x) {
- if (thisMsodrawing!=null)
- thisMsodrawing.setX((short) Math.round(x/6.4)); // 20090506 KSC: convert pixels to excel units
- else // save for later
- this.x= (short) x;
- }
-
- /**
- * set the image upper y coordinate in pixels
- * @param y
- */
- public void setY(int y) {
- if (thisMsodrawing!=null)
- thisMsodrawing.setY((short) Math.round(y*0.60)); //convert pixels to points
- else // save for later
- this.y= (short) y;
- }
- /**
- * return the topmost row of the image
- * @return
- */
- public int getRow(){ return thisMsodrawing.getRow0(); }
- /**
- * return the lower row of the image
- * @return
- */
- public int getRow1() { return thisMsodrawing.getRow1(); }
- /**
- * set the topmost row of the image
- * @param row
- */
- public void setRow(int row) { thisMsodrawing.setRow(row); }
- /**
- * set the lower row of the image
- * @param row
- */
- public void setRow1(int row) { thisMsodrawing.setRow1(row); }
-
- /**
- * return the leftmost column of the image
- */
- public int getCol() { return thisMsodrawing.getCol(); }
-
- /**
- * return the rightmost column of the image
- */
- public int getCol1() { return thisMsodrawing.getCol1(); }
-
- public int getOriginalWidth() { return thisMsodrawing.getOriginalWidth(); }
- /**
- * return the width of the image in pixels
- * @return
- */
- public short getWidth() { return (short) Math.round(thisMsodrawing.getWidth()*6.4); // 20090506 KSC: Convert excel units to pixels
- }
- /**
- * set the width of the image in pixels
- * @param w
- */
- public void setWidth(int w) {
- thisMsodrawing.setWidth((short) Math.round(w/6.4)); // 20090506 KSC: convert pixels to excel units
- }
- /**
- * return the height of the image in pixels
- * @return
- */
- public short getHeight() { return (short) Math.round(thisMsodrawing.getHeight()/0.60); // 20090506 KSC: Convert points to pixels
- }
- /**
- * set the height of the image in pixels
- * @param h
- */
- public void setHeight(int h) {
- thisMsodrawing.setHeight((short) Math.round(h*0.60)); // 20090506 KSC: convert pixels to points
- }
- /**
- * return the upper x coordinate of the image in pixels
- * @return
- */
- public short getX() { return (short) Math.round(thisMsodrawing.getX()*6.4); // 20090506 KSC: convert excel units to pixels
- }
- /**
- * return the upper y coordinate of the image in pixels
- * @return
- */
- public short getY() { return (short) Math.round(thisMsodrawing.getY()*0.60); // 20090506 KSC: convert points to pixels
- }
- /** get the position of the top left corner of the image in the sheet
- */
-
- public short[] getRowAndOffset(){
- return thisMsodrawing.getRowAndOffset();
- }
-
- /** get the position of the top left corner of the image in the sheet
- */
- public short[] getColAndOffset(){
- return thisMsodrawing.getColAndOffset();
- }
-
- /** Internal method that converts the image bounds appropriate for saving
- * by Excel in the MsofbtOPT record.
- */
- public int getImageIndex(){
- return thisMsodrawing.getImageIndex();
- }
-
- /** write the image bytes to an outputstream such as a file
-
- *
- * @param out
- */
- //Modified by Bikash
- public void write(OutputStream out) throws IOException{
- // TODO: write the image bytes out
- out.write(this.imageBytes);
- }
-
- /** Need to figure out a unique identifier for these -- if there
- * is one in the BIFF8 information, that would be best
-
- *
- * @see java.lang.Object#toString()
- */
- public String toString(){
- return getName(); // 20071026 KSC: imageName;
- }
-
-
- /** removes this Image from the WorkBook.
- *
- * @return whether the removal was a success
- */
- public boolean remove() {
- this.mysheet.removeImage(this);
- // blow out the image rec
- this.thisMsodrawing.remove(true);
- return true;
- }
-
- /**
- *
- * @return Returns the image type.
- */
- public int getImageType() {
- return image_type;
- }
-
- /**
- *
- * @param image_type The image type to set.
- */
- public void setImageType(int type) {
- image_type = type;
- }
-
- /** returns the WorkSheet this image is contained in
- *
- *
- * @return Returns the sheet.
- */
- public Boundsheet getSheet() {
- return mysheet;
- }
-
- /**
- *
- * @return Returns the name (either explicitly set name or image name).
- */
- public String getName() { // 20071025 KSC: use Explicitly set name = shape name, if present. Otherwise, use imageName
- if (!shapeName.equals(""))
- return shapeName;
- return this.imageName;
- }
-
- /**
- * return the imageName (= original file name, I believe)
- * @return
- */
- public String getImageName() {
- return this.imageName;
- }
- /**
- * returns the explicitly set shape name (set by entering text in the named range field in Excel)
- * @return the shape name
- */
- public String getShapeName() {
- return shapeName;
- }
- /**
- *
- * @param name The name to set.
- */
- public void setName(String name) {
- this.imageName = name;
- // NOTE: updating mso code causes corruption in certain Infoteria files- must look at
- if (this.thisMsodrawing!=null && !this.thisMsodrawing.getName().equals(name)) {
- this.thisMsodrawing.setImageName(name); // update is done in setImageName
- this.thisMsodrawing.getWorkBook().updateMsodrawingHeaderRec(this.getSheet()); // must update header if change mso's - Claritas image insert regression bug (testImages.testInsertImageCorruption)
- }
- }
-
- /**
- * allow setting of image name as seen in the Named Range Box
- * @param name
- */
- public void setShapeName(String name){
- if (name!=null)
- shapeName= name;
- else
- shapeName= "";
- // only set name/update record if names have changed
- if (this.thisMsodrawing!=null && !shapeName.equals(this.thisMsodrawing.getShapeName())) {
- this.thisMsodrawing.setShapeName(shapeName); // update is done in setShapeName
- this.thisMsodrawing.getWorkBook().updateMsodrawingHeaderRec(this.getSheet()); // 20100202 KSC: must update header if change mso's - Claritas image insert regression bug (testImages.testInsertImageCorruption)
- }
- }
-
- /**
- *
- * @return Returns the imageBytes.
- */
- public byte[] getImageBytes() {
- return imageBytes;
- }
-
- /** sets the underlying image bytes to the bytes from a new image
- *
- * essentially swapping the image bytes for another, while retaining
- * all other image properties (borders, etc.)
- *
- *
- *
- * @param imageBytes The imageBytes to set.
- */
- public void setImageBytes(byte[] imageBytes) {
- this.imageBytes = imageBytes;
- mysheet.getWorkBook().getMSODrawingGroup().setImageBytes(this.imageBytes, mysheet, this.thisMsodrawing, this.getName());
- }
-
- /**
- * Get a JSON representation of the format
-
- *
- * @param cr
- * @return
- */
- public JSONObject getJSON() {
- JSONObject ch= new JSONObject();
- try {
- ch.put("name", this.getImageName());
- short[] coords= this.getCoords();
-
- // short[] coords = { x, y, width, height };
-
- ch.put("x", coords[ImageHandle.X]);
- ch.put("y", coords[ImageHandle.Y]);
-
- ch.put("width", coords[ImageHandle.WIDTH]);
- // ch.put("width", width); // for some reason COORDS wrong for width
-
- ch.put("height", coords[ImageHandle.HEIGHT]);
- ch.put("type", this.getType());
-
- }catch(JSONException e) {
- Logger.logErr("Error getting imageHandle JSON: " + e);
- }
- return ch;
- }
-
- /**
- * set ImageHandle position based on another
- * @param im source ImageHandle
- * @return
- */
- public void position(ImageHandle im) {
- /* one way, just set x and y and keep original w and h
- // set x and y, keep original width and height
- short[] origcoords= im.getCoords();
- short[] coords= this.getCoords();
- coords[0]= origcoords[0];
- coords[1]= origcoords[1];
- this.setCoords(coords[0], coords[1], coords[2], coords[3]);
- */
- /* other way, set with all original coordinates */
- this.setBounds(im.getBounds());
- }
-
- /**
- * return the XML representation of this image
- * @return String
- */
- public String getXML(int rId) {
- StringBuffer sb= new StringBuffer();
- short[] bounds= this.getBounds();
- final int EMU= 1270; // 1 pt= 1270 EMUs -- for consistency with OOXML
-
- sb.append(""); sb.append("\r\n");
- // top left coords
- sb.append("");
- sb.append(" " + bounds[0] + "");
- sb.append("" + bounds[1]*EMU + " ");
- sb.append("" + bounds[2] + " ");
- sb.append("" + bounds[3]*EMU + " ");
- sb.append(" "); sb.append("\r\n");
- // bottom right coords
- sb.append("");
- sb.append(" " + bounds[4] + "");
- sb.append("" + bounds[5]*EMU + " ");
- sb.append("" + bounds[6] + " ");
- sb.append("" + bounds[7]*EMU + " ");
- sb.append(" "); sb.append("\r\n");
- // Picture details - req. child elements= nvPicPr (non-visual picture properties), blipFill (links to image), spPr (shape properties)
- sb.append(""); sb.append("\r\n");
- sb.append("");
- sb.append(" ");
- sb.append("");
- sb.append("");
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- // Picture relationship Id and relationship to the package
- sb.append("");
- sb.append(" ");
- // //If the picture is cropped, these details are stored in the element
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- // shape properties
- sb.append(""/* bwMode=\"auto\">"*/);
- sb.append("");
- int x=this.getX()*EMU, y=this.getY()*EMU, cx= this.getWidth()*EMU, cy= this.getHeight()*EMU;
- sb.append(" "); // offsets= location
- sb.append(" "); // extents= size of bounding box enclosing pic in EMUs
- sb.append(" ");
- sb.append(""); // preset geometry, appears necessary for images ...
- sb.append(" ");
- sb.append(" ");
- sb.append(" ");
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- sb.append(" "); sb.append("\r\n");
- sb.append(" ");
- return sb.toString();
- }
- /**
- * return the (00)XML (or DrawingML) representation of this image
- * @param rId relationship id for image file
- * @return String
- */
- public String getOOXML(int rId) {
- TwoCellAnchor t= new TwoCellAnchor(this.editMovement);
- t.setAsImage(rId, this.getImageName(), this.getShapeName(), this.getMsodrawing().getSPID(), this.getSpPr());
- t.setBounds(TwoCellAnchor.convertBoundsFromBIFF8(this.getSheet(), this.getBounds())); // adjust BIFF8 bounds to OOXML units
- return t.getOOXML();
- // missing in
- //
- //
- //
-
-
-/*
- StringBuffer sb= new StringBuffer();
- int[] bounds= twoCellAnchor.convertBoundsFromBIFF8(this.getSheet(), this.getBounds()); // adjust BIFF8 bounds to OOXML units
- final int EMU= 1270; // 1 pt= 1270 EMUs
-
- // 20081008 KSC: Added namespaces for Excel7 Use **********************
- // TODO: create a twoCellAnchor from this ImageHandle and use twoCellAnchor.getOOXML
- sb.append("\r\n");
- // top left coords
- sb.append("");
- sb.append("" + bounds[0] + " "); // 1-based column
- sb.append("" + bounds[1]+ " ");
- sb.append("" + bounds[2] + " ");
- sb.append("" + bounds[3] + " ");
- sb.append(" "); sb.append("\r\n");
- // bottom right coords
- sb.append("");
- sb.append("" + bounds[4] + " "); // 1-based column
- sb.append("" + bounds[5] + " ");
- sb.append("" + bounds[6] + " ");
- sb.append("" + bounds[7] + " ");
- sb.append(" "); sb.append("\r\n");
- // Picture details - req. child elements= nvPicPr (non-visual picture properties), blipFill (links to image), spPr (shape properties)
- sb.append(""); sb.append("\r\n");
- sb.append("");
- sb.append(" ");
- sb.append("");
- sb.append("");
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- // Picture relationship Id and relationship to the package
- sb.append("");
- sb.append(" ");
- sb.append(" "); //If the picture is cropped, these details are stored in the element
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- // shape properties
- if (imagesp!=null)
- sb.append(imagesp.getOOXML());
- else { // default basic
- sb.append("");
- sb.append("");
- int x=this.getX()*EMU, y=this.getY()*EMU, cx= this.getWidth()*EMU, cy= this.getHeight()*EMU;
- sb.append(" "); // offsets= location
- sb.append(" "); // extents= size of bounding box enclosing pic in EMUs
- sb.append(" ");
- sb.append(""); // preset geometry, appears necessary for images ...
- sb.append(" ");
- sb.append(" ");
- sb.append(" "); sb.append("\r\n");
- }
- sb.append(" "); sb.append("\r\n");
- sb.append(" "); sb.append("\r\n");
- sb.append(" ");
- return sb.toString();
-*/
- }
- /**
- * return the OOXML shape property for this image
- * @return
- */
- public SpPr getSpPr() {
- return imagesp;
- }
-
- /**
- * define the OOXML shape property for this image from an existing spPr element
- */
- public void setSpPr(SpPr sp) {
- imagesp= sp;
-// imagesp.setNS("xdr");
- }
- /**
- * specify how to resize or move upon edit OOXML specific
- * @param editMovement
- */
- public void setEditMovement(String editMovement) {
- this.editMovement= editMovement;
- }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/ImageHandle.kt b/src/main/java/io/starter/OpenXLS/ImageHandle.kt
new file mode 100644
index 0000000..4ebea5f
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/ImageHandle.kt
@@ -0,0 +1,890 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.OOXML.SpPr
+import io.starter.formats.OOXML.TwoCellAnchor
+import io.starter.formats.XLS.Boundsheet
+import io.starter.formats.XLS.MSODrawing
+import io.starter.formats.XLS.MSODrawingConstants
+import io.starter.toolkit.Logger
+import org.json.JSONException
+import org.json.JSONObject
+
+import javax.imageio.ImageIO
+import javax.imageio.ImageReader
+import javax.imageio.stream.ImageInputStream
+import java.awt.image.BufferedImage
+import java.io.*
+
+//OOXML-specific structures
+
+
+/**
+ * The ImageHandle provides access to an Image embedded in a spreadsheet.
+ *
+ * Use the ImageHandle to work with images in spreadsheet.
+ *
+ * With an ImageHandle you can:
+ *
+ *
+ * insert images into your spreadsheet
+ * set the position of the image
+ * set the width and height of the image
+ * write spreadsheet image files to any outputstream
+ *
+ *
+ *
+ *
+ *
+ * @see io.starter.OpenXLS.WorkBookHandle
+ *
+ * @see io.starter.OpenXLS.WorkSheetHandle
+ */
+class ImageHandle : Serializable {
+ /**
+ * returns width divided by height for the aspect ratio
+ *
+ * @return the aspect ratio for the image
+ */
+ //(convert to in)
+ //(convert to in)
+ val aspectRatio: Double
+ get() {
+ val height: Double
+ val width: Double
+ var aspectRatio = 0.0
+ height = getHeight() / 122.27
+ width = getWidth() / 57.06
+ aspectRatio = width / height
+ return aspectRatio
+ }
+ private var imageBytes: ByteArray? = null
+ /**
+ * returns the WorkSheet this image is contained in
+ *
+ * @return Returns the sheet.
+ */
+ var sheet: Boundsheet? = null
+ private set
+
+ /**
+ * return the imageName (= original file name, I believe)
+ *
+ * @return
+ */
+ var imageName = " "
+ private set
+ /**
+ * returns the explicitly set shape name (set by entering text in the named range field in Excel)
+ *
+ * @return the shape name
+ */
+ /**
+ * allow setting of image name as seen in the Named Range Box
+ *
+ * @param name
+ */
+ // only set name/update record if names have changed
+ // update is done in setShapeName
+ // 20100202 KSC: must update header if change mso's - Claritas image insert regression bug (testImages.testInsertImageCorruption)
+ var shapeName: String? = ""
+ set(name) {
+ if (name != null)
+ field = name
+ else
+ field = ""
+ if (this.msodrawing != null && this.shapeName != this.msodrawing!!.shapeName) {
+ this.msodrawing!!.shapeName = this.shapeName!!
+ this.msodrawing!!.workBook!!.updateMsodrawingHeaderRec(this.sheet)
+ }
+ }
+ private var height: Short = 0
+ private var width: Short = 0
+ private var x: Short = 0
+ private var y: Short = 0
+ /**
+ * @return Returns the image type.
+ */
+ /**
+ * @param image_type The image type to set.
+ */
+ var imageType = -1
+ private val DEBUGLEVEL = 0 // eventually will set!
+
+ // OOXML-specific
+ /**
+ * return the OOXML shape property for this image
+ *
+ * @return
+ */
+ /**
+ * define the OOXML shape property for this image from an existing spPr element
+ */
+ // imagesp.setNS("xdr");
+ var spPr: SpPr? = null
+ private var editMovement: String? = null
+
+ var msodrawing: MSODrawing? = null
+ private set //20070924 KSC: link to actual msodrawing rec that describes this image
+
+
+ /**
+ * Returns the image type
+ *
+ * @return
+ */
+ val type: String
+ get() {
+ when (imageType) {
+ io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_GIF -> return "gif"
+ io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_JPG -> return "jpeg"
+ io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_PNG -> return "png"
+ io.starter.formats.XLS.MSODrawingConstants.IMAGE_TYPE_EMF -> return "emf"
+ else -> return "undefined"
+ }
+ }
+
+ /**
+ * Returns the image mime type
+ *
+ * @return
+ */
+ val mimeType: String
+ get() = "image/$imageType"
+
+ /**
+ * returns true if this drawing is active i.e. not deleted
+ * Note this is experimental
+ *
+ * @return
+ */
+ // default
+ val isActive: Boolean
+ get() = if (this.msodrawing != null) this.msodrawing!!.isActive else true
+
+
+ /*
+ * 20070924 KSC: image bounds are set via column/row # + offsets within the respective cell
+ * added many position methods that access msodrawing for actual positions
+ */
+ /* position methods */
+
+ /**
+ * return the image bounds
+ * images bounds are as follows:
+ * bounds[0]= column # of top left position (0-based) of the shape
+ * bounds[1]= x offset within the top-left column (0-1023)
+ * bounds[2]= row # for top left corner
+ * bounds[3]= y offset within the top-left corner (0-1023)
+ * bounds[4]= column # of the bottom right corner of the shape
+ * bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
+ * bounds[6]= row # for bottom-right corner of the shape
+ * bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
+ */
+ // short is not big enough to handle MAXROWS... correct? -jm
+
+ /**
+ * sets the image bounds
+ * images bounds are as follows:
+ * bounds[0]= column # of top left position (0-based) of the shape
+ * bounds[1]= x offset within the top-left column (0-1023)
+ * bounds[2]= row # for top left corner
+ * bounds[3]= y offset within the top-left corner (0-1023)
+ * bounds[4]= column # of the bottom right corner of the shape
+ * bounds[5]= x offset within the cell for the bottom-right corner (0-1023)
+ * bounds[6]= row # for bottom-right corner of the shape
+ * bounds[7]= y offset within the cell for the bottom-right corner (0-1023)
+ */
+ var bounds: ShortArray?
+ get() = msodrawing!!.bounds
+ set(bounds) {
+ msodrawing!!.bounds = bounds!!
+ }
+
+ /**
+ * return the image bounds in x, y, width, height format in pixels
+ *
+ * @return
+ */
+ val coords: ShortArray
+ get() = if (msodrawing != null)
+ msodrawing!!.coords
+ else
+ shortArrayOf(x, y, width, height)
+
+ /**
+ * return the topmost row of the image
+ *
+ * @return
+ */
+ /**
+ * set the topmost row of the image
+ *
+ * @param row
+ */
+ var row: Int
+ get() = msodrawing!!.row0
+ set(row) = msodrawing!!.setRow(row)
+
+ /**
+ * return the lower row of the image
+ *
+ * @return
+ */
+ /**
+ * set the lower row of the image
+ *
+ * @param row
+ */
+ var row1: Int
+ get() = msodrawing!!.row1
+ set(row) {
+ msodrawing!!.row1 = row
+ }
+
+ /**
+ * return the leftmost column of the image
+ */
+ val col: Int
+ get() = msodrawing!!.col
+
+ /**
+ * return the rightmost column of the image
+ */
+ val col1: Int
+ get() = msodrawing!!.col1
+
+ val originalWidth: Int
+ get() = msodrawing!!.originalWidth.toInt()
+
+ /**
+ * get the position of the top left corner of the image in the sheet
+ */
+
+ val rowAndOffset: ShortArray
+ get() = msodrawing!!.rowAndOffset
+
+ /**
+ * get the position of the top left corner of the image in the sheet
+ */
+ val colAndOffset: ShortArray
+ get() = msodrawing!!.colAndOffset
+
+ /**
+ * Internal method that converts the image bounds appropriate for saving
+ * by Excel in the MsofbtOPT record.
+ */
+ val imageIndex: Int
+ get() = msodrawing!!.imageIndex
+
+ /**
+ * @return Returns the name (either explicitly set name or image name).
+ */
+ /**
+ * @param name The name to set.
+ */
+ // 20071025 KSC: use Explicitly set name = shape name, if present. Otherwise, use imageName
+ // NOTE: updating mso code causes corruption in certain Infoteria files- must look at
+ // update is done in setImageName
+ // must update header if change mso's - Claritas image insert regression bug (testImages.testInsertImageCorruption)
+ var name: String
+ get() = if (this.shapeName != "") this.shapeName else this.imageName
+ set(name) {
+ this.imageName = name
+ if (this.msodrawing != null && this.msodrawing!!.name != name) {
+ this.msodrawing!!.setImageName(name)
+ this.msodrawing!!.workBook!!.updateMsodrawingHeaderRec(this.sheet)
+ }
+ }
+
+ /**
+ * Get a JSON representation of the format
+ *
+ * @param cr
+ * @return
+ */
+ // short[] coords = { x, y, width, height };
+ // ch.put("width", width); // for some reason COORDS wrong for width
+ val json: JSONObject
+ get() {
+ val ch = JSONObject()
+ try {
+ ch.put("name", this.imageName)
+ val coords = this.coords
+
+ ch.put("x", coords[ImageHandle.X].toInt())
+ ch.put("y", coords[ImageHandle.Y].toInt())
+
+ ch.put("width", coords[ImageHandle.WIDTH].toInt())
+
+ ch.put("height", coords[ImageHandle.HEIGHT].toInt())
+ ch.put("type", this.type)
+
+ } catch (e: JSONException) {
+ Logger.logErr("Error getting imageHandle JSON: $e")
+ }
+
+ return ch
+ }
+
+ fun setMsgdrawing(rec: MSODrawing) {
+ msodrawing = rec
+ }
+
+ /**
+ * Constructor which takes image file bytes and inserts into
+ * specific sheet
+ *
+ * @param imageBytes
+ * @param sheet
+ */
+ constructor(imagebytestream: InputStream, _sheet: WorkSheetHandle) : this(imagebytestream, _sheet.mysheet) {}
+
+ /**
+ * Constructor which takes image file bytes and associates it with the
+ * specified boundsheet
+ *
+ * @param imagebytestream
+ * @param bs
+ */
+ constructor(imagebytestream: InputStream, bs: Boundsheet?) {
+ sheet = bs
+ try {
+ imageBytes = ByteArray(imagebytestream.available())
+ imagebytestream.read(imageBytes!!)
+ } catch (ex: Exception) {
+ System.err.print("Failed to create new ImageHandle in sheet" + bs!!.sheetName + " from InputStream:" + ex.toString())
+ }
+
+ initialize()
+ }
+
+ /**
+ * Constructor which takes image file bytes and inserts into
+ * specific sheet
+ *
+ * @param imageBytes
+ * @param sheet
+ */
+ constructor(_imageBytes: ByteArray, sheet: Boundsheet) {
+ this.sheet = sheet
+ imageBytes = _imageBytes
+
+ initialize()
+
+ }
+
+ /**
+ * Override equals so that Sheet cannot contain dupes.
+ *
+ * @see java.lang.Object.equals
+ */
+ override fun equals(another: Any?): Boolean {
+ return another!!.toString() == this.toString()
+ }
+
+ private fun initialize() {
+ // after instantiating the image you should have
+ // access to the width and height bounds
+ var imageFormat: String? = ""
+ try {
+ val bis = ByteArrayInputStream(imageBytes!!)
+
+ imageFormat = getImageFormat(bis)
+ if (imageFormat == null) {
+ // 20080128 KSC: Occurs when image format= EMF ????? We cannot interpret, will most likely crash file
+ if (DEBUGLEVEL > WorkBook.DEBUG_LOW)
+ Logger.logErr("ImageHandle.initialize: Unrecognized Image Format")
+ return
+ }
+ if (!(imageFormat.equals("jpeg", ignoreCase = true) || imageFormat.equals("png", ignoreCase = true))) {
+ bis.reset()
+ imageBytes = convertData(bis)
+ imageType = MSODrawingConstants.IMAGE_TYPE_PNG
+ } else {
+ if (imageFormat.equals("jpeg", ignoreCase = true))
+ imageType = MSODrawingConstants.IMAGE_TYPE_JPG
+ else
+ this.imageType = MSODrawingConstants.IMAGE_TYPE_PNG
+
+ }
+
+ try {
+ var bi: BufferedImage? = ImageIO.read(ByteArrayInputStream(imageBytes!!))
+ width = bi!!.width.toShort()
+ height = bi.height.toShort()
+ bi = null
+ } catch (ex: IOException) {
+ Logger.logWarn("Java ImageIO could not decode image bytes for $imageName:$ex")
+ if (false) { // 20081028 KSC: don't overwrite original image bytes
+ val imgname = "failed_image_read_" + this.imageName + "." + imageFormat
+ val outimg = FileOutputStream(imgname)
+ outimg.write(imageBytes!!)
+ outimg.flush()
+ outimg.close()
+
+ }
+ }
+
+ // 20070924 KSC: bounds[2] = width;
+ // "" bounds[3] = height;
+ this.imageName = "UnnamedImage"
+ } catch (e: Exception) {
+ Logger.logWarn("Problem creating ImageHandle:$e Please see BugTrack article: http://extentech.com/uimodules/docs/docs_detail.jsp?meme_id=1431&showall=true")
+ if (false) { // debug image parse probs
+ val imgname = "failed_image_read_" + this.imageName + "." + imageFormat
+ try {
+ val outimg = FileOutputStream(imgname)
+ outimg.write(imageBytes!!)
+ outimg.flush()
+ outimg.close()
+ } catch (ex: Exception) {
+ }
+
+ }
+ }
+
+ }
+
+ /**
+ * update the underlying image record
+ */
+ @Throws(Exception::class)
+ fun update() {
+ if (this.msodrawing == null)
+ throw Exception("ImageHandle.Update: Image Not initialzed")
+ this.msodrawing!!.updateRecord() //this.thisMsodrawing.getSPID());
+ this.sheet!!.workBook!!.updateMsodrawingHeaderRec(this.sheet)
+ }
+
+ /**
+ * converts image data into byte array used by
+ *
+ *
+ * Jan 22, 2010
+ *
+ * @param imagebytestream
+ * @return
+ */
+ fun convertData(imagebytestream: InputStream): ByteArray? {
+ try {
+ val bos = ByteArrayOutputStream()
+
+ val bi = ImageIO.read(imagebytestream)
+
+ ImageIO.write(bi, "png", bos)
+
+ return bos.toByteArray()
+ } catch (e: Exception) {
+ Logger.logErr("ImageHandle.convertData: $e")
+ return null
+ }
+
+ }
+
+ /**
+ * returns the format name of the image data
+ *
+ *
+ * Jan 22, 2010
+ *
+ * @param imagebytestream
+ * @return
+ */
+ fun getImageFormat(imagebytestream: InputStream): String? {
+
+ try {
+ // Create an image input stream on the image
+ val iis = ImageIO.createImageInputStream(imagebytestream)
+
+ // Find all image readers that recognize the image format
+ val iter = ImageIO.getImageReaders(iis)
+ if (!iter.hasNext()) {
+
+ return null
+ }
+
+ // Use the first reader
+ val reader = iter.next() as ImageReader
+
+ // Close stream
+ iis.close()
+
+ // Return the format name
+ return reader.formatName
+ } catch (e: IOException) {
+ }
+
+ // The image could not be read
+ return null
+ }
+
+ /**
+ * set the image x, w, width and height in pixels
+ *
+ * @param x
+ * @param y
+ * @param w
+ * @param h
+ */
+ fun setCoords(x: Int, y: Int, w: Int, h: Int) {
+ if (msodrawing != null)
+ msodrawing!!.coords = shortArrayOf(x.toShort(), y.toShort(), w.toShort(), h.toShort())
+ else {// save for later
+ this.x = x.toShort()
+ this.y = y.toShort()
+ this.width = w.toShort()
+ this.height = h.toShort()
+ }
+ }
+
+ /**
+ * set the image upper x coordinate in pixels
+ *
+ * @param x
+ */
+ fun setX(x: Int) {
+ if (msodrawing != null)
+ msodrawing!!.setX(Math.round(x / 6.4).toShort().toInt()) // 20090506 KSC: convert pixels to excel units
+ else
+ // save for later
+ this.x = x.toShort()
+ }
+
+ /**
+ * set the image upper y coordinate in pixels
+ *
+ * @param y
+ */
+ fun setY(y: Int) {
+ if (msodrawing != null)
+ msodrawing!!.setY(Math.round(y * 0.60).toShort().toInt()) //convert pixels to points
+ else
+ // save for later
+ this.y = y.toShort()
+ }
+
+ /**
+ * return the width of the image in pixels
+ *
+ * @return
+ */
+ fun getWidth(): Short {
+ return Math.round(msodrawing!!.width * 6.4).toShort() // 20090506 KSC: Convert excel units to pixels
+ }
+
+ /**
+ * set the width of the image in pixels
+ *
+ * @param w
+ */
+ fun setWidth(w: Int) {
+ msodrawing!!.setWidth(Math.round(w / 6.4).toShort().toInt()) // 20090506 KSC: convert pixels to excel units
+ }
+
+ /**
+ * return the height of the image in pixels
+ *
+ * @return
+ */
+ fun getHeight(): Short {
+ return Math.round(msodrawing!!.height / 0.60).toShort() // 20090506 KSC: Convert points to pixels
+ }
+
+ /**
+ * set the height of the image in pixels
+ *
+ * @param h
+ */
+ fun setHeight(h: Int) {
+ msodrawing!!.setHeight(Math.round(h * 0.60).toShort().toInt()) // 20090506 KSC: convert pixels to points
+ }
+
+ /**
+ * return the upper x coordinate of the image in pixels
+ *
+ * @return
+ */
+ fun getX(): Short {
+ return Math.round(msodrawing!!.x * 6.4).toShort() // 20090506 KSC: convert excel units to pixels
+ }
+
+ /**
+ * return the upper y coordinate of the image in pixels
+ *
+ * @return
+ */
+ fun getY(): Short {
+ return Math.round(msodrawing!!.y * 0.60).toShort() // 20090506 KSC: convert points to pixels
+ }
+
+ /**
+ * write the image bytes to an outputstream such as a file
+ *
+ * @param out
+ */
+ //Modified by Bikash
+ @Throws(IOException::class)
+ fun write(out: OutputStream) {
+ // TODO: write the image bytes out
+ out.write(this.imageBytes!!)
+ }
+
+ /**
+ * Need to figure out a unique identifier for these -- if there
+ * is one in the BIFF8 information, that would be best
+ *
+ * @see java.lang.Object.toString
+ */
+ override fun toString(): String {
+ return name // 20071026 KSC: imageName;
+ }
+
+
+ /**
+ * removes this Image from the WorkBook.
+ *
+ * @return whether the removal was a success
+ */
+ fun remove(): Boolean {
+ this.sheet!!.removeImage(this)
+ // blow out the image rec
+ this.msodrawing!!.remove(true)
+ return true
+ }
+
+ /**
+ * @return Returns the imageBytes.
+ */
+ fun getImageBytes(): ByteArray? {
+ return imageBytes
+ }
+
+ /**
+ * sets the underlying image bytes to the bytes from a new image
+ *
+ *
+ * essentially swapping the image bytes for another, while retaining
+ * all other image properties (borders, etc.)
+ *
+ * @param imageBytes The imageBytes to set.
+ */
+ fun setImageBytes(imageBytes: ByteArray) {
+ this.imageBytes = imageBytes
+ sheet!!.workBook!!.msoDrawingGroup!!.setImageBytes(this.imageBytes, sheet, this.msodrawing!!, this.name)
+ }
+
+ /**
+ * set ImageHandle position based on another
+ *
+ * @param im source ImageHandle
+ * @return
+ */
+ fun position(im: ImageHandle) {
+ /* one way, just set x and y and keep original w and h
+ // set x and y, keep original width and height
+ short[] origcoords= im.getCoords();
+ short[] coords= this.getCoords();
+ coords[0]= origcoords[0];
+ coords[1]= origcoords[1];
+ this.setCoords(coords[0], coords[1], coords[2], coords[3]);
+ */
+ /* other way, set with all original coordinates */
+ this.bounds = im.bounds
+ }
+
+ /**
+ * return the XML representation of this image
+ *
+ * @return String
+ */
+ fun getXML(rId: Int): String {
+ val sb = StringBuffer()
+ val bounds = this.bounds
+ val EMU = 1270 // 1 pt= 1270 EMUs -- for consistency with OOXML
+
+ sb.append("")
+ sb.append("\r\n")
+ // top left coords
+ sb.append("")
+ sb.append(" " + bounds!![0] + "")
+ sb.append("" + bounds[1] * EMU + " ")
+ sb.append("" + bounds[2] + " ")
+ sb.append("" + bounds[3] * EMU + " ")
+ sb.append(" ")
+ sb.append("\r\n")
+ // bottom right coords
+ sb.append("")
+ sb.append(" " + bounds[4] + "")
+ sb.append("" + bounds[5] * EMU + " ")
+ sb.append("" + bounds[6] + " ")
+ sb.append("" + bounds[7] * EMU + " ")
+ sb.append(" ")
+ sb.append("\r\n")
+ // Picture details - req. child elements= nvPicPr (non-visual picture properties), blipFill (links to image), spPr (shape properties)
+ sb.append("")
+ sb.append("\r\n")
+ sb.append("")
+ sb.append(" ")
+ sb.append("")
+ sb.append("")
+ sb.append(" ")
+ sb.append(" ")
+ sb.append("\r\n")
+ // Picture relationship Id and relationship to the package
+ sb.append("")
+ sb.append("")
+ // //If the picture is cropped, these details are stored in the element
+ sb.append(" ")
+ sb.append(" ")
+ sb.append("\r\n")
+ // shape properties
+ sb.append(""/* bwMode=\"auto\">"*/)
+ sb.append("")
+ val x = this.getX() * EMU
+ val y = this.getY() * EMU
+ val cx = this.getWidth() * EMU
+ val cy = this.getHeight() * EMU
+ sb.append("") // offsets= location
+ sb.append("") // extents= size of bounding box enclosing pic in EMUs
+ sb.append(" ")
+ sb.append("") // preset geometry, appears necessary for images ...
+ sb.append(" ")
+ sb.append(" ")
+ sb.append(" ")
+ sb.append(" ")
+ sb.append(" ")
+ sb.append("\r\n")
+ sb.append(" ")
+ sb.append("\r\n")
+ sb.append(" ")
+ return sb.toString()
+ }
+
+ /**
+ * return the (00)XML (or DrawingML) representation of this image
+ *
+ * @param rId relationship id for image file
+ * @return String
+ */
+ fun getOOXML(rId: Int): String {
+ val t = TwoCellAnchor(this.editMovement)
+ t.setAsImage(rId, this.imageName, this.shapeName, this.msodrawing!!.spid, this.spPr)
+ t.bounds = TwoCellAnchor.convertBoundsFromBIFF8(this.sheet, this.bounds!!) // adjust BIFF8 bounds to OOXML units
+ return t.ooxml
+ // missing in
+ //
+ //
+ //
+
+
+ /*
+ StringBuffer sb= new StringBuffer();
+ int[] bounds= twoCellAnchor.convertBoundsFromBIFF8(this.getSheet(), this.getBounds()); // adjust BIFF8 bounds to OOXML units
+ final int EMU= 1270; // 1 pt= 1270 EMUs
+
+ // 20081008 KSC: Added namespaces for Excel7 Use **********************
+ // TODO: create a twoCellAnchor from this ImageHandle and use twoCellAnchor.getOOXML
+ sb.append("\r\n");
+ // top left coords
+ sb.append("");
+ sb.append("" + bounds[0] + " "); // 1-based column
+ sb.append("" + bounds[1]+ " ");
+ sb.append("" + bounds[2] + " ");
+ sb.append("" + bounds[3] + " ");
+ sb.append(" "); sb.append("\r\n");
+ // bottom right coords
+ sb.append("");
+ sb.append("" + bounds[4] + " "); // 1-based column
+ sb.append("" + bounds[5] + " ");
+ sb.append("" + bounds[6] + " ");
+ sb.append("" + bounds[7] + " ");
+ sb.append(" "); sb.append("\r\n");
+ // Picture details - req. child elements= nvPicPr (non-visual picture properties), blipFill (links to image), spPr (shape properties)
+ sb.append(""); sb.append("\r\n");
+ sb.append("");
+ sb.append(" ");
+ sb.append("");
+ sb.append("");
+ sb.append(" ");
+ sb.append(" "); sb.append("\r\n");
+ // Picture relationship Id and relationship to the package
+ sb.append("");
+ sb.append(" ");
+ sb.append(" "); //If the picture is cropped, these details are stored in the element
+ sb.append(" ");
+ sb.append(" "); sb.append("\r\n");
+ // shape properties
+ if (imagesp!=null)
+ sb.append(imagesp.getOOXML());
+ else { // default basic
+ sb.append("");
+ sb.append("");
+ int x=this.getX()*EMU, y=this.getY()*EMU, cx= this.getWidth()*EMU, cy= this.getHeight()*EMU;
+ sb.append(" "); // offsets= location
+ sb.append(" "); // extents= size of bounding box enclosing pic in EMUs
+ sb.append(" ");
+ sb.append(""); // preset geometry, appears necessary for images ...
+ sb.append(" ");
+ sb.append(" ");
+ sb.append(" "); sb.append("\r\n");
+ }
+ sb.append(" "); sb.append("\r\n");
+ sb.append(" "); sb.append("\r\n");
+ sb.append(" ");
+ return sb.toString();
+*/
+ }
+
+ /**
+ * specify how to resize or move upon edit OOXML specific
+ *
+ * @param editMovement
+ */
+ fun setEditMovement(editMovement: String) {
+ this.editMovement = editMovement
+ }
+
+ companion object {
+
+ /**
+ *
+ */
+ private const val serialVersionUID = 3177017738178634238L
+
+ // coordinates
+ val X = 0
+ val Y = 1
+ val WIDTH = 2
+ val HEIGHT = 3
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/JSONConstants.java b/src/main/java/io/starter/OpenXLS/JSONConstants.java
deleted file mode 100644
index e9cf994..0000000
--- a/src/main/java/io/starter/OpenXLS/JSONConstants.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-/** Constants used in the generation of JSON output. */
-interface JSONConstants {
- public static final String JSON_CELL_VALUE = "v";
- public static final String JSON_CELL_FORMATTED_VALUE = "fv";
- public static final String JSON_CELL_FORMULA = "fm";
- public static final String JSON_CELL = "Cell";
- public static final String JSON_CELLS = "cs";
- public static final String JSON_DATETIME = "DateTime";
- public static final String JSON_DATEVALUE = "DateValue";
- public static final String JSON_DOUBLE = "Double";
- public static final String JSON_RANGE = "Range";
- public static final String JSON_DATA = "d";
- public static final String JSON_FLOAT = "Float";
- public static final String JSON_INTEGER = "Integer";
- public static final String JSON_LOCATION = "loc";
- public static final String JSON_ROW = "Row";
- public static final String JSON_ROW_BORDER_TOP = "BdrT";
- public static final String JSON_ROW_BORDER_BOTTOM = "BdrB";
- public static final String JSON_HEIGHT = "h";
- public static final String JSON_STRING = "String";
- public static final String JSON_STYLEID = "sid";
- public static final String JSON_TYPE = "t";
- public static final String JSON_FORMULA_HIDDEN = "fhd";
- public static final String JSON_LOCKED = "lck";
- public static final String JSON_HIDDEN = "Hidden";
- public static final String JSON_VALIDATION_MESSAGE = "vm";
- public static final String JSON_MERGEACROSS = "MergeAcross";
- public static final String JSON_MERGEDOWN = "MergeDown";
- public static final String JSON_MERGEPARENT = "MergeParent";
- public static final String JSON_MERGECHILD = "MergeChild";
- public static final String JSON_HREF = "HRef";
- public static final String JSON_WORD_WRAP = "wrap";
- public static final String JSON_RED_FORMAT = "negRed";
- public static final String JSON_TEXT_ALIGN = "txtAlign";
-}
diff --git a/src/main/java/io/starter/OpenXLS/JSONConstants.kt b/src/main/java/io/starter/OpenXLS/JSONConstants.kt
new file mode 100644
index 0000000..b3a6dd5
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/JSONConstants.kt
@@ -0,0 +1,63 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+/**
+ * Constants used in the generation of JSON output.
+ */
+internal interface JSONConstants {
+ companion object {
+ val JSON_CELL_VALUE = "v"
+ val JSON_CELL_FORMATTED_VALUE = "fv"
+ val JSON_CELL_FORMULA = "fm"
+ val JSON_CELL = "Cell"
+ val JSON_CELLS = "cs"
+ val JSON_DATETIME = "DateTime"
+ val JSON_DATEVALUE = "DateValue"
+ val JSON_DOUBLE = "Double"
+ val JSON_RANGE = "Range"
+ val JSON_DATA = "d"
+ val JSON_FLOAT = "Float"
+ val JSON_INTEGER = "Integer"
+ val JSON_LOCATION = "loc"
+ val JSON_ROW = "Row"
+ val JSON_ROW_BORDER_TOP = "BdrT"
+ val JSON_ROW_BORDER_BOTTOM = "BdrB"
+ val JSON_HEIGHT = "h"
+ val JSON_STRING = "String"
+ val JSON_STYLEID = "sid"
+ val JSON_TYPE = "t"
+ val JSON_FORMULA_HIDDEN = "fhd"
+ val JSON_LOCKED = "lck"
+ val JSON_HIDDEN = "Hidden"
+ val JSON_VALIDATION_MESSAGE = "vm"
+ val JSON_MERGEACROSS = "MergeAcross"
+ val JSON_MERGEDOWN = "MergeDown"
+ val JSON_MERGEPARENT = "MergeParent"
+ val JSON_MERGECHILD = "MergeChild"
+ val JSON_HREF = "HRef"
+ val JSON_WORD_WRAP = "wrap"
+ val JSON_RED_FORMAT = "negRed"
+ val JSON_TEXT_ALIGN = "txtAlign"
+ }
+}
diff --git a/src/main/java/io/starter/OpenXLS/NameHandle.java b/src/main/java/io/starter/OpenXLS/NameHandle.java
deleted file mode 100644
index 3819d6f..0000000
--- a/src/main/java/io/starter/OpenXLS/NameHandle.java
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import static io.starter.OpenXLS.JSONConstants.*;
-
-import io.starter.formats.XLS.Boundsheet;
-import io.starter.formats.XLS.WorkSheetNotFoundException;
-import io.starter.formats.XLS.formulas.Ptg;
-import io.starter.formats.XLS.*;
-import io.starter.toolkit.CompatibleVector;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.StringTool;
-import org.json.*;
-
-/** The NameHandle provides access to a Named Range and its Cells.
-
- Use the NameHandle to work with individual Named Ranges in an XLS file.
-
- With a NameHandle you can:
-
-
- get a handle to the Cells in a Name
- set the default formatting for a Name
-
-
-
-
- @see WorkBookHandle
- @see WorkSheetHandle
- @see FormulaHandle
-*/
-public class NameHandle {
-
- private Name myName;
- private WorkBook mybook;
- private int DEBUGLEVEL = -1;
- private boolean createblanks = false;
- private CellRange initialRange = null;
-
- /** Creates a new Named Range from a CellRange
- *
- * @param Name of the Range, the CellRange referenced by the Name
- */
- public NameHandle(String namestr, CellRange cr){
- mybook = cr.getWorkBook();
- initialRange = cr; // cache
- myName = new Name(mybook.getWorkBook(),namestr);
- this.setName(namestr);
- this.setLocation(cr.toString());
- }
-
- /**
- * Create a NameHandle from an internal Name record
-
- *
- * @param c
- * @param myb
- */
- protected NameHandle(Name c, WorkBookHandle myb){
- myName = c;
- mybook = myb;
- }
-
- /**
- * Returns a handle to the object (either workbook or sheet) that is scoped
- * to the name record
- *
- * Default scope is a WorkBookHandle, else the WorkSheetHandle is returned.
- * @return the scope of the name
- */
- public Handle getScope() throws WorkSheetNotFoundException {
- int itab = myName.getItab();
- if (itab == 0)return mybook;
- WorkSheetHandle sheet = mybook.getWorkSheet(itab-1);
- return sheet;
- }
-
- /**
- * Set the scope of this name to that of the handle passed in.
- *
- * This can either be a WorkbookHandle or a WorksheetHandle
- *
- *note: this will only be functional for the workbook that the name is contained in,
- *you cannot change the scope to a different Document with this method.
- *
- * @param scope Workbookhandle or WorksheetHandle
- */
- public void setScope(Handle scope) {
- int newitab = 0;
- if(scope instanceof WorkSheetHandle) {
- newitab = (((WorkSheetHandle)scope).getSheetNum()+1);
- }
- try {
- myName.setNewScope(newitab);
- } catch (WorkSheetNotFoundException e) {
- // this really shouldnt happen unless you are passing a scope in from a different workbook
- Logger.logErr("ERROR: setting new scope on name: " + e);
- }
- }
- /**
- * Create a new named range in the workbook
- * note that this does not set the actual range, just the workbook and name,
- * follow up with setLocation
-
- *
- * @param namestr
- * @param myb
- * @deprecated
- */
- public NameHandle(String namestr, WorkBookHandle myb){
- mybook = myb;
- myName = new Name(mybook.getWorkBook(),namestr);
- this.setName(namestr);
- }
-
- /**
- * Create a new named range in the workbook
-
- *
- * @param name name that should be used to reference this named range
- * @param location rangeDef Range of the cells for this named range, in excel syntax including sheet name, ie "Sheet1!A1:D1"
- * @param book WorkBookHandle to insert this named range into
- */
- public NameHandle(String name, String location, WorkBookHandle book){
- mybook = book;
- myName = new Name(mybook.getWorkBook(),name);
- this.setName(name);
- this.setLocation(location);
- mybook.getWorkBook().associateDereferencedNames(myName);
- }
-
-
- /**
- * Return an XML representation of this name record
- */
- public String getXML() {
- StringBuffer retXML = new StringBuffer();
- String nmv = getExpressionString();
- if(nmv.indexOf("=!")>-1) { // add the sheetname
- Boundsheet bs = myName.getSheet();
- if(bs!=null) {
- nmv = bs.getSheetName() + "!" + nmv;
- }else{ // TODO: why no sheet defined for name???
- nmv = StringTool.replaceChars("!", nmv, "");
- }
- }
- // it's possible that name expression can have quotes and other non-compliant characters
- nmv = io.starter.toolkit.StringTool.convertXMLChars(nmv);
-
- String nmx = getName();
- nmx = io.starter.toolkit.StringTool.convertXMLChars(nmx);
-
- if(nmx.length()==1) { // deal with snafu character names
- if(Character.isLetterOrDigit(nmx.charAt(0))) {
- Logger.logInfo("NameHandle getting XML for name: " + nmx);
- }else {
- nmx = "#NAME";
- }
- }
-
- if (nmv.startsWith("="))
- nmv = nmv.substring(1);
- retXML.append(" ");
- return retXML.toString();
- }
-
-
- /**
- *
- * @return String XML rep of all the cells referenced by this range
- */
- public String getExpandedXML() {
- String nmv = getExpressionString();
- if(nmv.indexOf("=!")>-1) { // add the sheetname
- Boundsheet bs = myName.getSheet();
- if(bs!=null) {
- nmv = bs.getSheetName() + "!" + nmv;
- }else{ // TODO: why no sheet defined for name???
- nmv = StringTool.replaceChars("!", nmv, "");
- }
- }
- String nmx = getName();
- nmx = io.starter.toolkit.StringTool.convertXMLChars(nmx);
-
- if(nmx.length()==1) { // deal with snafu character names
- if(Character.isLetterOrDigit(nmx.charAt(0))) {
- Logger.logInfo("NameHandle getting XML for name: " + nmx);
- }else {
- nmx = "#NAME";
- }
- }
-
- if (nmv.startsWith("="))
- nmv = nmv.substring(1);
- StringBuffer retXML = new StringBuffer();
- retXML.append("\t\n");
- try{
- CellHandle[] cells= getCells();
-
- for (int i= 0; i < cells.length; i++) {
- retXML.append("\t\t" + cells[i].getXML() + "\n");
- }
- }catch(CellNotFoundException ex) {
- Logger.logErr("NameHandle.getExpandedXML failed: ",ex);
- }
- retXML.append(" \n");
-
- return retXML.toString();
- }
- /** sets the default format id for the Name's Cells
-
- @param int Format Id for all Cells in Name
- */
- public void setFormatId(int i){
- // myName.setXFRecord(i);
- // TODO: why doesn't this work with myName?
- try {
- CellHandle[] cs = this.getCells();
- for(int t = 0;t1) {
- throw new WorkBookException("NamedRange.updateRow Object array failed: too many CellRanges.",WorkBookException.RUNTIME_ERROR);
- }else if(rngs.length ==0){
- throw new WorkBookException("NamedRange.updateRow Object array failed: zero CellRanges",WorkBookException.RUNTIME_ERROR);
- }
-
- //
- WorkSheetHandle shtx = rngs[0].getSheet();
- int x = rngs[0].firstcellrow;
-
-
- RowHandle[] rx = rngs[0].getRows();
- boolean found = false;
- // iterate, find, update
- for(int t=0;t1) {
- throw new WorkBookException("NamedRange.updateRow Object array failed: too many CellRanges.",WorkBookException.RUNTIME_ERROR);
- }else if(rngs.length ==0){
- throw new WorkBookException("NamedRange.updateRow Object array failed: zero CellRanges",WorkBookException.RUNTIME_ERROR);
- }
-
- //
- WorkSheetHandle shtx = rngs[0].getSheet();
- int x = rngs[0].firstcellrow;
-
-
- RowHandle[] rx = rngs[0].getRows();
- boolean found = false;
- // iterate, find, update
- for(int t=0;tidxcol){
- if(cx[idxcol].getStringVal().equalsIgnoreCase(objarr[idxcol].toString())){
- found = true;
- for(int z=0;z1) {
- throw new WorkBookException("NamedRange.add Object array failed: too many CellRanges.",WorkBookException.RUNTIME_ERROR);
- }else if(rngs.length ==0){
- throw new WorkBookException("NamedRange.add Object array failed: zero CellRanges",WorkBookException.RUNTIME_ERROR);
- }
-
- //
- WorkSheetHandle shtx = rngs[0].getSheet();
-
- int x = rngs[0].firstcellrow;
- CellHandle[] cxx = shtx.insertRow(x, objarr, true);
-
- //for(int t=0;t1) {
- throw new WorkBookException("NamedRange.addCell failed -- more than one cell range defined in this NameHandle, cannot determine where to add cell.",WorkBookException.RUNTIME_ERROR);
- }
- rngs[0].addCellToRange(cx);
- setLocation(rngs[0].getRange());
- }
-
- /** set the referenced cells for the named range
- *
- * this reference should be in the standard excel syntax including sheetname,
- * for instance "Sheet1!A1:Z255"
- *
- *
- */
- public void setLocation(String strloc){
-
- // if there is no sheetname, and no sheet, then this is an unusable name and cannot be added
- if((strloc.indexOf("!")==-1)&&(strloc.indexOf("=")==-1)){
- if(this.get2DSheetName()==null){
- this.remove();
- throw new IllegalArgumentException("Named Range References must include a Sheet name.");
- }else
- strloc = this.get2DSheetName() + "!" + strloc;
- }
- try{myName.setLocation(strloc);
- }catch(FunctionNotSupportedException e) {
- Logger.logWarn("NameHandle.setLocation :" + strloc + " failed: " + e.toString());
- }
- }
-
- /** get the referenced named cell range as string in standard excel syntax including sheetname,
- *
- * for instance "Sheet1!A1:Z255"
- *
- */
- public String getLocation(){
- try{
- String loc = myName.getLocation();
- return loc;
- }catch(Exception e) {
- Logger.logErr("Error getting named range location" + e);
- return null;
- }
- }
-
-
-
-
-
- /** set the name String for the range definition
-
- @param String definition name
- */
- public void setName(String newname){
- myName.setName(newname);
- }
-
- /** returns the name String for the range definition
-
- @return String definition name
- */
- public String getName(){return myName.getName();}
-
- public String toString(){return getName();}
-
- /** returns the name's formula String for the range definition
-
- @return String the expression string
- */
- public String getExpressionString(){
- try{
- return myName.getExpressionString();
- }catch(Exception e){
- if(DEBUGLEVEL > -1)Logger.logWarn("Could not parse expression string for name: " + this.getName());
- }
- return "#ERR";
- }
-
- /** removes this Named Range from the WorkBook.
- *
- * @return whether the removal was a success
- */
- public boolean remove() {
- boolean success = false;
- try{
- success = this.myName.getWorkBook().removeName(myName);
- }catch(Exception e) {
- return false;
- }
- return success;
- }
-
- /** set whether the CellRanges referenced by the NameHandle
- * will add blank records to the WorkBook for any missing Cells
- * contained within the range.
- *
- * @param b set whether to create blank records for missing Cells
- */
- public void setCreateBlanks(boolean b) {
- createblanks= b;
- }
-
- /** gets the array of Cells in this Name
- *
- * NOTE: this method variation also returns the Sheetname for the name record if not null.
- *
- * Thus this method is limited to use with 2D ranges.
- *
- *
- * @return Cell[] all Cells defined in this Name
- @param fragment whether to enclose result in NameHandle tag
- */
- public String getCellRangeXML(boolean fragment){
- StringBuffer sbx = new StringBuffer();
- if(!fragment)
- sbx.append("");
- sbx.append("");
- sbx.append(getCellRangeXML());
- sbx.append(" ");
- return sbx.toString();
- }
-
- /** gets the array of Cells in this Name
-
- @return Cell[] all Cells defined in this Name
- */
- public String getCellRangeXML(){
- StringBuffer sbx = new StringBuffer();
- try {
- CellHandle[] celx = this.getCells();
- RowHandle rowhold = null;
- for(int x=0;x");
- sbx.append(celx[x].getXML()); // ignores merged ranges here
- }else if(rowhold.getRowNumber() == rx.getRowNumber()){
- sbx.append(celx[x].getXML()); // ignores merged ranges here
- }else{
- sbx.append("");
- rowhold = rx;
- sbx.append("");
- sbx.append(celx[x].getXML()); // ignores merged ranges here
- }
- }
- sbx.append(" ");
- }catch(CellNotFoundException ex) {
- Logger.logErr("NameHandle.getCellRangeXML failed: ",ex);
- }
- // sbx.append("");
- return sbx.toString();
- }
-
- /** gets the array of Cells in this Name
-
- @return Cell[] all Cells defined in this Name
- */
- public CellHandle[] getCells()
- throws CellNotFoundException{
- if(false)
- return null;
- // first get the ptgArea3d from the parsed expression
- try{
- CompatibleVector cellhandles = new CompatibleVector();
- CellRange[] rngz = this.getCellRanges();
- if (rngz!=null) {
- for(int t=0;t=0;b--)cellhandles.add(cells[b]);
- for(int b =0; b< cells.length;b++)
- if(cells[b]!=null)
- cellhandles.add(cells[b]);
- }catch(Exception ex){
- Logger.logWarn("Could not get cells for range: " + rngz[t]);
- }
- }
- } else {
- return null;
- }
- CellHandle[] ret = new CellHandle[cellhandles.size()];
- return (CellHandle[]) cellhandles.toArray(ret);
- }catch(Exception e){
- if(e instanceof CellNotFoundException)
- throw (CellNotFoundException)e;
- throw new CellNotFoundException(e.toString());
- }
- }
-
-
- /** Get an Array of CellRanges, one per referenced WorkSheet.
- *
- * If this method throws CellNotFoundExceptions, then you are
- * addressing a sparsely populated CellRange.
- *
- * Use 'setCreateBlanks(true)' to populate these Cells and avoid
- * this error.
- *
- * @return
- * @throws Exception
- */
- public CellRange[] getCellRanges()
- throws Exception{
- if(initialRange!=null){
- CellRange[] ret = {initialRange};
- return ret;
- }
- // 20100217 KSC: try a better way (that can handle 3D refs and complex cell ranges)
- String loc= myName.getLocation(); // may contain one or more ranges, separated by ","'s if complex
- WorkSheetHandle[] sheets = this.getReferencedSheets();
- // handle commas within quoted sheet names (TestExtenXLSEngine.TestQuotedSheetsWithCommansInNRs)
- // NOTE that sheetnames must be properly qualified for the split to work below
- String[] nranges= loc.split(",(?=([^'|\"]*'[^'|\"]*'|\")*[^'|\"]*$)");
- // below cannot handle commas embedded within quotes
-// String[] nranges= StringTool.splitString(loc, ","); // TODO: can be another delimeter?
- CellRange[] ranges = new CellRange[nranges.length];
- for (int i= 0; i < nranges.length; i++) {
- String r= nranges[i];
- if (r.indexOf("!")==-1) { // no sheetname
- r= sheets[i] + "!" + r;
- }
- ranges[i] = new CellRange(r,mybook,createblanks);
- ranges[i].setParent(this.myName);
- }
-
- return ranges;
- }
-
- /** Get WorkSheetHandles for all of the Boundsheets referenced in
- * this NameHandle.
- *
- * @return an array of WorkSheetHandles referenced in this Name
- */
- public WorkSheetHandle[] getReferencedSheets()
- throws WorkSheetNotFoundException{
- //first get the ptgArea3d from the parsed expression
- Boundsheet[] bs = myName.getBoundSheets();
- if(bs == null)
- throw new WorkSheetNotFoundException("Worksheet for Named Range: "+this.toString()+":"+ this.myName.getExpressionString());
- if(bs[0]==null)
- throw new WorkSheetNotFoundException("Worksheet for Named Range: "+this.toString()+":" + this.myName.getExpressionString());
- WorkSheetHandle[] ret = new WorkSheetHandle[bs.length];
- for(int x=0;x .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.*
+import io.starter.formats.XLS.formulas.Ptg
+import io.starter.toolkit.CompatibleVector
+import io.starter.toolkit.Logger
+import io.starter.toolkit.StringTool
+import org.json.JSONArray
+import org.json.JSONObject
+
+import io.starter.OpenXLS.JSONConstants.JSON_CELL
+import io.starter.OpenXLS.JSONConstants.JSON_CELLS
+
+/**
+ * The NameHandle provides access to a Named Range and its Cells.
+ *
+ * Use the NameHandle to work with individual Named Ranges in an XLS file.
+ *
+ * With a NameHandle you can:
+ *
+ *
+ * get a handle to the Cells in a Name
+ * set the default formatting for a Name
+ *
+ *
+ *
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see FormulaHandle
+ */
+class NameHandle {
+
+ private var myName: Name? = null
+ private var mybook: WorkBook? = null
+ private val DEBUGLEVEL = -1
+ private var createblanks = false
+ private var initialRange: CellRange? = null
+
+ /**
+ * Returns a handle to the object (either workbook or sheet) that is scoped
+ * to the name record
+ *
+ *
+ * Default scope is a WorkBookHandle, else the WorkSheetHandle is returned.
+ *
+ * @return the scope of the name
+ */
+ /**
+ * Set the scope of this name to that of the handle passed in.
+ *
+ *
+ * This can either be a WorkbookHandle or a WorksheetHandle
+ *
+ *
+ * note: this will only be functional for the workbook that the name is contained in,
+ * you cannot change the scope to a different Document with this method.
+ *
+ * @param scope Workbookhandle or WorksheetHandle
+ */
+ // this really shouldnt happen unless you are passing a scope in from a different workbook
+ var scope: Handle?
+ @Throws(WorkSheetNotFoundException::class)
+ get() {
+ val itab = myName!!.itab.toInt()
+ return if (itab == 0) mybook else mybook!!.getWorkSheet(itab - 1)
+ }
+ set(scope) {
+ var newitab = 0
+ if (scope is WorkSheetHandle) {
+ newitab = scope.sheetNum + 1
+ }
+ try {
+ myName!!.setNewScope(newitab)
+ } catch (e: WorkSheetNotFoundException) {
+ Logger.logErr("ERROR: setting new scope on name: $e")
+ }
+
+ }
+
+
+ /**
+ * Return an XML representation of this name record
+ */
+ // add the sheetname
+ // TODO: why no sheet defined for name???
+ // it's possible that name expression can have quotes and other non-compliant characters
+ // deal with snafu character names
+ // if not workbook-scoped, add sheet scope for later retrieval
+ val xml: String
+ get() {
+ val retXML = StringBuffer()
+ var nmv = expressionString
+ if (nmv.indexOf("=!") > -1) {
+ val bs = myName!!.sheet
+ if (bs != null) {
+ nmv = bs.sheetName + "!" + nmv
+ } else {
+ nmv = StringTool.replaceChars("!", nmv, "")
+ }
+ }
+ nmv = io.starter.toolkit.StringTool.convertXMLChars(nmv)
+
+ var nmx = name
+ nmx = io.starter.toolkit.StringTool.convertXMLChars(nmx)
+
+ if (nmx.length == 1) {
+ if (Character.isLetterOrDigit(nmx[0])) {
+ Logger.logInfo("NameHandle getting XML for name: $nmx")
+ } else {
+ nmx = "#NAME"
+ }
+ }
+
+ if (nmv.startsWith("="))
+ nmv = nmv.substring(1)
+ retXML.append(" ")
+ return retXML.toString()
+ }
+
+
+ /**
+ * @return String XML rep of all the cells referenced by this range
+ */
+ // add the sheetname
+ // TODO: why no sheet defined for name???
+ // deal with snafu character names
+ val expandedXML: String
+ get() {
+ var nmv = expressionString
+ if (nmv.indexOf("=!") > -1) {
+ val bs = myName!!.sheet
+ if (bs != null) {
+ nmv = bs.sheetName + "!" + nmv
+ } else {
+ nmv = StringTool.replaceChars("!", nmv, "")
+ }
+ }
+ var nmx = name
+ nmx = io.starter.toolkit.StringTool.convertXMLChars(nmx)
+
+ if (nmx.length == 1) {
+ if (Character.isLetterOrDigit(nmx[0])) {
+ Logger.logInfo("NameHandle getting XML for name: $nmx")
+ } else {
+ nmx = "#NAME"
+ }
+ }
+
+ if (nmv.startsWith("="))
+ nmv = nmv.substring(1)
+ val retXML = StringBuffer()
+ retXML.append("\t\n")
+ try {
+ val cells = cells
+
+ for (i in cells!!.indices) {
+ retXML.append("\t\t" + cells[i].xml + "\n")
+ }
+ } catch (ex: CellNotFoundException) {
+ Logger.logErr("NameHandle.getExpandedXML failed: ", ex)
+ }
+
+ retXML.append(" \n")
+
+ return retXML.toString()
+ }
+
+ /**
+ * get the referenced named cell range as string in standard excel syntax including sheetname,
+ *
+ *
+ * for instance "Sheet1!A1:Z255"
+ */
+ /**
+ * set the referenced cells for the named range
+ *
+ *
+ * this reference should be in the standard excel syntax including sheetname,
+ * for instance "Sheet1!A1:Z255"
+ */
+ // if there is no sheetname, and no sheet, then this is an unusable name and cannot be added
+ var location: String?
+ get() {
+ try {
+ return myName!!.location
+ } catch (e: Exception) {
+ Logger.logErr("Error getting named range location$e")
+ return null
+ }
+
+ }
+ set(strloc) {
+ var strloc = strloc
+ if (strloc.indexOf("!") == -1 && strloc.indexOf("=") == -1) {
+ if (this .2 DSheetName == null)
+ {
+ this.remove()
+ throw IllegalArgumentException("Named Range References must include a Sheet name.")
+ }
+ else
+ strloc = this.2DSheetName+"!"+strloc
+ }
+ try {
+ myName!!.location = strloc
+ } catch (e: FunctionNotSupportedException) {
+ Logger.logWarn("NameHandle.setLocation :$strloc failed: $e")
+ }
+
+ }
+
+ /**
+ * returns the name String for the range definition
+ *
+ * @return String definition name
+ */
+ /**
+ * set the name String for the range definition
+ *
+ * @param String definition name
+ */
+ var name: String
+ get() = myName!!.name
+ set(newname) {
+ myName!!.name = newname
+ }
+
+ /**
+ * returns the name's formula String for the range definition
+ *
+ * @return String the expression string
+ */
+ val expressionString: String
+ get() {
+ try {
+ return myName!!.expressionString
+ } catch (e: Exception) {
+ if (DEBUGLEVEL > -1) Logger.logWarn("Could not parse expression string for name: " + this.name)
+ }
+
+ return "#ERR"
+ }
+
+ /**
+ * gets the array of Cells in this Name
+ *
+ * @return Cell[] all Cells defined in this Name
+ */
+ // ignores merged ranges here
+ // ignores merged ranges here
+ // ignores merged ranges here
+ // sbx.append("");
+ val cellRangeXML: String
+ get() {
+ val sbx = StringBuffer()
+ try {
+ val celx = this.cells
+ var rowhold: RowHandle? = null
+ for (x in celx!!.indices) {
+ val rx = celx[x].row
+ if (x == 0) {
+ rowhold = rx
+ sbx.append("")
+ sbx.append(celx[x].xml)
+ } else if (rowhold!!.rowNumber == rx.rowNumber) {
+ sbx.append(celx[x].xml)
+ } else {
+ sbx.append(" ")
+ rowhold = rx
+ sbx.append("")
+ sbx.append(celx[x].xml)
+ }
+ }
+ sbx.append(" ")
+ } catch (ex: CellNotFoundException) {
+ Logger.logErr("NameHandle.getCellRangeXML failed: ", ex)
+ }
+
+ return sbx.toString()
+ }
+
+ /**
+ * gets the array of Cells in this Name
+ *
+ * @return Cell[] all Cells defined in this Name
+ */
+ // first get the ptgArea3d from the parsed expression
+ // for(int b = (cells.length-1);b>=0;b--)cellhandles.add(cells[b]);
+ val cells: Array?
+ @Throws(CellNotFoundException::class)
+ get() {
+ if (false)
+ return null
+ try {
+ val cellhandles = CompatibleVector()
+ val rngz = this.cellRanges
+ if (rngz != null) {
+ for (t in rngz.indices) {
+ try {
+ val cells = rngz[t].getCells()
+ for (b in cells!!.indices)
+ if (cells[b] != null)
+ cellhandles.add(cells[b])
+ } catch (ex: Exception) {
+ Logger.logWarn("Could not get cells for range: " + rngz[t])
+ }
+
+ }
+ } else {
+ return null
+ }
+ val ret = arrayOfNulls(cellhandles.size)
+ return cellhandles.toTypedArray() as Array
+ } catch (e: Exception) {
+ if (e is CellNotFoundException)
+ throw e
+ throw CellNotFoundException(e.toString())
+ }
+
+ }
+
+
+ /**
+ * Get an Array of CellRanges, one per referenced WorkSheet.
+ *
+ *
+ * If this method throws CellNotFoundExceptions, then you are
+ * addressing a sparsely populated CellRange.
+ *
+ *
+ * Use 'setCreateBlanks(true)' to populate these Cells and avoid
+ * this error.
+ *
+ * @return
+ * @throws Exception
+ */
+ // 20100217 KSC: try a better way (that can handle 3D refs and complex cell ranges)
+ // may contain one or more ranges, separated by ","'s if complex
+ // handle commas within quoted sheet names (TestExtenXLSEngine.TestQuotedSheetsWithCommansInNRs)
+ // NOTE that sheetnames must be properly qualified for the split to work below
+ // below cannot handle commas embedded within quotes
+ // String[] nranges= StringTool.splitString(loc, ","); // TODO: can be another delimeter?
+ // no sheetname
+ val cellRanges: Array
+ @Throws(Exception::class)
+ get() {
+ if (initialRange != null) {
+ return arrayOf(initialRange)
+ }
+ val loc = myName!!.location
+ val sheets = this.referencedSheets
+ val nranges = loc!!.split(",(?=([^'|\"]*'[^'|\"]*'|\")*[^'|\"]*$)".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
+ val ranges = arrayOfNulls(nranges.size)
+ for (i in nranges.indices) {
+ var r = nranges[i]
+ if (r.indexOf("!") == -1) {
+ r = sheets[i].toString() + "!" + r
+ }
+ ranges[i] = CellRange(r, mybook, createblanks)
+ ranges[i].setParent(this.myName)
+ }
+
+ return ranges
+ }
+
+ /**
+ * Get WorkSheetHandles for all of the Boundsheets referenced in
+ * this NameHandle.
+ *
+ * @return an array of WorkSheetHandles referenced in this Name
+ */
+ //first get the ptgArea3d from the parsed expression
+ val referencedSheets: Array
+ @Throws(WorkSheetNotFoundException::class)
+ get() {
+ val bs = myName!!.boundSheets
+ ?: throw WorkSheetNotFoundException("Worksheet for Named Range: " + this.toString() + ":" + this.myName!!.expressionString)
+ if (bs[0] == null)
+ throw WorkSheetNotFoundException("Worksheet for Named Range: " + this.toString() + ":" + this.myName!!.expressionString)
+ val ret = arrayOfNulls(bs.size)
+ for (x in ret.indices) {
+ ret[x] = mybook!!.getWorkSheet(bs[x].toString())
+ }
+ return ret
+ }
+
+ /**
+ * return the calculated value of this Name
+ * if it contains a parsed Expression (Formula)
+ *
+ * @return
+ * @throws FunctionNotSupportedException
+ */
+ val calculatedValue: Any
+ @Throws(FunctionNotSupportedException::class)
+ get() = myName!!.calculatedValue
+
+ /**
+ * Return a JSON object representing this name Handle.
+ * name:'nameOfRange'
+ * cellrange:'Sheet1!A1:B1'
+ *
+ * @return
+ */
+ val json: String
+ get() = getJSON(false)
+
+ /**
+ * Returns a JSON object in the same format as [CellRange.getJSON].
+ */
+ val jsonCellRange: JSONObject
+ get() {
+ val theRange = JSONObject()
+ val cells = JSONArray()
+ try {
+ val chandles = cells
+ for (i in chandles.indices) {
+ val thisCell = chandles[i]
+ val result = JSONObject()
+
+ result.put(JSON_CELL, thisCell.jsonObject)
+ cells.put(result)
+ }
+ theRange.put(JSON_CELLS, cells)
+ } catch (e: Exception) {
+ Logger.logErr("Error getting NamedRange JSON: $e")
+ }
+
+ return theRange
+ }
+
+ /**
+ * return the sheetname for a 2D named range
+ *
+ *
+ * NOTE: Does not work for 3D ranges
+ *
+ * @return the Sheet name if this is a 2d range
+ */
+ val 2DSheetName:String?
+ get()
+ {
+ try {
+ return this.myName!!.boundSheets!![0].sheetName
+ } catch (e: Exception) {
+ try {
+ return this.myName!!.sheet!!.sheetName
+ } catch (ex: Exception) {
+ return null
+ }
+
+ }
+
+ }
+
+ /**
+ * Creates a new Named Range from a CellRange
+ *
+ * @param Name of the Range, the CellRange referenced by the Name
+ */
+ constructor(namestr: String, cr: CellRange) {
+ mybook = cr.workBook
+ initialRange = cr // cache
+ myName = Name(mybook!!.workBook, namestr)
+ this.name = namestr
+ this.location = cr.toString()
+ }
+
+ /**
+ * Create a NameHandle from an internal Name record
+ *
+ * @param c
+ * @param myb
+ */
+ constructor(c: Name, myb: WorkBookHandle) {
+ myName = c
+ mybook = myb
+ }
+
+ /**
+ * Create a new named range in the workbook
+ * note that this does not set the actual range, just the workbook and name,
+ * follow up with setLocation
+ *
+ * @param namestr
+ * @param myb
+ */
+ @Deprecated("")
+ constructor(namestr: String, myb: WorkBookHandle) {
+ mybook = myb
+ myName = Name(mybook!!.workBook, namestr)
+ this.name = namestr
+ }
+
+ /**
+ * Create a new named range in the workbook
+ *
+ * @param name name that should be used to reference this named range
+ * @param location rangeDef Range of the cells for this named range, in excel syntax including sheet name, ie "Sheet1!A1:D1"
+ * @param book WorkBookHandle to insert this named range into
+ */
+ constructor(name: String, location: String, book: WorkBookHandle) {
+ mybook = book
+ myName = Name(mybook!!.workBook, name)
+ this.name = name
+ this.location = location
+ mybook!!.workBook.associateDereferencedNames(myName!!)
+ }
+
+ /**
+ * sets the default format id for the Name's Cells
+ *
+ * @param int Format Id for all Cells in Name
+ */
+ fun setFormatId(i: Int) {
+ // myName.setXFRecord(i);
+ // TODO: why doesn't this work with myName?
+ try {
+ val cs = this.cells
+ for (t in cs!!.indices) {
+ cs[t].formatId = i
+ }
+ } catch (ex: CellNotFoundException) {
+ Logger.logErr("NameHandle.setFormatId failed: ", ex)
+ }
+
+ }
+
+ /**
+ * deletes a row of cells in this named range, shifts subsequent
+ * rows up.
+ *
+ * @param the column to use as unique index
+ */
+ @Throws(Exception::class)
+ fun deleteRow(idxcol: Int) {
+ val rngs = cellRanges
+ if (rngs.size > 1) {
+ throw WorkBookException("NamedRange.updateRow Object array failed: too many CellRanges.", WorkBookException.RUNTIME_ERROR)
+ } else if (rngs.size == 0) {
+ throw WorkBookException("NamedRange.updateRow Object array failed: zero CellRanges", WorkBookException.RUNTIME_ERROR)
+ }
+
+ //
+ val shtx = rngs[0].sheet
+ val x = rngs[0].firstcellrow
+
+
+ val rx = rngs[0].rows
+ val found = false
+ // iterate, find, update
+ for (t in rx.indices) {
+
+ }
+ }
+
+ /**
+ * update a row of cells in this named range
+ *
+ * @param an array of Objects to update existing
+ * @param the column to use as unique index
+ */
+ @Throws(Exception::class)
+ fun updateRow(objarr: Array, idxcol: Int) {
+ val rngs = cellRanges
+ if (rngs.size > 1) {
+ throw WorkBookException("NamedRange.updateRow Object array failed: too many CellRanges.", WorkBookException.RUNTIME_ERROR)
+ } else if (rngs.size == 0) {
+ throw WorkBookException("NamedRange.updateRow Object array failed: zero CellRanges", WorkBookException.RUNTIME_ERROR)
+ }
+
+ //
+ val shtx = rngs[0].sheet
+ val x = rngs[0].firstcellrow
+
+
+ val rx = rngs[0].rows
+ var found = false
+ // iterate, find, update
+ for (t in rx.indices) {
+
+ val cx = rx[t].cells
+ if (cx.size > idxcol) {
+ if (cx[idxcol].stringVal!!.equals(objarr[idxcol].toString(), ignoreCase = true)) {
+ found = true
+ for (z in cx.indices) {
+ cx[z].`val` = objarr[z]
+ }
+ }
+ }
+ }
+
+ if (!found)
+ this.addRow(objarr)
+ }
+
+
+ /**
+ * add a row of cells to this named range
+ *
+ * @param an array of Objects to insert at last rown
+ */
+ @Throws(Exception::class)
+ fun addRow(objarr: Array) {
+ val rngs = cellRanges
+ if (rngs.size > 1) {
+ throw WorkBookException("NamedRange.add Object array failed: too many CellRanges.", WorkBookException.RUNTIME_ERROR)
+ } else if (rngs.size == 0) {
+ throw WorkBookException("NamedRange.add Object array failed: zero CellRanges", WorkBookException.RUNTIME_ERROR)
+ }
+
+ //
+ val shtx = rngs[0].sheet
+
+ val x = rngs[0].firstcellrow
+ val cxx = shtx!!.insertRow(x, objarr, true)
+
+ //for(int t=0;t 1) {
+ throw WorkBookException("NamedRange.addCell failed -- more than one cell range defined in this NameHandle, cannot determine where to add cell.", WorkBookException.RUNTIME_ERROR)
+ }
+ rngs[0].addCellToRange(cx)
+ location = rngs[0].getRange()
+ }
+
+ override fun toString(): String {
+ return name
+ }
+
+ /**
+ * removes this Named Range from the WorkBook.
+ *
+ * @return whether the removal was a success
+ */
+ fun remove(): Boolean {
+ var success = false
+ try {
+ success = this.myName!!.workBook!!.removeName(myName)
+ } catch (e: Exception) {
+ return false
+ }
+
+ return success
+ }
+
+ /**
+ * set whether the CellRanges referenced by the NameHandle
+ * will add blank records to the WorkBook for any missing Cells
+ * contained within the range.
+ *
+ * @param b set whether to create blank records for missing Cells
+ */
+ fun setCreateBlanks(b: Boolean) {
+ createblanks = b
+ }
+
+ /**
+ * gets the array of Cells in this Name
+ *
+ *
+ * NOTE: this method variation also returns the Sheetname for the name record if not null.
+ *
+ *
+ * Thus this method is limited to use with 2D ranges.
+ *
+ * @param fragment whether to enclose result in NameHandle tag
+ * @return Cell[] all Cells defined in this Name
+ */
+ fun getCellRangeXML(fragment: Boolean): String {
+ val sbx = StringBuffer()
+ if (!fragment)
+ sbx.append("")
+ sbx.append("")
+ sbx.append(cellRangeXML)
+ sbx.append(" ")
+ return sbx.toString()
+ }
+
+ /**
+ * Sets the location lock on the Cell Reference at the
+ * specified location
+ *
+ *
+ * Used to prevent updating of the Cell Reference when
+ * Cells are moved.
+ *
+ * @param location of the Cell Reference to be locked/unlocked
+ * @param lock status setting
+ * @return boolean whether the Cell Reference was found and modified
+ */
+ fun setLocationLocked(loc: String, l: Boolean): Boolean {
+ var x = Ptg.PTG_LOCATION_POLICY_UNLOCKED
+ if (l) x = Ptg.PTG_LOCATION_POLICY_LOCKED
+ return myName!!.setLocationPolicy(loc, x)
+ }
+
+
+ /**
+ * Return a JSON object representing this name Handle.
+ * name:'nameOfRange'
+ * cellrange:'Sheet1!A1:B1'
+ * cells:celldata
+ *
+ * @param whether to return cell data
+ * @return
+ */
+ fun getJSON(celldata: Boolean): String {
+ val theNameHandle = JSONObject()
+ try {
+ theNameHandle.put("name", this.name)
+ theNameHandle.put("cellrange", myName!!.location)
+
+ if (celldata) {
+ val ret = StringBuffer()
+ val cx1 = cells
+ var p = cx1!![0].rowNum
+ for (x in cx1.indices) {
+ if (cx1[x] != null) {
+ if (cx1[x].rowNum != p) {
+ ret.append("\r\n")
+ p = cx1[x].rowNum
+ }
+ ret.append("'")
+ try {
+ ret.append(cx1[x].stringVal)
+ } catch (ex: Exception) { // handles empties
+ //
+ }
+
+ if (x != cx1.size - 1)
+ ret.append("',")
+ else
+ ret.append("'")
+ }
+ }
+
+ theNameHandle.put("celldata", ret.toString())
+ }
+ } catch (e: Exception) {
+ Logger.logErr("Error creating JSON name handle: $e")
+ }
+
+ return theNameHandle.toString()
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/PivotTableHandle.java b/src/main/java/io/starter/OpenXLS/PivotTableHandle.java
deleted file mode 100644
index ee6bb15..0000000
--- a/src/main/java/io/starter/OpenXLS/PivotTableHandle.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-
-import org.json.JSONObject;
-
-import io.starter.formats.XLS.*;
-import io.starter.toolkit.Logger;
-
-
-/** PivotTable Handle allows for manipulation of PivotTables within a WorkBook.
-
- @see WorkBookHandle
- @see WorkSheetHandle
- @see CellHandle
- */
-/**
- *
- */
-/**
- *
- */
-/**
- *
- */
-public class PivotTableHandle {
-
- public static int AUTO_FORMAT_Report1 = 1;
- public static int AUTO_FORMAT_Report2 = 2;
- public static int AUTO_FORMAT_Report3 = 3;
- public static int AUTO_FORMAT_Report4 = 4;
- public static int AUTO_FORMAT_Report5 = 5;
- public static int AUTO_FORMAT_Report6 = 6;
- public static int AUTO_FORMAT_Report7 = 7;
- public static int AUTO_FORMAT_Report8 = 8;
- public static int AUTO_FORMAT_Report9 = 9;
- public static int AUTO_FORMAT_Report10 = 10;
- public static int AUTO_FORMAT_Table1 = 11;
- public static int AUTO_FORMAT_Table2 = 12;
- public static int AUTO_FORMAT_Table3 = 13;
- public static int AUTO_FORMAT_Table4 = 14;
- public static int AUTO_FORMAT_Table5 = 15;
- public static int AUTO_FORMAT_Table6 = 16;
- public static int AUTO_FORMAT_Table7 = 17;
- public static int AUTO_FORMAT_Table8 = 18;
- public static int AUTO_FORMAT_Table9 = 19;
- public static int AUTO_FORMAT_Table10 = 20;
- public static int AUTO_FORMAT_Classic = 30;
- private Sxview pt;
- private WorkBookHandle book;
- private WorkSheetHandle worksheet;
-
- /**
- * Create a new PivotTableHandle from an Excel PivotTable
- *
- * @param PivotTable
- * - the PivotTable to create a handle for.
- */
- public PivotTableHandle(Sxview f, WorkBookHandle bk) {
- pt = f;
- book = bk;
- //SxStreamID sxid= bk.getWorkBook().getPivotStrean(pt.getICache());
- //cellRange= sxid.getCellRange();
- }
-
- public WorkSheetHandle getWorkSheetHandle() {
- return worksheet;
- }
-
- /**
- * @return Returns the cellRange.
- */
- public CellRange getDataSourceRange() {
- SxStreamID sxid= book.getWorkBook().getPivotStream(pt.getICache());
- return sxid.getCellRange();
- }
-
- /**
- * Sets the Pivot Table Range to represent the Data to analyse
- * NOTE: any existing data will be replaced
- * @param cellRange The cellRange to set.
- */
- public void setSourceDataRange(CellRange cellRange) {
- SxStreamID sxid= book.getWorkBook().getPivotStream(pt.getICache());
- sxid.setCellRange(cellRange);
- try {
- pt.setNPivotFields((short) cellRange.getCols().length);
- } catch (ColumnNotFoundException e) {
-
- }
-
- }
-
- /**
- * Sets the Pivot Table Range to represent the Data to analyse
- * NOTE: any existing data will be replaced
- * If the cell range does not contain sheet information, the sheet that the pivot table is located will be used
- * @param cellRange
- */
- public void setSourceDataRange(String range) {
- int[] rc= ExcelTools.getRangeCoords(range);
- if (range.indexOf("!")==-1)
- range= this.getWorkSheetHandle() + "!" + range;
- SxStreamID sxid= book.getWorkBook().getPivotStream(pt.getICache());
- sxid.setCellRange(range);
-
- pt.setNPivotFields((short) ((rc[3]-rc[1])+1));
- }
-
- /**
- * Sets the Pivot Table data source from a named range
- * @param namedrange Named Range
- */
- public void setSource(String namedrange) {
-// TODO: finish; update DCONNAME
- }
-
- /**
- * get the Name of the PivotTable
- *
- * @return String - value of the PivotTable if stored as a String.
- */
- public String getTableName() {
- return pt.getTableName();
- }
-
- /**
- * set the Name of the PivotTable
- *
- * @param String
- * - value of the PivotTable if stored as a String.
- */
- public void setTableName(String tx) {
- pt.setTableName(tx);
- }
-
- /**
- * returns the name of the data field
- * @return
- */
- public String getDataName() {
- return pt.getDataName();
- }
-
- /**
- * sets the name of the data field for this pivot table
- * @param name
- */
- public void setDataName(String name) {
- pt.setDataName(name);
- }
- /**
- * returns whether a given row is contained in this PivotTable
- *
- * @param int the row number
- * @return boolean whether the row is in the table
- */
- public boolean containsRow(int x) {
- if ((x <= pt.getRwLast()) && (x >= pt.getRwFirst()))
- return true;
- return false;
- }
-
- /**
- * return a more friendly
- *
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return this.getTableName();
- }
-
- /**
- * returns whether a given col is contained in this PivotTable
- *
- * @param int the column number
- * @return boolean whether the col is in the table
- */
- public boolean containsCol(int x) {
- if ((x <= pt.getColLast()) && (x >= pt.getColFirst()))
- return true;
- return false;
- }
-
- /**
- * Takes a string as a current PivotTable location, and changes that pointer
- * in the PivotTable to the new string that is sent. This can take single
- * cells "A5" and cell ranges, "A3:d4" Returns true if the cell range
- * specified in PivotTableLoc exists & can be changed else false. This also
- * cannot change a cell pointer to a cell range or vice versa.
- *
- * @param String
- * - range of Cells within PivotTable to modify
- * @param String
- * - new range of Cells within PivotTable
- *
- *
- * public boolean changePivotTableLocation(String PivotTableLoc,
- * String newLoc) throws PivotTableNotFoundException{
- *
- * Logger.logInfo("Changing: " + PivotTableLoc + " to: " +
- * newLoc);
- *
- * return false;
- *
- * }
- */
-
- /**
- * set whether to display row grand totals
- *
- * @param boolean whether to display row grand totals
- */
- public void setRowsHaveGrandTotals(boolean b) {
- pt.setFRwGrand(b);
- }
-
- /**
- * get whether table displays row grand totals
- *
- * @return boolean whether table displays row grand total
- */
- public boolean getRowsHaveGrandTotals() {
- return pt.getFRwGrand();
- }
-
- /**
- * set whether to display a column grand total
- *
- * @param boolean whether to display column grand total
- */
- public void setColsHaveGrandTotals(boolean b) {
- pt.setColGrand(b);
- }
-
- /**
- * get whether table displays a column grand total
- *
- * @return boolean whether table displays column grand total
- */
- public boolean getColsHaveGrandTotals() {
- return pt.getFColGrand();
- }
-
- /**
- * set the auto format for the Table
- *
- *
- * The valid formats are:
- *
- * PivotTableHandle.AUTO_FORMAT_Report1
- * PivotTableHandle.AUTO_FORMAT_Report2
- * PivotTableHandle.AUTO_FORMAT_Report3
- * PivotTableHandle.AUTO_FORMAT_Report4
- * PivotTableHandle.AUTO_FORMAT_Report5
- * PivotTableHandle.AUTO_FORMAT_Report6
- * PivotTableHandle.AUTO_FORMAT_Report7
- * PivotTableHandle.AUTO_FORMAT_Report8
- * PivotTableHandle.AUTO_FORMAT_Report9
- * PivotTableHandle.AUTO_FORMAT_Report10
- * PivotTableHandle.AUTO_FORMAT_Table1
- * PivotTableHandle.AUTO_FORMAT_Table2
- * PivotTableHandle.AUTO_FORMAT_Table3
- * PivotTableHandle.AUTO_FORMAT_Table4
- * PivotTableHandle.AUTO_FORMAT_Table5
- * PivotTableHandle.AUTO_FORMAT_Table6
- * PivotTableHandle.AUTO_FORMAT_Table7
- * PivotTableHandle.AUTO_FORMAT_Table8
- * PivotTableHandle.AUTO_FORMAT_Table9
- * PivotTableHandle.AUTO_FORMAT_Table10
- *
- *
- * @param int the auto format Id for the table
- */
- public void setAutoFormatId(int b) {
- pt.setItblAutoFmt((short) b);
- }
-
- /**
- * get the auto format for the Table
- *
- * @return int the auto format Id for the table
- */
- public int getAutoFormatId() {
- return pt.getItblAutoFmt();
- }
-
- /**
- * set whether to auto format the Table
- *
- * @param boolean whether to auto format the table
- */
- public void setUsesAutoFormat(boolean b) {
- pt.setFAutoFormat(b);
- }
-
- /**
- * get whether table has auto format applied
- *
- * @param boolean whether table has auto format applied
- */
- public boolean getUsesAutoFormat() {
- return pt.getFAutoFormat();
- }
-
- /**
- * set Width/Height Autoformat is applied
- *
- * @param boolean whether to apply the Width/Height Autoformat
- */
- public void setAutoWidthHeight(boolean b) {
- pt.setFWH(b);
- }
-
- /**
- * get whether Width/Height Autoformat is applied
- *
- * @return boolean whether the Width/Height Autoformat is applied
- */
- public boolean getAutoWidthHeight() {
- return pt.getFWH();
- }
-
- /**
- * set whether Font Autoformat is applied
- *
- * @param boolean whether to apply the Font Autoformat
- */
- public void setAutoFont(boolean b) {
- pt.setFFont(b);
- }
-
- /**
- * get whether Font Autoformat is applied
- *
- * @return boolean whether the Font Autoformat is applied
- */
- public boolean getAutoFont() {
- return pt.getFFont();
- }
-
- public void removeArtifacts() {
- int[] coords = { pt.getRwFirst() - 2, pt.getColFirst(), pt.getRwLast(),
- pt.getColLast() };
- try {
- CellRange newr = new CellRange(worksheet, coords, true);
- CellHandle[] ch = newr.getCells();
- for (int r = 0; r < ch.length; r++) {
- if (ch[r] != null)
- ch[r].remove(true);
- }
- } catch (Exception e) {
- Logger.logWarn("could not remove artifacts in PivotTableHandle: "
- + e);
- }
- }
-
- /**
- * set whether Alignment Autoformat is applied
- *
- * @param boolean whether to apply the Alignment Autoformat
- */
- public void setAutoAlign(boolean b) {
- pt.setFAlign(b);
- }
-
- /**
- * get whether Alignment Autoformat is applied
- *
- * @return boolean whether the Alignment Autoformat is applied
- */
- public boolean getAutoAlign() {
- return pt.getFAlign();
- }
-
- /**
- * set whether Border Autoformat is applied
- *
- * @param boolean whether to apply the Border Autoformat
- */
- public void setAutoBorder(boolean b) {
- pt.setFBorder(b);
- }
-
- /**
- * get whether Border Autoformat is applied
- *
- * @return boolean whether the Border Autoformat is applied
- */
- public boolean getAutoBorder() {
- return pt.getFBorder();
- }
-
- /**
- * set whether Pattern Autoformat is applied
- *
- * @param boolean whether to apply the Pattern Autoformat
- */
- public void setAutoPattern(boolean b) {
- pt.setFPattern(b);
- }
-
- /**
- * get whether Pattern Autoformat is applied
- *
- * @return boolean whether the Pattern Autoformat is applied
- */
- public boolean getAutoPattern() {
- return pt.getFPattern();
- }
-
- /**
- * set whether Number Autoformat is applied
- *
- * @param boolean whether to apply the Number Autoformat
- */
- public void setAutoNumber(boolean b) {
- pt.setFNumber(b);
- }
-
- /**
- * get whether Number Autoformat is applied
- *
- * @return boolean whether the Number Autoformat is applied
- */
- public boolean getAutoNumber() {
- return pt.getFNumber();
- }
-
- /**
- * set the first row in the PivotTable
- */
- public void setRowFirst(int s) {
- // s--; // these are zero-based rows
- pt.setRwFirst((short) s);
- }
-
- /**
- * get the first row in the PivotTable
- */
- public int getRowFirst() {
- return (int) pt.getRwFirst() + 1;
- }
-
- /**
- * set the last row in the PivotTable
- */
- public void setRowLast(int s) {
- s--;
- pt.setRwLast((short) s);
- }
-
- /**
- * get the last row in the PivotTable
- */
- public int getRowLast() {
- return (int) pt.getRwLast() + 1;
- }
-
- /**
- * set the first Column in the PivotTable
- */
- public void setColFirst(int s) {
- pt.setColFirst((short) s);
- }
-
- /**
- * get the first Column in the PivotTable
- */
- public int getColFirst() {
- return (int) pt.getColFirst();
- }
-
- /**
- * set the last Column in the PivotTable
- */
- public void setColLast(int s) {
- pt.setColLast((short) s);
- }
-
- /**
- * get the last Column in the PivotTable
- */
- public int getColLast() {
- return (int) pt.getColLast();
- }
-
- /**
- * set the first header row
- */
- public void setRowFirstHead(int s) {
- s--;
- pt.setRwFirstHead((short) s);
- }
-
- /**
- * get the first header row
- */
- public int getRowFirstHead() {
- return (int) pt.getRwFirstHead() + 1;
- }
-
- /**
- * set the first Row containing data
- */
- public void setRowFirstData(int s) {
- s--; // zero-based rows
- pt.setRwFirstData((short) s);
- }
-
- /**
- * get the first Row containing data
- */
- public int getRowFirstData() {
- return (int) pt.getRwFirstData() + 1;
- }
-
- /**
- * set the first Column containing data
- */
- public void setColFirstData(int s) {
- pt.setColFirstData((short) s);
- }
-
- /**
- * get the first Column containing data
- */
- public int getColFirstData() {
- return (int) pt.getColFirstData();
- }
-
- /**
- * returns the JSON representation of this PivotTable
- *
- * @return JSON Pivot Table representation
- */
- public String getJSON() {
- // copy all methods to this sucker
- JSONObject thePivot = new JSONObject();
-
- try {
- thePivot.put("title", this.getTableName());
-// thePivot.put("cellrange", this.getCellRange().getRange());
-
- } catch (Exception e) {
- throw new WorkBookException("PivotTableHandle.getJSON failed:" + e,
- WorkBookException.RUNTIME_ERROR);
- }
- return thePivot.toString();
- }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/PivotTableHandle.kt b/src/main/java/io/starter/OpenXLS/PivotTableHandle.kt
new file mode 100644
index 0000000..24c754d
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/PivotTableHandle.kt
@@ -0,0 +1,536 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+
+import io.starter.formats.XLS.ColumnNotFoundException
+import io.starter.formats.XLS.SxStreamID
+import io.starter.formats.XLS.Sxview
+import io.starter.toolkit.Logger
+import org.json.JSONObject
+
+
+/**
+ * PivotTable Handle allows for manipulation of PivotTables within a WorkBook.
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see CellHandle
+ */
+/**
+ *
+ */
+/**
+ *
+ */
+
+/**
+ *
+ */
+class PivotTableHandle
+/**
+ * Create a new PivotTableHandle from an Excel PivotTable
+ *
+ * @param PivotTable
+ * - the PivotTable to create a handle for.
+ */
+(private val pt: Sxview, private val book: WorkBookHandle)//SxStreamID sxid= bk.getWorkBook().getPivotStrean(pt.getICache());
+//cellRange= sxid.getCellRange();
+{
+ val workSheetHandle: WorkSheetHandle? = null
+
+ /**
+ * @return Returns the cellRange.
+ */
+ val dataSourceRange: CellRange?
+ get() {
+ val sxid = book.workBook!!.getPivotStream(pt.iCache.toInt())
+ return sxid!!.cellRange
+ }
+
+ /**
+ * get the Name of the PivotTable
+ *
+ * @return String - value of the PivotTable if stored as a String.
+ */
+ /**
+ * set the Name of the PivotTable
+ *
+ * @param String
+ * - value of the PivotTable if stored as a String.
+ */
+ var tableName: String?
+ get() = pt.tableName
+ set(tx) {
+ pt.tableName = tx
+ }
+
+ /**
+ * returns the name of the data field
+ * @return
+ */
+ /**
+ * sets the name of the data field for this pivot table
+ * @param name
+ */
+ var dataName: String?
+ get() = pt.dataName
+ set(name) {
+ pt.dataName = name
+ }
+
+ /**
+ * get whether table displays row grand totals
+ *
+ * @return boolean whether table displays row grand total
+ */
+ /**
+ * Takes a string as a current PivotTable location, and changes that pointer
+ * in the PivotTable to the new string that is sent. This can take single
+ * cells "A5" and cell ranges, "A3:d4" Returns true if the cell range
+ * specified in PivotTableLoc exists & can be changed else false. This also
+ * cannot change a cell pointer to a cell range or vice versa.
+ *
+ * @param String
+ * - range of Cells within PivotTable to modify
+ * @param String
+ * - new range of Cells within PivotTable
+ *
+ *
+ * public boolean changePivotTableLocation(String PivotTableLoc,
+ * String newLoc) throws PivotTableNotFoundException{
+ *
+ * Logger.logInfo("Changing: " + PivotTableLoc + " to: " +
+ * newLoc);
+ *
+ * return false;
+ *
+ * }
+ */
+
+ /**
+ * set whether to display row grand totals
+ *
+ * @param boolean whether to display row grand totals
+ */
+ var rowsHaveGrandTotals: Boolean
+ get() = pt.fRwGrand
+ set(b) {
+ pt.fRwGrand = b
+ }
+
+ /**
+ * get whether table displays a column grand total
+ *
+ * @return boolean whether table displays column grand total
+ */
+ /**
+ * set whether to display a column grand total
+ *
+ * @param boolean whether to display column grand total
+ */
+ var colsHaveGrandTotals: Boolean
+ get() = pt.fColGrand
+ set(b) = pt.setColGrand(b)
+
+ /**
+ * get the auto format for the Table
+ *
+ * @return int the auto format Id for the table
+ */
+ /**
+ * set the auto format for the Table
+ *
+ *
+ * The valid formats are:
+ *
+ * PivotTableHandle.AUTO_FORMAT_Report1
+ * PivotTableHandle.AUTO_FORMAT_Report2
+ * PivotTableHandle.AUTO_FORMAT_Report3
+ * PivotTableHandle.AUTO_FORMAT_Report4
+ * PivotTableHandle.AUTO_FORMAT_Report5
+ * PivotTableHandle.AUTO_FORMAT_Report6
+ * PivotTableHandle.AUTO_FORMAT_Report7
+ * PivotTableHandle.AUTO_FORMAT_Report8
+ * PivotTableHandle.AUTO_FORMAT_Report9
+ * PivotTableHandle.AUTO_FORMAT_Report10
+ * PivotTableHandle.AUTO_FORMAT_Table1
+ * PivotTableHandle.AUTO_FORMAT_Table2
+ * PivotTableHandle.AUTO_FORMAT_Table3
+ * PivotTableHandle.AUTO_FORMAT_Table4
+ * PivotTableHandle.AUTO_FORMAT_Table5
+ * PivotTableHandle.AUTO_FORMAT_Table6
+ * PivotTableHandle.AUTO_FORMAT_Table7
+ * PivotTableHandle.AUTO_FORMAT_Table8
+ * PivotTableHandle.AUTO_FORMAT_Table9
+ * PivotTableHandle.AUTO_FORMAT_Table10
+ *
+ *
+ * @param int the auto format Id for the table
+ */
+ var autoFormatId: Int
+ get() = pt.itblAutoFmt.toInt()
+ set(b) {
+ pt.itblAutoFmt = b.toShort()
+ }
+
+ /**
+ * get whether table has auto format applied
+ *
+ * @param boolean whether table has auto format applied
+ */
+ /**
+ * set whether to auto format the Table
+ *
+ * @param boolean whether to auto format the table
+ */
+ var usesAutoFormat: Boolean
+ get() = pt.fAutoFormat
+ set(b) {
+ pt.fAutoFormat = b
+ }
+
+ /**
+ * get whether Width/Height Autoformat is applied
+ *
+ * @return boolean whether the Width/Height Autoformat is applied
+ */
+ /**
+ * set Width/Height Autoformat is applied
+ *
+ * @param boolean whether to apply the Width/Height Autoformat
+ */
+ var autoWidthHeight: Boolean
+ get() = pt.fwh
+ set(b) {
+ pt.fwh = b
+ }
+
+ /**
+ * get whether Font Autoformat is applied
+ *
+ * @return boolean whether the Font Autoformat is applied
+ */
+ /**
+ * set whether Font Autoformat is applied
+ *
+ * @param boolean whether to apply the Font Autoformat
+ */
+ var autoFont: Boolean
+ get() = pt.fFont
+ set(b) {
+ pt.fFont = b
+ }
+
+ /**
+ * get whether Alignment Autoformat is applied
+ *
+ * @return boolean whether the Alignment Autoformat is applied
+ */
+ /**
+ * set whether Alignment Autoformat is applied
+ *
+ * @param boolean whether to apply the Alignment Autoformat
+ */
+ var autoAlign: Boolean
+ get() = pt.fAlign
+ set(b) {
+ pt.fAlign = b
+ }
+
+ /**
+ * get whether Border Autoformat is applied
+ *
+ * @return boolean whether the Border Autoformat is applied
+ */
+ /**
+ * set whether Border Autoformat is applied
+ *
+ * @param boolean whether to apply the Border Autoformat
+ */
+ var autoBorder: Boolean
+ get() = pt.fBorder
+ set(b) {
+ pt.fBorder = b
+ }
+
+ /**
+ * get whether Pattern Autoformat is applied
+ *
+ * @return boolean whether the Pattern Autoformat is applied
+ */
+ /**
+ * set whether Pattern Autoformat is applied
+ *
+ * @param boolean whether to apply the Pattern Autoformat
+ */
+ var autoPattern: Boolean
+ get() = pt.fPattern
+ set(b) {
+ pt.fPattern = b
+ }
+
+ /**
+ * get whether Number Autoformat is applied
+ *
+ * @return boolean whether the Number Autoformat is applied
+ */
+ /**
+ * set whether Number Autoformat is applied
+ *
+ * @param boolean whether to apply the Number Autoformat
+ */
+ var autoNumber: Boolean
+ get() = pt.fNumber
+ set(b) {
+ pt.fNumber = b
+ }
+
+ /**
+ * get the first row in the PivotTable
+ */
+ /**
+ * set the first row in the PivotTable
+ */
+ // s--; // these are zero-based rows
+ var rowFirst: Int
+ get() = pt.rwFirst.toInt() + 1
+ set(s) {
+ pt.rwFirst = s.toShort()
+ }
+
+ /**
+ * get the last row in the PivotTable
+ */
+ /**
+ * set the last row in the PivotTable
+ */
+ var rowLast: Int
+ get() = pt.rwLast.toInt() + 1
+ set(s) {
+ var s = s
+ s--
+ pt.rwLast = s.toShort()
+ }
+
+ /**
+ * get the first Column in the PivotTable
+ */
+ /**
+ * set the first Column in the PivotTable
+ */
+ var colFirst: Int
+ get() = pt.colFirst.toInt()
+ set(s) {
+ pt.colFirst = s.toShort()
+ }
+
+ /**
+ * get the last Column in the PivotTable
+ */
+ /**
+ * set the last Column in the PivotTable
+ */
+ var colLast: Int
+ get() = pt.colLast.toInt()
+ set(s) {
+ pt.colLast = s.toShort()
+ }
+
+ /**
+ * get the first header row
+ */
+ /**
+ * set the first header row
+ */
+ var rowFirstHead: Int
+ get() = pt.rwFirstHead.toInt() + 1
+ set(s) {
+ var s = s
+ s--
+ pt.rwFirstHead = s.toShort()
+ }
+
+ /**
+ * get the first Row containing data
+ */
+ /**
+ * set the first Row containing data
+ */
+ // zero-based rows
+ var rowFirstData: Int
+ get() = pt.rwFirstData.toInt() + 1
+ set(s) {
+ var s = s
+ s--
+ pt.rwFirstData = s.toShort()
+ }
+
+ /**
+ * get the first Column containing data
+ */
+ /**
+ * set the first Column containing data
+ */
+ var colFirstData: Int
+ get() = pt.colFirstData.toInt()
+ set(s) {
+ pt.colFirstData = s.toShort()
+ }
+
+ /**
+ * returns the JSON representation of this PivotTable
+ *
+ * @return JSON Pivot Table representation
+ */
+ // copy all methods to this sucker
+ // thePivot.put("cellrange", this.getCellRange().getRange());
+ val json: String
+ get() {
+ val thePivot = JSONObject()
+
+ try {
+ thePivot.put("title", this.tableName)
+
+ } catch (e: Exception) {
+ throw WorkBookException("PivotTableHandle.getJSON failed:$e",
+ WorkBookException.RUNTIME_ERROR)
+ }
+
+ return thePivot.toString()
+ }
+
+ /**
+ * Sets the Pivot Table Range to represent the Data to analyse
+ * NOTE: any existing data will be replaced
+ * @param cellRange The cellRange to set.
+ */
+ fun setSourceDataRange(cellRange: CellRange) {
+ val sxid = book.workBook!!.getPivotStream(pt.iCache.toInt())
+ sxid!!.cellRange = cellRange
+ try {
+ pt.nPivotFields = cellRange.cols.size.toShort()
+ } catch (e: ColumnNotFoundException) {
+
+ }
+
+ }
+
+ /**
+ * Sets the Pivot Table Range to represent the Data to analyse
+ * NOTE: any existing data will be replaced
+ * If the cell range does not contain sheet information, the sheet that the pivot table is located will be used
+ * @param cellRange
+ */
+ fun setSourceDataRange(range: String) {
+ var range = range
+ val rc = ExcelTools.getRangeCoords(range)
+ if (range.indexOf("!") == -1)
+ range = this.workSheetHandle.toString() + "!" + range
+ val sxid = book.workBook!!.getPivotStream(pt.iCache.toInt())
+ sxid!!.setCellRange(range)
+
+ pt.nPivotFields = (rc[3] - rc[1] + 1).toShort()
+ }
+
+ /**
+ * Sets the Pivot Table data source from a named range
+ * @param namedrange Named Range
+ */
+ fun setSource(namedrange: String) {
+ // TODO: finish; update DCONNAME
+ }
+
+ /**
+ * returns whether a given row is contained in this PivotTable
+ *
+ * @param int the row number
+ * @return boolean whether the row is in the table
+ */
+ fun containsRow(x: Int): Boolean {
+ return x <= pt.rwLast && x >= pt.rwFirst
+ }
+
+ /**
+ * return a more friendly
+ *
+ * @see java.lang.Object.toString
+ */
+ override fun toString(): String? {
+ return this.tableName
+ }
+
+ /**
+ * returns whether a given col is contained in this PivotTable
+ *
+ * @param int the column number
+ * @return boolean whether the col is in the table
+ */
+ fun containsCol(x: Int): Boolean {
+ return x <= pt.colLast && x >= pt.colFirst
+ }
+
+ fun removeArtifacts() {
+ val coords = intArrayOf(pt.rwFirst - 2, pt.colFirst.toInt(), pt.rwLast.toInt(), pt.colLast.toInt())
+ try {
+ val newr = CellRange(workSheetHandle!!, coords, true)
+ val ch = newr.getCells()
+ for (r in ch!!.indices) {
+ if (ch[r] != null)
+ ch[r].remove(true)
+ }
+ } catch (e: Exception) {
+ Logger.logWarn("could not remove artifacts in PivotTableHandle: $e")
+ }
+
+ }
+
+ companion object {
+
+ var AUTO_FORMAT_Report1 = 1
+ var AUTO_FORMAT_Report2 = 2
+ var AUTO_FORMAT_Report3 = 3
+ var AUTO_FORMAT_Report4 = 4
+ var AUTO_FORMAT_Report5 = 5
+ var AUTO_FORMAT_Report6 = 6
+ var AUTO_FORMAT_Report7 = 7
+ var AUTO_FORMAT_Report8 = 8
+ var AUTO_FORMAT_Report9 = 9
+ var AUTO_FORMAT_Report10 = 10
+ var AUTO_FORMAT_Table1 = 11
+ var AUTO_FORMAT_Table2 = 12
+ var AUTO_FORMAT_Table3 = 13
+ var AUTO_FORMAT_Table4 = 14
+ var AUTO_FORMAT_Table5 = 15
+ var AUTO_FORMAT_Table6 = 16
+ var AUTO_FORMAT_Table7 = 17
+ var AUTO_FORMAT_Table8 = 18
+ var AUTO_FORMAT_Table9 = 19
+ var AUTO_FORMAT_Table10 = 20
+ var AUTO_FORMAT_Classic = 30
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.java b/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.java
deleted file mode 100644
index 704a5d2..0000000
--- a/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.java
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-import java.util.Iterator;
-
-import io.starter.formats.XLS.BiffRec;
-import io.starter.formats.XLS.BottomMargin;
-import io.starter.formats.XLS.Boundsheet;
-import io.starter.formats.XLS.HCenter;
-import io.starter.formats.XLS.LeftMargin;
-import io.starter.formats.XLS.Name;
-import io.starter.formats.XLS.PrintGrid;
-import io.starter.formats.XLS.PrintRowCol;
-import io.starter.formats.XLS.RightMargin;
-import io.starter.formats.XLS.Setup;
-import io.starter.formats.XLS.TopMargin;
-import io.starter.formats.XLS.VCenter;
-import io.starter.formats.XLS.WorkSheetNotFoundException;
-import io.starter.formats.XLS.WsBool;
-
-/**
- * The PrinterSettingsHandle gives you control over the printer settings for a Sheet such as whether to print in landscape or portrait mode.
-
- * The PrinterSettingsHandle provides fine-grained control over printing settings
- * in Excel.
- *
- * NOTE: you can only view the effects of these methods in an open Excel file when
- * you use the "Print Setup" command.
- *
- * OpenXLS does not currently support directly sending
- * spreadsheet data to a printer.
- *
- *
- * Example Usage:
- *
- ...
- PrinterSettingsHandle printersetup = sheet.getPrinterSettings();
- // Paper Size
- printersetup.setPaperSize(PrinterSettingsHandle.PAPER_SIZE_LEDGER_17x11);
- // Scaling
- printersetup.setScale(125);
- // resolution
- printersetup.setResolution(300);
- ...
-
- *
- *
- */
-/* order of records in Page Settings Block:
- * HORIZONTALPAGEBREAKS
- VERTICALPAGEBREAKS
- HEADER
- FOOTER
- HCENTER
- VCENTER
- LEFTMARGIN
- RIGHTMARGIN
- TOPMARGIN
- BOTTOMMARGIN
- PLS
- SETUP
- BITMAP
- *
- */
-public class PrinterSettingsHandle implements Handle {
-
-
-// paper size ints
- public static final int PAPER_SIZE_UNDEFINED = 0;
- public static final int PAPER_SIZE_LETTER_8_5x11 = 1; // Letter 81/2" x 11"
- public static final int PAPER_SIZE_LETTER_SMALL = 2; // Letter small 81/2" x 11"
- public static final int PAPER_SIZE_TABLOID_11x17 = 3; // Tabloid 11" x 17"
- public static final int PAPER_SIZE_LEDGER_17x11 = 4; // Ledger 17" x 11"
- public static final int PAPER_SIZE_LEGAL_8_5x14 = 5; // Legal 81/2" x 14"
- public static final int PAPER_SIZE_STATEMENT_5_5x8_5 = 6; // Statement 51/2" x 81/2"
- public static final int PAPER_SIZE_LETTER_EXTRA_9_5Ax12 = 50 ; // Letter Extra 91/2" x 12
- public static final int PAPER_SIZE_LEGAL_EXTRA_9_5Ax15 = 51 ; // Legal Extra 91/2" x 15"
- public static final int PAPER_SIZE_TABLOID_EXTRA_1111_16Ax18 = 52 ; // Tabloid Extra 1111/16" x 18"
- public static final int PAPER_SIZE_A4_EXTRA_235MM_X_322MM = 53 ; // A4 Extra 235mm x 322mm
- public static final int PAPER_SIZE_LETTER_TRANSVERSE_8_5Ax11 = 54 ; // Letter Transverse 81/2" x 11"
- public static final int PAPER_SIZE_EXECUTIVE_7_QUARTER_X_10_5 = 7 ; // Executive 71/4" x 101/2"
- public static final int PAPER_SIZE_TRANSVERSE_210MM_X_297MM = 55 ; // A4 Transverse 210mm x 297mm
- public static final int PAPER_SIZE_A3_297MM_X_420MM = 8 ; // 8 A3 297mm x 420mm
- public static final int PAPER_SIZE_LETTER_EXTRA_TRANSV_9_5_X_12 = 56 ; // 56 Letter Extra Transv. 91/2" x 12"
- public static final int PAPER_SIZE_A4_210MM_X_297MM = 9 ; // A4 210mm x 297mm
- public static final int PAPER_SIZE_SUPER_A_A4_227MM_X_356MM = 57 ; // Super A/A4 227mm x 356mm
- public static final int PAPER_SIZE_A4_SMALL_210MM_X_297MM = 10 ; // A4 small 210mm x 297mm
- public static final int PAPER_SIZE_SUPER_B_A3_305MM_X_487MM = 58 ; // Super B/A3 305mm x 487mm
- public static final int PAPER_SIZE_A5_148MM_X_210MM = 11 ; // A5 148mm x 210mm
- public static final int PAPER_SIZE_LETTER_PLUS = 59 ; // Letter Plus
- public static final int PAPER_SIZE_2_X_1211_16 = 81 ; // 2" x 1211/16"
- public static final int PAPER_SIZE_B4_JIS_257MM_X_364MM = 12 ; // B4 (JIS) 257mm x 364mm
- public static final int PAPER_SIZE_A4_PLUS_210MM_X_330MM = 60 ; // A4 Plus 210mm x 330mm
- public static final int PAPER_SIZE_B5_JIS_182MM_X_257MM = 13 ; // B5 (JIS) 182mm x 257mm
- public static final int PAPER_SIZE_A5_TRANSVERSE_148MM_X_210MM = 61 ; // A5 Transverse 148mm x 210mm
- public static final int PAPER_SIZE_FOLIO_8_5_X_13 = 14 ; // Folio 81/2" x 13"
- public static final int PAPER_SIZE_B5_JIS_TRANSVERSE_182MM_X_257MM = 62 ; // B5 (JIS) Transverse 182mm x 257mm
- public static final int PAPER_SIZE_QUATRO_215MM_X_275MM = 15 ; // Quarto 215mm x 275mm
- public static final int PAPER_SIZE_A3_EXTRA_322MM_X_445MM = 63 ; // A3 Extra 322mm x 445mm
- public static final int PAPER_SIZE_10Ax14_10_X_14 = 16 ; // 10x14 10" x 14"
- public static final int PAPER_SIZE_A5_EXTRA_174MM_X_235 = 64 ; // A5 Extra 174mm x 235mm
- public static final int PAPER_SIZE_11Ax17_11_X_17 = 17 ; // 11x17 11" x 17"
- public static final int PAPER_SIZE_B5_ISO_EXTRA_201MM_X_276MM = 65 ; // B5 (ISO) Extra 201mm x 276mm
- public static final int PAPER_SIZE_NOTE_8_5_X_11 = 18 ; // Note 81/2" x 11"
- public static final int PAPER_SIZE_A2_420MM_X_594MM = 66 ; // A2 420mm x 594mm
- public static final int PAPER_SIZE_ENVELOPE_9_3_78_X_8_78 = 19 ; // Envelope #9 37/8" x 87/8"
- public static final int PAPER_SIZE_A3_TRANSVERSE_297MM_X_420MM = 67 ; // A3 Transverse 297mm x 420mm
- public static final int PAPER_SIZE_ENVELOPE_10_4_18_X_9_5 = 20 ; // Envelope #10 41/8" x 91/2"
- public static final int PAPER_SIZE_EXTRA_TRANSVERSE_322MM_X_445MM = 68 ; // A3 Extra Transverse 322mm x 445mm
- public static final int PAPER_SIZE_ENVELOPE_11_4_5_X_10_38 = 21 ; // Envelope #11 41/2" x 103/8"
- public static final int PAPER_SIZE_DBL_JAP_POSTCARD_200MM_X_148MM = 69 ; // Dbl. Japanese Postcard 200mm x 148mm
- public static final int PAPER_SIZE_ENVELOPE_12_4_34_X_11 = 22 ; // Envelope #12 43/4" x 11"
- public static final int PAPER_SIZE_A6_105MM_X_148MM = 70 ; // A6 105mm x 148mm
- public static final int PAPER_SIZE_ENVELOPE_14_5_X_11_5 = 23 ; // Envelope #14 5" x 111/2"
- public static final int PAPER_SIZE_C_17_X_22_72 = 24 ; // C 17" x 22" 72
- public static final int PAPER_SIZE_D_22_X_34_73 = 25 ; // D 22" x 34" 73
- public static final int PAPER_SIZE_E_34_X_44_74 = 26 ; // E 34" x 44" 74
- public static final int PAPER_SIZE_DL_ENVELOPE_110MM_X_110MM_X_220MM = 27 ; // Envelope DL 110mm x 220mm
- public static final int PAPER_SIZE_LETTER_ROTATED_11_X_8_5 = 75 ; // Letter Rotated 11" x 81/2"
- public static final int PAPER_SIZE_ENVELOPE_C5_162MM_X_229M = 28 ; // Envelope C5 162mm x 229mm
- public static final int PAPER_SIZE_A3_ROTATED_420MM_X_297MM = 76 ; // A3 Rotated 420mm x 297mm
- public static final int PAPER_SIZE_ENVELOPE_C3_324MM_X_458MM = 29 ; // Envelope C3 324mm x 458mm
- public static final int PAPER_SIZE_A4_ROTATED_297MM_X_210MM = 77 ; // A4 Rotated 297mm x 210mm
- public static final int PAPER_SIZE_ENVELOPE_C4_229MM_X_324MM = 30 ; // Envelope C4 229mm x 324mm
- public static final int PAPER_SIZE_A5_ROTATED_210MM_X_148MM = 78 ; // A5 Rotated 210mm x 148mm
- public static final int PAPER_SIZE_ENVELOPE_C6_115MM_X_162MM = 31 ; // Envelope C6 114mm x 162mm
- public static final int PAPER_SIZE_ENVELOPE_C6_C5_114MM_X_229MM = 32 ; // Envelope C6/C5 114mm x 229mm
- public static final int PAPER_SIZE_B4_ISO_250MM_X_353MM = 33 ; // B4 (ISO) 250mm x 353mm
- public static final int PAPER_SIZE_B5_ISO_176MM_X_250MM = 34 ; // B5 (ISO) 176mm x 250mm
- public static final int PAPER_SIZE_DBL_JAP_POSTCARD_ROT_148MM_X_200MM = 82 ; // Dbl. Jap. Postcard Rot. 148mm x 200mm
- public static final int PAPER_SIZE_B6_ISO_125MM_X_176MM = 35 ; // B6 (ISO) 125mm x 176mm
- public static final int PAPER_SIZE_ENVELOPE_ITALY_10MM_X_230MM = 36 ; // Envelope Italy 110mm x 230mm 84
- public static final int PAPER_SIZE_ENVELOPE_MONARCH_3_7_8_X_7_5 = 37 ; // Envelope Monarch 37/8" x 71/2" 85
- public static final int PAPER_SIZE_6_3_4_ENVELOPE_3_5_8_X_6_5 = 38 ; // 63/4 Envelope 35/8" x 61/2" 86
- public static final int PAPER_SIZE_US_STANDARD_FANFOLD_147_8_X_11 = 39 ; // US Standard Fanfold 147/8" x 11" 87
- public static final int PAPER_SIZE_GERMAN_STD_FANFOLD_8_5_X_12 = 40 ; // German Std. Fanfold 81/2" x 12"
- public static final int PAPER_SIZE_GERMAN_LEGAL_FANFOLD_8_5_X_13 = 41 ; // German Legal Fanfold 81/2" x 13"
- // public static final int PAPER_SIZE_B4_ISO_250MM_X_353MM = 42 ; // B4 (ISO) 250mm x 353mm
- public static final int PAPER_SIZE_JAP_POSTCARD_100M_X_148MM = 43 ; // Japanese Postcard 100mm x 148mm
- public static final int PAPER_SIZE_9_X_11 = 44 ; // 9x11 9" x 11"
- public static final int PAPER_SIZE_10_X_11 = 45 ; // 10x11 10" x 11"
- public static final int PAPER_SIZE_15_X_11 = 46 ; // 15x11 15" x 11"
- public static final int PAPER_SIZE_ENVELOPE_INVITE_220MM_X_220MM = 47 ; // Envelope Invite 220mm x 220mm
- public static final int PAPER_SIZE_B4_JIS_ROTATED_364MM_X_257MM = 79 ; // B4 (JIS) Rotated 364mm x 257mm
- public static final int PAPER_SIZE_B5_JIS_ROTATED_257MMX_X_182MM = 80 ; // B5 (JIS) Rotated 257mm x 182mm
- public static final int PAPER_SIZE_JAP_POSTCARD_ROT_148MM_X_100MM = 81 ; // Japanese Postcard Rot. 148mm x 100mm
- public static final int PAPER_SIZE_A6_ROTATED_148MM_X_105MM = 83 ; // A6 Rotated 148mm x 105mm
- public static final int PAPER_SIZE_B6_JIS_128MM_X_182MM = 88 ; // B6 (JIS) 128mm x 182mm
- public static final int PAPER_SIZE_B6_JIS_ROT_182MM_X_128MM = 89 ; // B6 (JIS) Rotated 182mm x 128mm
- public static final int PAPER_SIZE_12_X_11 = 90 ; // 12x11 12" x 11"
-
- /**
- * default constructor
- */
- public PrinterSettingsHandle (Boundsheet sheet) {
- this.sheet = sheet;
-
- Iterator> iter = sheet.getPrintRecs().iterator();
- while (iter.hasNext()) {
- BiffRec record = (BiffRec) iter.next();
-
- if (record instanceof Setup)
- printerSettings = (Setup) record;
- else if (record instanceof HCenter)
- hCenter = (HCenter) record;
- else if (record instanceof VCenter)
- vCenter = (VCenter) record;
- else if (record instanceof LeftMargin)
- leftMargin = (LeftMargin) record; // missing in default set of records
- else if (record instanceof RightMargin)
- rightMargin = (RightMargin) record; // missing in default set of records
- else if (record instanceof TopMargin)
- topMargin = (TopMargin) record; // missing in default set of records
- else if (record instanceof BottomMargin)
- bottomMargin = (BottomMargin) record; // missing in default set of records
- else if (record instanceof PrintGrid)
- grid = (PrintGrid) record;
- else if (record instanceof PrintRowCol)
- headers = (PrintRowCol) record;
- else if (record instanceof WsBool)
- wsBool = (WsBool) record;
- }
- // Actually, the below comment is incorrect: do NOT do this unconditionally
- //printerSettings.setNoPrintData(false); // there IS printer setup data
- }
-
- Boundsheet sheet;
-
- private Setup printerSettings;
- private HCenter hCenter;
- private VCenter vCenter;
- private LeftMargin leftMargin;
- private RightMargin rightMargin;
- private TopMargin topMargin;
- private BottomMargin bottomMargin;
- private PrintGrid grid;
- private PrintRowCol headers;
- private WsBool wsBool;
-
- // the following are unimplemented printer setting recs:
- // HORIZONTALPAGEBREAKS;
- // VERTICALPAGEBREAKS;
-
-
- /**
- * get the number of copies to print
- *
- * @return the number of copies
- */
- public short getCopies() {
- return printerSettings.getCopies();
- }
-
-
- /**
- * get the footer margin size in inches
- *
- * @return the footer margin in inches
- */
- public double getFooterMargin() {
- return printerSettings.getFooterMargin();
- }
-
- /**
- * get the header margin size in inches
- *
- * @return the header margin in inches
- */
- public double getHeaderMargin() {
- return printerSettings.getHeaderMargin();
- }
-
- /** Gets the left print margin. */
- public double getLeftMargin() {
- if (leftMargin==null) {
- leftMargin= new LeftMargin();
- this.sheet.addMarginRecord(leftMargin);
- }
- return leftMargin.getMargin();
- }
-
- /** Gets the right print margin. */
- public double getRightMargin() {
- if (rightMargin==null) {
- rightMargin= new RightMargin();
- this.sheet.addMarginRecord(rightMargin);
- }
- return rightMargin.getMargin();
- }
-
- /** Gets the top print margin. */
- public double getTopMargin() {
- if (topMargin==null) {
- topMargin= new TopMargin();
- this.sheet.addMarginRecord(topMargin);
- }
- return topMargin.getMargin();
- }
-
- /** Gets the bottom print margin. */
- public double getBottomMargin() {
- if (bottomMargin==null) {
- bottomMargin= new BottomMargin();
- this.sheet.addMarginRecord(bottomMargin);
- }
- return bottomMargin.getMargin();
- }
-
- /**
- * get the landscape orientation
- *
- * @return whether the print orientation is set to landscape
- *
- */
- public boolean getLandscape() {
- return printerSettings.getLandscape();
- }
-
- /**
- * get the left-to-right print orientation
- *
- * @return whether the print orientation is set to left-to-right
- */
- public boolean getLeftToRight() {
- return printerSettings.getLeftToRight();
- }
-
- /**
- * get whether printing is in black and white
- *
- * @return black and white
- */
- public boolean getNoColor() {
- return printerSettings.getNoColor();
- }
-
- /**
- * get whether to ignore orientation
- *
- * @return ignore orientation
- */
- public boolean getNoOrient() {
- return printerSettings.getNoOrient();
- }
-
- /**
- * get whether printer data is missing
- *
- * @return whether the printer data is missing
- */
- public boolean getNoPrintData() {
- return printerSettings.getNoPrintData();
- }
-
- /**
- * get the page to start printing from
- *
- * @return the page to start printing from
- *
- */
- public short getPageStart() {
- return printerSettings.getPageStart();
- }
-
- /**
- * Returns the paper size setting for the printer setup based on the
- * following table:
- *
- *
- *
- * @return paper size
- */
- public short getPaperSize() {
- return printerSettings.getPaperSize();
- }
-
- /**
- * @return
- * @return whether to print Notes.
- */
- public boolean getPrintNotes() {
- return printerSettings.getPrintNotes();
- }
-
-
- /**
- * get the print resolution
- *
- * @return the printer resolution in DPI
- */
- public short getResolution() {
- return printerSettings.getResolution();
- }
-
- /**
- * get the scale of the printer output in whole percentages
- *
- * ie: 25 = 25%
- *
- * @return the scale of printer output
- */
- public short getScale() {
- return printerSettings.getScale();
- }
-
- /**
- * use custom start page for auto numbering
- *
- * @return Returns whether to use a custom start page
- */
- public boolean getUsePage() {
- return printerSettings.getUsePage();
- }
-
- /**
- * get the vertical print resolution
- *
- * @return the vertical printer resolution in DPI
- */
- public short getVerticalResolution() {
- return printerSettings.getVerticalResolution();
- }
-
- /** Whether the sheet should be centered horizontally. */
- public boolean isHCenter() {
- return hCenter.isHCenter();
- }
-
- /** Whether the sheet should be centered vertically. */
- public boolean isVCenter() {
- return vCenter.isVCenter();
- }
-
- /** Whether the grid lines will be printed. */
- public boolean isPrintGridLines() {
- return grid.isPrintGrid();
- }
-
- /** Whether the row and column headers will be printed. */
- public boolean isPrintRowColHeaders() {
- return headers.isPrintHeaders();
- }
-
- /** Gets whether the sheet will be printed fit to some number of pages. */
- public boolean isFitToPage() {
- return wsBool.isFitToPage();
- }
-
- /**
- * set for draft quality output
- *
- * @param whether to use draft quality
- */
- public void setDraft(boolean b) {
- printerSettings.setDraft(b);
- }
-
- /**
- * Set the output to print onto this number of pages high
- *
- * ie: setFitHeight(10) will stretch the print out to fit 10
- * pages high
- *
- * @param number of pages to fit to height
- */
- public void setFitHeight(int numpages) {
- printerSettings.setFitHeight((short)numpages);
- }
-
- /**
- * Set the output to print onto this number of pages wide
- *
- * ie: setFitWidth(10) will stretch the print out to fit 10
- * pages wide
- *
- * @param number of pages to fit to width
- */
- public void setFitWidth(int numpages) {
- printerSettings.setFitWidth((short)numpages);
- }
-
- /** Sets whether the sheet will be printed fit to some number of pages. */
- public void setFitToPage (boolean value) {
- wsBool.setFitToPage( value );
- }
-
- /**
- * sets the footer margin in inches
- *
- * @param footer margin
- */
- public void setFooterMargin(double f) {
- printerSettings.setFooterMargin(f);
- }
-
- /** Sets whether the page should be centered horizontally. */
- public void setHCenter (boolean center) {
- hCenter.setHCenter( center );
- }
-
- /**
- * sets the Header margin in inches
- *
- * @param header margin
- */
- public void setHeaderMargin(double h) {
- printerSettings.setHeaderMargin(h);
- }
-
- /** Sets the sheet's left print margin. */
- public void setLeftMargin (double value) {
- if (leftMargin==null) {
- leftMargin= new LeftMargin();
- this.sheet.addMarginRecord(leftMargin);
- }
- leftMargin.setMargin( value );
- }
-
- /** Sets the sheet's right print margin. */
- public void setRightMargin (double value) {
- if (rightMargin==null) {
- rightMargin= new RightMargin();
- this.sheet.addMarginRecord(rightMargin);
- }
- rightMargin.setMargin( value );
- }
-
- /** Sets the sheet's top print margin. */
- public void setTopMargin (double value) {
- if (topMargin==null) {
- topMargin= new TopMargin();
- this.sheet.addMarginRecord(topMargin);
- }
- topMargin.setMargin( value );
- }
-
- /** Sets the sheet's bottom print margin. */
- public void setBottomMargin (double value) {
- if (bottomMargin==null) {
- bottomMargin= new BottomMargin();
- this.sheet.addMarginRecord(bottomMargin);
- }
- bottomMargin.setMargin( value );
- }
-
- /**
- * set the print orientation to landscape or portrait
- *
- * @param landscape
- */
- public void setLandscape(boolean b) {
- printerSettings.setNoOrient(false); // use the orientation setting
- printerSettings.setLandscape(b);
- }
-
- /**
- * set the print orientation to left-to-right printing
- *
- * @param leftToRight
- */
- public void setLeftToRight(boolean b) {
- printerSettings.setLeftToRight(b);
- }
-
- /**
- * sets the output to black and white
- *
- * @param noColor
- */
- public void setNoColor(boolean b) {
- printerSettings.setNoColor(b);
- }
-
- /**
- * set the default page to start printing from
- *
- * @param p
- */
- public void setPageStart(short p) {
- printerSettings.setPageStart(p);
- }
-
- /**
- * sets the whether to print cell notes
- *
- * @param printNotes whether to print Notes.
- */
- public void setPrintNotes(boolean b) {
- printerSettings.setPrintNotes(b);
- }
-
- /**
- * Set the output printer resolution
- *
- * @param resolution The resolution to set in DPI.
- */
- public void setResolution(int r) {
- printerSettings.setResolution((short)r);
- }
-
- /**
- * scale the printer output in whole percentages
- *
- * ie: 25 = 25%
- *
- * @param scale The scale to set.
- */
- public void setScale(int scale) {
- printerSettings.setScale((short)scale);
- }
-
- /**
- * @param usePage whether to use custom Page to start printing from.
- */
- public void setUsePage(boolean usePage) {
- printerSettings.setUsePage(usePage);
- }
-
- /**
- * @param verticalResolution The vertical Resolution in DPI
- */
- public void setVerticalResolution(short verticalResolution) {
- printerSettings.setVerticalResolution(verticalResolution);
- }
-
- /**
- * @param copies The number of copies to print
- */
- public void setCopies(int copies) {
- printerSettings.setCopies((short)copies);
- }
-
- /**
- * sets the paper size based on the paper size table
- *
- * @param the paper size index
- */
- public void setPaperSize(int p) {
- printerSettings.setPaperSize((short)p);
- }
-
- /**
- * get the draft quality setting
- *
- * @return draft quality
- */
- public boolean getDraft() {
- return printerSettings.getDraft();
- }
-
- /**
- * get the number of pages to fit the printout to height
- *
- * @return fit to height
- */
- public short getFitHeight() {
- return printerSettings.getFitHeight();
- }
-
- /**
- * get the number of pages to fit the printout to width
- *
- * @return fit to width
- */
- public short getFitWidth() {
- return printerSettings.getFitWidth();
- }
-
- /** Sets whether the sheet should be centered vertically. */
- public void setVCenter (boolean center) {
- vCenter.setVCenter( center );
- }
-
- /** Sets whether to print the grid lines. */
- public void setPrintGrid (boolean print) {
- grid.setPrintGrid( print );
- }
-
- /** Sets whether to print the row and column headers. */
- public void setPrintRowColHeaders (boolean print) {
- headers.setPrintHeaders( print );
- }
-
- /** Gets the range specifying the titles printed on each page.
- */
- public String getTitles() {
- Name range = sheet.getName( "Built-in: PRINT_TITLES" );
- if (range == null) return null;
- return range.getExpressionString();
- }
-
- /** Sets the range specifying the titles printed on each page.
- * The reference for the row(s) to repeat e.g. $1:$1 for row 1
- * For Columns, type the reference to the column or columns that
- * you want to set as a title e.g. $A:$B for columns A and B
- */
- // note: MUST be in $ROW:$ROW or $COL:$COL format, for both
- // can be $R:$R, $C:$C for both
- public void setTitles (String range) {
- Name name = sheet.getName( "Built-in: PRINT_TITLES" );
- if (name == null) try {
- name = new Name( sheet.getWorkBook(), "Print_Titles" );
- name.setBuiltIn( (byte)0x07 ); //do before setNewScope as it blows out itab
- name.setNewScope( sheet.getSheetNum() + 1 );
- } catch (WorkSheetNotFoundException e) {
- // This shouldn't be possible.
- throw new Error ("sheet not found re-scoping name");
- }
- // pre-process range to ensure in proper format, ensure all absolute ($) refs +
- // handle wholerow-wholecol refs + complex ranges
- if (range==null) return; // TODO: Do what?? remove??
- String[] ranges= range.split(",");
- range= "";
- for (int i= 0; i < ranges.length; i++) {
- if (i > 0) // concatenate terms into one ptgmemfunc-style expression
- range+=",";
- String r= "";
- int[] rc= ExcelTools.getRangeCoords(ranges[i]);
- if (rc[0]==rc[2]) // varies by column
- r= "$" + ExcelTools.getAlphaVal(rc[1]) + ":$" + ExcelTools.getAlphaVal(rc[3]);
- if (rc[1]==rc[3]) {// varies by row
- r= "$" + rc[0] + ":$" + rc[2];
- }
- range+= sheet.getSheetName() + "!" + r;
- }
- name.setLocation( range );
-}
-
-}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.kt b/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.kt
new file mode 100644
index 0000000..a342bf1
--- /dev/null
+++ b/src/main/java/io/starter/OpenXLS/PrinterSettingsHandle.kt
@@ -0,0 +1,703 @@
+/*
+ * --------- BEGIN COPYRIGHT NOTICE ---------
+ * Copyright 2002-2012 Extentech Inc.
+ * Copyright 2013 Infoteria America Corp.
+ *
+ * This file is part of OpenXLS.
+ *
+ * OpenXLS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * OpenXLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with OpenXLS. If not, see
+ * .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.*
+
+/**
+ * The PrinterSettingsHandle gives you control over the printer settings for a Sheet such as whether to print in landscape or portrait mode.
+ *
+ * The PrinterSettingsHandle provides fine-grained control over printing settings
+ * in Excel.
+ *
+ * NOTE: you can only view the effects of these methods in an open Excel file when
+ * you use the "Print Setup" command.
+ *
+ * OpenXLS does not currently support directly sending
+ * spreadsheet data to a printer.
+ *
+ *
+ * **
+ * Example Usage:**
+ *
+ * ...
+ * PrinterSettingsHandle printersetup = sheet.getPrinterSettings();
+ * // Paper Size
+ * printersetup.setPaperSize(PrinterSettingsHandle.PAPER_SIZE_LEDGER_17x11);
+ * // Scaling
+ * printersetup.setScale(125);
+ * // resolution
+ * printersetup.setResolution(300);
+ * ...
+ *
+ */
+/* order of records in Page Settings Block:
+ * HORIZONTALPAGEBREAKS
+ VERTICALPAGEBREAKS
+ HEADER
+ FOOTER
+ HCENTER
+ VCENTER
+ LEFTMARGIN
+ RIGHTMARGIN
+ TOPMARGIN
+ BOTTOMMARGIN
+ PLS
+ SETUP
+ BITMAP
+ *
+ */
+class PrinterSettingsHandle
+/**
+ * default constructor
+ */
+(internal var sheet: Boundsheet) : Handle {
+
+ private var printerSettings: Setup? = null
+ private var hCenter: HCenter? = null
+ private var vCenter: VCenter? = null
+ private var leftMargin: LeftMargin? = null
+ private var rightMargin: RightMargin? = null
+ private var topMargin: TopMargin? = null
+ private var bottomMargin: BottomMargin? = null
+ private var grid: PrintGrid? = null
+ private var headers: PrintRowCol? = null
+ private var wsBool: WsBool? = null
+
+ // the following are unimplemented printer setting recs:
+ // HORIZONTALPAGEBREAKS;
+ // VERTICALPAGEBREAKS;
+
+
+ /**
+ * get the number of copies to print
+ *
+ * @return the number of copies
+ */
+ val copies: Short
+ get() = printerSettings!!.copies
+
+
+ /**
+ * get the footer margin size in inches
+ *
+ * @return the footer margin in inches
+ */
+ /**
+ * sets the footer margin in inches
+ *
+ * @param footer margin
+ */
+ var footerMargin: Double
+ get() = printerSettings!!.footerMargin
+ set(f) {
+ printerSettings!!.footerMargin = f
+ }
+
+ /**
+ * get the header margin size in inches
+ *
+ * @return the header margin in inches
+ */
+ /**
+ * sets the Header margin in inches
+ *
+ * @param header margin
+ */
+ var headerMargin: Double
+ get() = printerSettings!!.headerMargin
+ set(h) {
+ printerSettings!!.headerMargin = h
+ }
+
+ /**
+ * get the landscape orientation
+ *
+ * @return whether the print orientation is set to landscape
+ */
+ /**
+ * set the print orientation to landscape or portrait
+ *
+ * @param landscape
+ */
+ // use the orientation setting
+ var landscape: Boolean
+ get() = printerSettings!!.landscape
+ set(b) {
+ printerSettings!!.noOrient = false
+ printerSettings!!.landscape = b
+ }
+
+ /**
+ * get the left-to-right print orientation
+ *
+ * @return whether the print orientation is set to left-to-right
+ */
+ /**
+ * set the print orientation to left-to-right printing
+ *
+ * @param leftToRight
+ */
+ var leftToRight: Boolean
+ get() = printerSettings!!.leftToRight
+ set(b) {
+ printerSettings!!.leftToRight = b
+ }
+
+ /**
+ * get whether printing is in black and white
+ *
+ * @return black and white
+ */
+ /**
+ * sets the output to black and white
+ *
+ * @param noColor
+ */
+ var noColor: Boolean
+ get() = printerSettings!!.noColor
+ set(b) {
+ printerSettings!!.noColor = b
+ }
+
+ /**
+ * get whether to ignore orientation
+ *
+ * @return ignore orientation
+ */
+ val noOrient: Boolean
+ get() = printerSettings!!.noOrient
+
+ /**
+ * get whether printer data is missing
+ *
+ * @return whether the printer data is missing
+ */
+ val noPrintData: Boolean
+ get() = printerSettings!!.noPrintData
+
+ /**
+ * get the page to start printing from
+ *
+ * @return the page to start printing from
+ */
+ /**
+ * set the default page to start printing from
+ *
+ * @param p
+ */
+ var pageStart: Short
+ get() = printerSettings!!.pageStart
+ set(p) {
+ printerSettings!!.pageStart = p
+ }
+
+ /**
+ * Returns the paper size setting for the printer setup based on the
+ * following table:
+ *
+ * @return paper size
+ */
+ val paperSize: Short
+ get() = printerSettings!!.paperSize
+
+ /**
+ * @return whether to print Notes.
+ */
+ /**
+ * sets the whether to print cell notes
+ *
+ * @param printNotes whether to print Notes.
+ */
+ var printNotes: Boolean
+ get() = printerSettings!!.printNotes
+ set(b) {
+ printerSettings!!.printNotes = b
+ }
+
+
+ /**
+ * get the print resolution
+ *
+ * @return the printer resolution in DPI
+ */
+ val resolution: Short
+ get() = printerSettings!!.resolution
+
+ /**
+ * get the scale of the printer output in whole percentages
+ *
+ *
+ * ie: 25 = 25%
+ *
+ * @return the scale of printer output
+ */
+ val scale: Short
+ get() = printerSettings!!.scale
+
+ /**
+ * use custom start page for auto numbering
+ *
+ * @return Returns whether to use a custom start page
+ */
+ /**
+ * @param usePage whether to use custom Page to start printing from.
+ */
+ var usePage: Boolean
+ get() = printerSettings!!.usePage
+ set(usePage) {
+ printerSettings!!.usePage = usePage
+ }
+
+ /**
+ * get the vertical print resolution
+ *
+ * @return the vertical printer resolution in DPI
+ */
+ /**
+ * @param verticalResolution The vertical Resolution in DPI
+ */
+ var verticalResolution: Short
+ get() = printerSettings!!.verticalResolution
+ set(verticalResolution) {
+ printerSettings!!.verticalResolution = verticalResolution
+ }
+
+ /**
+ * Whether the sheet should be centered horizontally.
+ */
+ /**
+ * Sets whether the page should be centered horizontally.
+ */
+ var isHCenter: Boolean
+ get() = hCenter!!.isHCenter
+ set(center) {
+ hCenter!!.isHCenter = center
+ }
+
+ /**
+ * Whether the sheet should be centered vertically.
+ */
+ /**
+ * Sets whether the sheet should be centered vertically.
+ */
+ var isVCenter: Boolean
+ get() = vCenter!!.isVCenter
+ set(center) {
+ vCenter!!.isVCenter = center
+ }
+
+ /**
+ * Whether the grid lines will be printed.
+ */
+ val isPrintGridLines: Boolean
+ get() = grid!!.isPrintGrid
+
+ /**
+ * Whether the row and column headers will be printed.
+ */
+ /**
+ * Sets whether to print the row and column headers.
+ */
+ var isPrintRowColHeaders: Boolean
+ get() = headers!!.isPrintHeaders
+ set(print) {
+ headers!!.isPrintHeaders = print
+ }
+
+ /**
+ * Gets whether the sheet will be printed fit to some number of pages.
+ */
+ /**
+ * Sets whether the sheet will be printed fit to some number of pages.
+ */
+ var isFitToPage: Boolean
+ get() = wsBool!!.isFitToPage
+ set(value) {
+ wsBool!!.isFitToPage = value
+ }
+
+ /**
+ * get the draft quality setting
+ *
+ * @return draft quality
+ */
+ /**
+ * set for draft quality output
+ *
+ * @param whether to use draft quality
+ */
+ var draft: Boolean
+ get() = printerSettings!!.draft
+ set(b) {
+ printerSettings!!.draft = b
+ }
+
+ /**
+ * get the number of pages to fit the printout to height
+ *
+ * @return fit to height
+ */
+ val fitHeight: Short
+ get() = printerSettings!!.fitHeight
+
+ /**
+ * get the number of pages to fit the printout to width
+ *
+ * @return fit to width
+ */
+ val fitWidth: Short
+ get() = printerSettings!!.fitWidth
+
+ /**
+ * Gets the range specifying the titles printed on each page.
+ */
+ /**
+ * Sets the range specifying the titles printed on each page.
+ * The reference for the row(s) to repeat e.g. $1:$1 for row 1
+ * For Columns, type the reference to the column or columns that
+ * you want to set as a title e.g. $A:$B for columns A and B
+ */
+ // note: MUST be in $ROW:$ROW or $COL:$COL format, for both
+ // can be $R:$R, $C:$C for both
+ //do before setNewScope as it blows out itab
+ // This shouldn't be possible.
+ // pre-process range to ensure in proper format, ensure all absolute ($) refs +
+ // handle wholerow-wholecol refs + complex ranges
+ // TODO: Do what?? remove??
+ // concatenate terms into one ptgmemfunc-style expression
+ // varies by column
+ // varies by row
+ var titles: String?
+ get() {
+ val range = sheet.getName("Built-in: PRINT_TITLES") ?: return null
+ return range.expressionString
+ }
+ set(range) {
+ var range = range
+ var name = sheet.getName("Built-in: PRINT_TITLES")
+ if (name == null)
+ try {
+ name = Name(sheet.workBook, "Print_Titles")
+ name.setBuiltIn(0x07.toByte())
+ name.setNewScope(sheet.sheetNum + 1)
+ } catch (e: WorkSheetNotFoundException) {
+ throw Error("sheet not found re-scoping name")
+ }
+
+ if (range == null) return
+ val ranges = range.split(",".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
+ range = ""
+ for (i in ranges.indices) {
+ if (i > 0)
+ range += ","
+ var r = ""
+ val rc = ExcelTools.getRangeCoords(ranges[i])
+ if (rc[0] == rc[2])
+ r = "$" + ExcelTools.getAlphaVal(rc[1]) + ":$" + ExcelTools.getAlphaVal(rc[3])
+ if (rc[1] == rc[3]) {
+ r = "$" + rc[0] + ":$" + rc[2]
+ }
+ range += sheet.sheetName + "!" + r
+ }
+ name.location = range
+ }
+
+ init {
+
+ val iter = sheet.printRecs.iterator()
+ while (iter.hasNext()) {
+ val record = iter.next() as BiffRec
+
+ if (record is Setup)
+ printerSettings = record
+ else if (record is HCenter)
+ hCenter = record
+ else if (record is VCenter)
+ vCenter = record
+ else if (record is LeftMargin)
+ leftMargin = record // missing in default set of records
+ else if (record is RightMargin)
+ rightMargin = record // missing in default set of records
+ else if (record is TopMargin)
+ topMargin = record // missing in default set of records
+ else if (record is BottomMargin)
+ bottomMargin = record // missing in default set of records
+ else if (record is PrintGrid)
+ grid = record
+ else if (record is PrintRowCol)
+ headers = record
+ else if (record is WsBool)
+ wsBool = record
+ }
+ // Actually, the below comment is incorrect: do NOT do this unconditionally
+ //printerSettings.setNoPrintData(false); // there IS printer setup data
+ }
+
+ /**
+ * Gets the left print margin.
+ */
+ fun getLeftMargin(): Double {
+ if (leftMargin == null) {
+ leftMargin = LeftMargin()
+ this.sheet.addMarginRecord(leftMargin!!)
+ }
+ return leftMargin!!.margin
+ }
+
+ /**
+ * Gets the right print margin.
+ */
+ fun getRightMargin(): Double {
+ if (rightMargin == null) {
+ rightMargin = RightMargin()
+ this.sheet.addMarginRecord(rightMargin!!)
+ }
+ return rightMargin!!.margin
+ }
+
+ /**
+ * Gets the top print margin.
+ */
+ fun getTopMargin(): Double {
+ if (topMargin == null) {
+ topMargin = TopMargin()
+ this.sheet.addMarginRecord(topMargin!!)
+ }
+ return topMargin!!.margin
+ }
+
+ /**
+ * Gets the bottom print margin.
+ */
+ fun getBottomMargin(): Double {
+ if (bottomMargin == null) {
+ bottomMargin = BottomMargin()
+ this.sheet.addMarginRecord(bottomMargin!!)
+ }
+ return bottomMargin!!.margin
+ }
+
+ /**
+ * Set the output to print onto this number of pages high
+ *
+ *
+ * ie: setFitHeight(10) will stretch the print out to fit 10
+ * pages high
+ *
+ * @param number of pages to fit to height
+ */
+ fun setFitHeight(numpages: Int) {
+ printerSettings!!.fitHeight = numpages.toShort()
+ }
+
+ /**
+ * Set the output to print onto this number of pages wide
+ *
+ *
+ * ie: setFitWidth(10) will stretch the print out to fit 10
+ * pages wide
+ *
+ * @param number of pages to fit to width
+ */
+ fun setFitWidth(numpages: Int) {
+ printerSettings!!.fitWidth = numpages.toShort()
+ }
+
+ /**
+ * Sets the sheet's left print margin.
+ */
+ fun setLeftMargin(value: Double) {
+ if (leftMargin == null) {
+ leftMargin = LeftMargin()
+ this.sheet.addMarginRecord(leftMargin!!)
+ }
+ leftMargin!!.margin = value
+ }
+
+ /**
+ * Sets the sheet's right print margin.
+ */
+ fun setRightMargin(value: Double) {
+ if (rightMargin == null) {
+ rightMargin = RightMargin()
+ this.sheet.addMarginRecord(rightMargin!!)
+ }
+ rightMargin!!.margin = value
+ }
+
+ /**
+ * Sets the sheet's top print margin.
+ */
+ fun setTopMargin(value: Double) {
+ if (topMargin == null) {
+ topMargin = TopMargin()
+ this.sheet.addMarginRecord(topMargin!!)
+ }
+ topMargin!!.margin = value
+ }
+
+ /**
+ * Sets the sheet's bottom print margin.
+ */
+ fun setBottomMargin(value: Double) {
+ if (bottomMargin == null) {
+ bottomMargin = BottomMargin()
+ this.sheet.addMarginRecord(bottomMargin!!)
+ }
+ bottomMargin!!.margin = value
+ }
+
+ /**
+ * Set the output printer resolution
+ *
+ * @param resolution The resolution to set in DPI.
+ */
+ fun setResolution(r: Int) {
+ printerSettings!!.resolution = r.toShort()
+ }
+
+ /**
+ * scale the printer output in whole percentages
+ *
+ *
+ * ie: 25 = 25%
+ *
+ * @param scale The scale to set.
+ */
+ fun setScale(scale: Int) {
+ printerSettings!!.scale = scale.toShort()
+ }
+
+ /**
+ * @param copies The number of copies to print
+ */
+ fun setCopies(copies: Int) {
+ printerSettings!!.copies = copies.toShort()
+ }
+
+ /**
+ * sets the paper size based on the paper size table
+ *
+ * @param the paper size index
+ */
+ fun setPaperSize(p: Int) {
+ printerSettings!!.paperSize = p.toShort()
+ }
+
+ /**
+ * Sets whether to print the grid lines.
+ */
+ fun setPrintGrid(print: Boolean) {
+ grid!!.isPrintGrid = print
+ }
+
+ companion object {
+
+
+ // paper size ints
+ val PAPER_SIZE_UNDEFINED = 0
+ val PAPER_SIZE_LETTER_8_5x11 = 1 // Letter 81/2" x 11"
+ val PAPER_SIZE_LETTER_SMALL = 2 // Letter small 81/2" x 11"
+ val PAPER_SIZE_TABLOID_11x17 = 3 // Tabloid 11" x 17"
+ val PAPER_SIZE_LEDGER_17x11 = 4 // Ledger 17" x 11"
+ val PAPER_SIZE_LEGAL_8_5x14 = 5 // Legal 81/2" x 14"
+ val PAPER_SIZE_STATEMENT_5_5x8_5 = 6 // Statement 51/2" x 81/2"
+ val PAPER_SIZE_LETTER_EXTRA_9_5Ax12 = 50 // Letter Extra 91/2" x 12
+ val PAPER_SIZE_LEGAL_EXTRA_9_5Ax15 = 51 // Legal Extra 91/2" x 15"
+ val PAPER_SIZE_TABLOID_EXTRA_1111_16Ax18 = 52 // Tabloid Extra 1111/16" x 18"
+ val PAPER_SIZE_A4_EXTRA_235MM_X_322MM = 53 // A4 Extra 235mm x 322mm
+ val PAPER_SIZE_LETTER_TRANSVERSE_8_5Ax11 = 54 // Letter Transverse 81/2" x 11"
+ val PAPER_SIZE_EXECUTIVE_7_QUARTER_X_10_5 = 7 // Executive 71/4" x 101/2"
+ val PAPER_SIZE_TRANSVERSE_210MM_X_297MM = 55 // A4 Transverse 210mm x 297mm
+ val PAPER_SIZE_A3_297MM_X_420MM = 8 // 8 A3 297mm x 420mm
+ val PAPER_SIZE_LETTER_EXTRA_TRANSV_9_5_X_12 = 56 // 56 Letter Extra Transv. 91/2" x 12"
+ val PAPER_SIZE_A4_210MM_X_297MM = 9 // A4 210mm x 297mm
+ val PAPER_SIZE_SUPER_A_A4_227MM_X_356MM = 57 // Super A/A4 227mm x 356mm
+ val PAPER_SIZE_A4_SMALL_210MM_X_297MM = 10 // A4 small 210mm x 297mm
+ val PAPER_SIZE_SUPER_B_A3_305MM_X_487MM = 58 // Super B/A3 305mm x 487mm
+ val PAPER_SIZE_A5_148MM_X_210MM = 11 // A5 148mm x 210mm
+ val PAPER_SIZE_LETTER_PLUS = 59 // Letter Plus
+ val PAPER_SIZE_2_X_1211_16 = 81 // 2" x 1211/16"
+ val PAPER_SIZE_B4_JIS_257MM_X_364MM = 12 // B4 (JIS) 257mm x 364mm
+ val PAPER_SIZE_A4_PLUS_210MM_X_330MM = 60 // A4 Plus 210mm x 330mm
+ val PAPER_SIZE_B5_JIS_182MM_X_257MM = 13 // B5 (JIS) 182mm x 257mm
+ val PAPER_SIZE_A5_TRANSVERSE_148MM_X_210MM = 61 // A5 Transverse 148mm x 210mm
+ val PAPER_SIZE_FOLIO_8_5_X_13 = 14 // Folio 81/2" x 13"
+ val PAPER_SIZE_B5_JIS_TRANSVERSE_182MM_X_257MM = 62 // B5 (JIS) Transverse 182mm x 257mm
+ val PAPER_SIZE_QUATRO_215MM_X_275MM = 15 // Quarto 215mm x 275mm
+ val PAPER_SIZE_A3_EXTRA_322MM_X_445MM = 63 // A3 Extra 322mm x 445mm
+ val PAPER_SIZE_10Ax14_10_X_14 = 16 // 10x14 10" x 14"
+ val PAPER_SIZE_A5_EXTRA_174MM_X_235 = 64 // A5 Extra 174mm x 235mm
+ val PAPER_SIZE_11Ax17_11_X_17 = 17 // 11x17 11" x 17"
+ val PAPER_SIZE_B5_ISO_EXTRA_201MM_X_276MM = 65 // B5 (ISO) Extra 201mm x 276mm
+ val PAPER_SIZE_NOTE_8_5_X_11 = 18 // Note 81/2" x 11"
+ val PAPER_SIZE_A2_420MM_X_594MM = 66 // A2 420mm x 594mm
+ val PAPER_SIZE_ENVELOPE_9_3_78_X_8_78 = 19 // Envelope #9 37/8" x 87/8"
+ val PAPER_SIZE_A3_TRANSVERSE_297MM_X_420MM = 67 // A3 Transverse 297mm x 420mm
+ val PAPER_SIZE_ENVELOPE_10_4_18_X_9_5 = 20 // Envelope #10 41/8" x 91/2"
+ val PAPER_SIZE_EXTRA_TRANSVERSE_322MM_X_445MM = 68 // A3 Extra Transverse 322mm x 445mm
+ val PAPER_SIZE_ENVELOPE_11_4_5_X_10_38 = 21 // Envelope #11 41/2" x 103/8"
+ val PAPER_SIZE_DBL_JAP_POSTCARD_200MM_X_148MM = 69 // Dbl. Japanese Postcard 200mm x 148mm
+ val PAPER_SIZE_ENVELOPE_12_4_34_X_11 = 22 // Envelope #12 43/4" x 11"
+ val PAPER_SIZE_A6_105MM_X_148MM = 70 // A6 105mm x 148mm
+ val PAPER_SIZE_ENVELOPE_14_5_X_11_5 = 23 // Envelope #14 5" x 111/2"
+ val PAPER_SIZE_C_17_X_22_72 = 24 // C 17" x 22" 72
+ val PAPER_SIZE_D_22_X_34_73 = 25 // D 22" x 34" 73
+ val PAPER_SIZE_E_34_X_44_74 = 26 // E 34" x 44" 74
+ val PAPER_SIZE_DL_ENVELOPE_110MM_X_110MM_X_220MM = 27 // Envelope DL 110mm x 220mm
+ val PAPER_SIZE_LETTER_ROTATED_11_X_8_5 = 75 // Letter Rotated 11" x 81/2"
+ val PAPER_SIZE_ENVELOPE_C5_162MM_X_229M = 28 // Envelope C5 162mm x 229mm
+ val PAPER_SIZE_A3_ROTATED_420MM_X_297MM = 76 // A3 Rotated 420mm x 297mm
+ val PAPER_SIZE_ENVELOPE_C3_324MM_X_458MM = 29 // Envelope C3 324mm x 458mm
+ val PAPER_SIZE_A4_ROTATED_297MM_X_210MM = 77 // A4 Rotated 297mm x 210mm
+ val PAPER_SIZE_ENVELOPE_C4_229MM_X_324MM = 30 // Envelope C4 229mm x 324mm
+ val PAPER_SIZE_A5_ROTATED_210MM_X_148MM = 78 // A5 Rotated 210mm x 148mm
+ val PAPER_SIZE_ENVELOPE_C6_115MM_X_162MM = 31 // Envelope C6 114mm x 162mm
+ val PAPER_SIZE_ENVELOPE_C6_C5_114MM_X_229MM = 32 // Envelope C6/C5 114mm x 229mm
+ val PAPER_SIZE_B4_ISO_250MM_X_353MM = 33 // B4 (ISO) 250mm x 353mm
+ val PAPER_SIZE_B5_ISO_176MM_X_250MM = 34 // B5 (ISO) 176mm x 250mm
+ val PAPER_SIZE_DBL_JAP_POSTCARD_ROT_148MM_X_200MM = 82 // Dbl. Jap. Postcard Rot. 148mm x 200mm
+ val PAPER_SIZE_B6_ISO_125MM_X_176MM = 35 // B6 (ISO) 125mm x 176mm
+ val PAPER_SIZE_ENVELOPE_ITALY_10MM_X_230MM = 36 // Envelope Italy 110mm x 230mm 84
+ val PAPER_SIZE_ENVELOPE_MONARCH_3_7_8_X_7_5 = 37 // Envelope Monarch 37/8" x 71/2" 85
+ val PAPER_SIZE_6_3_4_ENVELOPE_3_5_8_X_6_5 = 38 // 63/4 Envelope 35/8" x 61/2" 86
+ val PAPER_SIZE_US_STANDARD_FANFOLD_147_8_X_11 = 39 // US Standard Fanfold 147/8" x 11" 87
+ val PAPER_SIZE_GERMAN_STD_FANFOLD_8_5_X_12 = 40 // German Std. Fanfold 81/2" x 12"
+ val PAPER_SIZE_GERMAN_LEGAL_FANFOLD_8_5_X_13 = 41 // German Legal Fanfold 81/2" x 13"
+ // public static final int PAPER_SIZE_B4_ISO_250MM_X_353MM = 42 ; // B4 (ISO) 250mm x 353mm
+ val PAPER_SIZE_JAP_POSTCARD_100M_X_148MM = 43 // Japanese Postcard 100mm x 148mm
+ val PAPER_SIZE_9_X_11 = 44 // 9x11 9" x 11"
+ val PAPER_SIZE_10_X_11 = 45 // 10x11 10" x 11"
+ val PAPER_SIZE_15_X_11 = 46 // 15x11 15" x 11"
+ val PAPER_SIZE_ENVELOPE_INVITE_220MM_X_220MM = 47 // Envelope Invite 220mm x 220mm
+ val PAPER_SIZE_B4_JIS_ROTATED_364MM_X_257MM = 79 // B4 (JIS) Rotated 364mm x 257mm
+ val PAPER_SIZE_B5_JIS_ROTATED_257MMX_X_182MM = 80 // B5 (JIS) Rotated 257mm x 182mm
+ val PAPER_SIZE_JAP_POSTCARD_ROT_148MM_X_100MM = 81 // Japanese Postcard Rot. 148mm x 100mm
+ val PAPER_SIZE_A6_ROTATED_148MM_X_105MM = 83 // A6 Rotated 148mm x 105mm
+ val PAPER_SIZE_B6_JIS_128MM_X_182MM = 88 // B6 (JIS) 128mm x 182mm
+ val PAPER_SIZE_B6_JIS_ROT_182MM_X_128MM = 89 // B6 (JIS) Rotated 182mm x 128mm
+ val PAPER_SIZE_12_X_11 = 90 // 12x11 12" x 11"
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/starter/OpenXLS/RowHandle.java b/src/main/java/io/starter/OpenXLS/RowHandle.java
deleted file mode 100644
index 655aa00..0000000
--- a/src/main/java/io/starter/OpenXLS/RowHandle.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * --------- BEGIN COPYRIGHT NOTICE ---------
- * Copyright 2002-2012 Extentech Inc.
- * Copyright 2013 Infoteria America Corp.
- *
- * This file is part of OpenXLS.
- *
- * OpenXLS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * OpenXLS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with OpenXLS. If not, see
- * .
- * ---------- END COPYRIGHT NOTICE ----------
- */
-package io.starter.OpenXLS;
-
-import static io.starter.OpenXLS.JSONConstants.*;
-
-import io.starter.formats.XLS.*;
-import io.starter.toolkit.Logger;
-import io.starter.toolkit.StringTool;
-
-import java.awt.Toolkit;
-import java.util.*;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-
-/** The RowHandle provides access to a Worksheet Row and its Cells.
-
- Use the RowHandle to work with individual Rows in an XLS file.
-
- With a RowHandle you can:
-
- get a handle to the Cells in a row
- set the default formatting for a Row
-
-
- @see WorkBookHandle
- @see WorkSheetHandle
- @see FormulaHandle
-*/
-public class RowHandle {
- // FYI: do not change lightly -- these match Excel 2007 almost exactly
- public static int ROW_HEIGHT_DIVISOR = 17;
-
- public Row myRow;
- private FormatHandle formatter;
- private WorkBook wbh;
- private WorkSheetHandle wsh;
-
- protected RowHandle(Row c, WorkSheetHandle ws){
- myRow = c;
- wbh = ws.getWorkBook();
- wsh = ws;
- }
-
- /**
- * Return the row height of an existing row.
- *
- * These values are returned in twips, 1/20th of a character.
- *
- @return int Height of Row in twips
- */
- public int getHeight(){
- return myRow.getRowHeight();
- }
-
- /**
- * returns the row height in Excel units, which depends upon the default font
- * in Arial 10 pt, standard row height is 12.75 points
- * @return int row height in Excel units
- */
- public int getHeightInChars() {
- return myRow.getRowHeight()/20;
- }
-
-
- /**
- * Return the row height of an existing row.
- *
- * These values are returned in twips, 1/20th of a character.
- *
- * @param sheet
- * @param row
- * @return
- */
- public static int getHeight(Boundsheet sheet, int row) {
- int h= 255;
- try {
- Row r = sheet.getRowByNumber(row);
- if(r!=null)
- h= r.getRowHeight();
- } catch (Exception e) { // exception if no row defined
- h= 255; // default
- }
- return h;
- }
-
- /** sets the row height in Excel units.
- @param double i - row height value in Excel units
- */
- public void setHeightInChars(int newHeight) {
- this.setHeight(newHeight*20); // 20090506 KSC: apparently it's in twips ?? 1/20 of a point
- }
-
- /**
- * sets the row height to auto fit
- * When the row height is set manually, autofit is automatically turned off
- */
- public void setRowHeightAutoFit() {
- // this.myRow.setUnsynched(false); // firstly, set so excel
- Collection> ct = myRow.getCells();
- Iterator> it = ct.iterator();
- double h= 0;
- int dpi = Toolkit.getDefaultToolkit().getScreenResolution(); // 96 is "small", 120 dpi is "lg"
- // 1 point= 1/72 of an inch
- // 1 twip= 1 twip= 1/20 of a point
- // this should be a pretty good pixels/twips conversion factor.
- double factorTwip = (double)dpi / 72 / 20; // .06 is "normal"
- // factorZero is width of 0 char in default font. If assume Arial 10 pt, it is 6 + 1= 7
- double factorZero= 7; //java.awt.Toolkit.getDefaultToolkit().getFontMetrics(f).charWidth('0') + 1;
-
- while(it.hasNext()) {
- XLSRecord cellrec= (XLSRecord)it.next();
- try {
- double newH= 255; // default row height
- try {
- Font ef= cellrec.getXfRec().getFont();
- int style= java.awt.Font.PLAIN;
- if (ef.getBold())
- style |= java.awt.Font.BOLD;
- if (ef.getItalic())
- style |= java.awt.Font.ITALIC;
- java.awt.Font f= new java.awt.Font(ef.getFontName(), style, (int)ef.getFontHeightInPoints());
- String s= cellrec.getStringVal();
- if (!cellrec.getXfRec().getWrapText()) // normal case, no wrap
- newH= StringTool.getApproximateHeight(f, s, Double.MAX_VALUE);
- else { // wrap to column width
- // convert column width to pixels
- // factorZero is usually 7 // double factorZero= java.awt.Toolkit.getDefaultToolkit().getFontMetrics(f).charWidth('0') + 1;
- double cw= ColHandle.getWidth(this.wsh.getBoundsheet(), cellrec.getColNumber())/256.0;
- newH= StringTool.getApproximateHeight(f, s, cw*factorZero);
- }
-// this doesn't work correctly newH/=factorTwip; // pixels * twips/pixels == twips)
- newH*=20; // this is better ...
- } catch (Exception e) {
- Logger.logErr("RowHandle.setRowHeightAutoFit: " + e.toString());
- }
-
- h= Math.max(h, newH);
- } catch (Exception e) { }
- }
- if (h > 0)
- this.myRow.setRowHeight((int) Math.ceil(h));
- }
- /**
- * Sets the row height in twips (1/20th of a point)
- * @param newHeight
- */
- public void setHeight(int newHeight){
- /* 20080604 KSC: if an image falls upon this column,
- * adjust image width so that it does not change
- */
- ArrayList iAdjust= new ArrayList();
- ImageHandle[] images= myRow.getSheet().getImages();
- if(images!=null) {
- // for each image that falls over this row, trap index + original width -- to be reset after setting row height
- for (int z= 0; z < images.length; z++) {
- ImageHandle ih= images[z];
- int r0= ih.getRow();
- int r1= ih.getRow1();
- int row= myRow.getRowNumber();
- if (row>=r0 && row<=r1) {
- int h= ih.getHeight();
- iAdjust.add(new int[]{z,h});
- }
- }
- }
- myRow.setRowHeight(newHeight);
- for (int z= 0; z < iAdjust.size(); z++) {
- ImageHandle ih= images[((int[]) iAdjust.get(z))[0]];
- ih.setHeight(((int[]) iAdjust.get(z))[1]);
- }
-
- }
-
- /**
- * Determines if the row passes through
- * a vertical merge range
- *
- * @return
- */
- public boolean containsVerticalMergeRange() {
- CellHandle[] c = this.getCells();
- for (int i=0;i1)return true;
- }catch (Exception e) {};
- }
- }
- return false;
- }
- /** sets the default format id for the Row's Cells
-
- @param int Format Id for all Cells in Row
- */
- public void setFormatId(int i){
- myRow.setIxfe(i);
- }
-
- /** Gets the FormatHandle for this Row.
-
- @return FormatHandle - a Format object to apply to this Row
-*/
- public FormatHandle getFormatHandle(){
- if(this.formatter==null)this.setFormatHandle();
- return this.formatter;
- }
-
-
- /**
- * Set up the format handle for this row
- *
- */
- private void setFormatHandle() {
- if(formatter!=null)return;
- formatter = new FormatHandle(wbh, this.getFormatId());
- formatter.setRowHandle(this);
- }
-
- /** gets the current default row format id. May be overwritten by contained cells
- *
- * @return format id of row
- */
- public int getFormatId(){
- if(myRow.getExplicitFormatSet())return myRow.getIxfe();
- return this.getWorkBook().getWorkBook().getDefaultIxfe();
- }
-
- /** Returns the array of Cells in this Row
-
- @return Cell[] all Cells in this Row
- @param cache cellhandles flag
- */
- public CellHandle[] getCells(boolean cached){
- Collection> ct = myRow.getCells();
- Iterator> it = ct.iterator();
- CellHandle[] ch = new CellHandle[ct.size()];
- int t = 0;
- Mulblank aMul= null;
- short c= -1;
- while(it.hasNext()) {
- BiffRec rc = (BiffRec)it.next();
- try{ // use cache of Cellhandles!
- if (rc.getOpcode()!=XLSConstants.MULBLANK) {
- ch[t] = this.wsh.getCell(rc.getRowNumber(), rc.getColNumber(), cached);
- } else {
- // handle Mulblanks: ref a range of cells; to get correct cell address,
- // traverse thru range and set cellhandle ref to correct column
- if (rc==aMul) {
- c++;
- } else {
- aMul= (Mulblank)rc;
- c= (short)aMul.getColFirst();
- }
- ch[t]= this.wsh.getCell(rc.getRowNumber(), c, cached);
- }
- }catch(CellNotFoundException cnfe){
- rc.setXFRecord();
- ch[t] = new CellHandle(rc,null);
- ch[t].setWorkSheetHandle(null); //TODO: implement if causing grief -jm
- if (rc.getOpcode()==XLSConstants.MULBLANK) {
- // handle Mulblanks: ref a range of cells; to get correct cell address,
- // traverse thru range and set cellhandle ref to correct column
- if (rc==aMul) {
- c++;
- } else {
- aMul= (Mulblank)rc;
- c= (short)aMul.getColFirst();
- }
- ch[t].setBlankRef(c); // for Mulblank use only -sets correct column reference for multiple blank cells ...
- }
-
- }
- t++;
- }
- return ch;
- }
-
- /** Returns the array of Cells in this Row
-
- @return Cell[] all Cells in this Row
- */
- public CellHandle[] getCells(){
- return getCells(false); // don't use cache
- }
-
-
- /**
- * Get the JSON object for this row.
- *
- * @return
- */
- public String getJSON() {
- return getJSON( 255 ).toString();
- }
-
- public JSONObject getJSON (int maxcols) {
- JSONObject theRange = new JSONObject();
- JSONArray cells = new JSONArray();
- try {
- theRange.put(JSON_ROW, getRowNumber());
-
- theRange.put( JSON_ROW_BORDER_TOP, getHasAnyThickTopBorder() );
- theRange.put( JSON_ROW_BORDER_BOTTOM, getHasAnyBottomBorder() );
- if (getFormatId()!=getWorkBook().getWorkBook().getDefaultIxfe())theRange.put("xf", getFormatId());
- theRange.put(JSON_HEIGHT, (getHeight()/ROW_HEIGHT_DIVISOR)+5); // the default is TOO SMALL!
- CellHandle[] chandles = getCells(false);
- for (int i=0;i=maxcols) {
- i=chandles.length;
- }else if (thisCell.getCell().getOpcode() == XLSRecord.MULBLANK){
- Mulblank mb = (Mulblank) thisCell.getCell();
- ArrayList columns = mb.getColReferences();
- for (int x=0; x .
+ * ---------- END COPYRIGHT NOTICE ----------
+ */
+package io.starter.OpenXLS
+
+import io.starter.formats.XLS.Font
+import io.starter.formats.XLS.*
+import io.starter.toolkit.Logger
+import io.starter.toolkit.StringTool
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+
+import java.awt.*
+import java.util.ArrayList
+
+import io.starter.OpenXLS.JSONConstants.*
+
+
+/**
+ * The RowHandle provides access to a Worksheet Row and its Cells.
+ *
+ * Use the RowHandle to work with individual Rows in an XLS file.
+ *
+ * With a RowHandle you can:
+ *
+ * get a handle to the Cells in a row
+ * set the default formatting for a Row
+ *
+ *
+ * @see WorkBookHandle
+ *
+ * @see WorkSheetHandle
+ *
+ * @see FormulaHandle
+ */
+class RowHandle(var myRow: Row, val workSheetHandle: WorkSheetHandle) {
+ private var formatter: FormatHandle? = null
+ val workBook: WorkBook?
+
+ /**
+ * Return the row height of an existing row.
+ *
+ *
+ * These values are returned in twips, 1/20th of a character.
+ *
+ * @return int Height of Row in twips
+ */
+ /**
+ * Sets the row height in twips (1/20th of a point)
+ *
+ * @param newHeight
+ */
+ /* 20080604 KSC: if an image falls upon this column,
+ * adjust image width so that it does not change
+ */// for each image that falls over this row, trap index + original width -- to be reset after setting row height
+ var height: Int
+ get() = myRow.rowHeight
+ set(newHeight) {
+ val iAdjust = ArrayList()
+ val images = myRow.sheet!!.images
+ if (images != null) {
+ for (z in images.indices) {
+ val ih = images[z]
+ val r0 = ih.row
+ val r1 = ih.row1
+ val row = myRow.rowNumber
+ if (row >= r0 && row <= r1) {
+ val h = ih.height.toInt()
+ iAdjust.add(intArrayOf(z, h))
+ }
+ }
+ }
+ myRow.rowHeight = newHeight
+ for (z in iAdjust.indices) {
+ val ih = images!![iAdjust[z][0]]
+ ih.setHeight(iAdjust[z][1])
+ }
+
+ }
+
+ /**
+ * returns the row height in Excel units, which depends upon the default font
+ * in Arial 10 pt, standard row height is 12.75 points
+ *
+ * @return int row height in Excel units
+ */
+ /**
+ * sets the row height in Excel units.
+ *
+ * @param double i - row height value in Excel units
+ */
+ // 20090506 KSC: apparently it's in twips ?? 1/20 of a point
+ var heightInChars: Int
+ get() = myRow.rowHeight / 20
+ set(newHeight) {
+ this.height = newHeight * 20
+ }
+
+ /**
+ * Gets the FormatHandle for this Row.
+ *
+ * @return FormatHandle - a Format object to apply to this Row
+ */
+ val formatHandle: FormatHandle?
+ get() {
+ if (this.formatter == null) this.setFormatHandle()
+ return this.formatter
+ }
+
+ /**
+ * gets the current default row format id. May be overwritten by contained cells
+ *
+ * @return format id of row
+ */
+ /**
+ * sets the default format id for the Row's Cells
+ *
+ * @param int Format Id for all Cells in Row
+ */
+ var formatId: Int
+ get() = if (myRow.explicitFormatSet) myRow.ixfe else this.workBook!!.workBook.defaultIxfe
+ set(i) {
+ myRow.ixfe = i
+ }
+
+ /**
+ * Returns the array of Cells in this Row
+ *
+ * @return Cell[] all Cells in this Row
+ */
+ // don't use cache
+ val cells: Array
+ get() = getCells(false)
+
+
+ /**
+ * Get the JSON object for this row.
+ *
+ * @return
+ */
+ val json: String
+ get() = getJSON(255).toString()
+
+ /**
+ * Returns the row number of this RowHandle
+ */
+ val rowNumber: Int
+ get() = myRow.rowNumber
+
+ /**
+ * Returns the Outline level (depth) of the row
+ *
+ * @return
+ */
+ /**
+ * Set the Outline level (depth) of the row
+ *
+ * @param x
+ */
+ var outlineLevel: Int
+ get() = myRow.outlineLevel
+ set(x) {
+ myRow.outlineLevel = x
+ }
+
+ /**
+ * Returns whether the row is collapsed
+ *
+ * @return
+ */
+ /**
+ * Set whether the row is collapsed.
+ * Will hide the current row, and all contiguous rows
+ * with the same outline level.
+ *
+ * @param b
+ */
+ var isCollapsed: Boolean
+ get() = myRow.isCollapsed
+ set(b) {
+ myRow.isCollapsed = b
+ }
+
+ /**
+ * Returns whether the row is hidden
+ *
+ * @return
+ */
+ /**
+ * Set whether the row is hidden
+ *
+ * @param b
+ */
+ var isHidden: Boolean
+ get() = myRow.isHidden
+ set(b) {
+ myRow.isHidden = b
+ }
+
+
+ /**
+ * true if row height has been altered from default
+ * i.e. set manually
+ *
+ * @return
+ */
+ val isAlteredHeight: Boolean
+ get() = myRow.isAlteredHeight
+
+ /**
+ * returns true if there is a Thick Top border set on the row
+ */
+ /**
+ * sets this row to have a thick top border
+ */
+ var hasThickTopBorder: Boolean
+ get() = myRow.hasThickTopBorder
+ set(hasBorder) {
+ myRow.hasThickTopBorder = hasBorder
+ }
+
+ /**
+ * returns true if there is a Thick Bottom border set on the row
+ */
+ /**
+ * sets this row to have a thick bottom border
+ */
+ var hasThickBottomBorder: Boolean
+ get() = myRow.hasThickBottomBorder
+ set(hasBorder) {
+ myRow.hasThickBottomBorder = hasBorder
+ }
+
+ /**
+ * returns true if there is a thick top or thick or medium bottom border on previoous row
+ *
+ *
+ * Not useful for public API
+ */
+ val hasAnyThickTopBorder: Boolean
+ get() = myRow.hasAnyThickTopBorder
+
+ /**
+ * Additional space below the row. This flag is set, if the
+ * lower border of at least one cell in this row or if the upper
+ * border of at least one cell in the row below is formatted with
+ * a medium or thick line style. Thin line styles are not taken
+ * into account.
+ *
+ *
+ * Usage of this method is primarily for UI applications, and is not
+ * needed for standard OpenXLS functionality
+ */
+ val hasAnyBottomBorder: Boolean
+ get() = myRow.hasAnyBottomBorder
+
+ /**
+ * return the min/max columns defined for this row
+ *
+ * @return
+ */
+ val colDimensions: IntArray
+ get() = myRow.colDimensions
+
+ init {
+ workBook = workSheetHandle.workBook
+ }
+
+ /**
+ * sets the row height to auto fit
+ * When the row height is set manually, autofit is automatically turned off
+ */
+ fun setRowHeightAutoFit() {
+ // this.myRow.setUnsynched(false); // firstly, set so excel
+ val ct = myRow.cells
+ val it = ct.iterator()
+ var h = 0.0
+ val dpi = Toolkit.getDefaultToolkit().screenResolution // 96 is "small", 120 dpi is "lg"
+ // 1 point= 1/72 of an inch
+ // 1 twip= 1 twip= 1/20 of a point
+ // this should be a pretty good pixels/twips conversion factor.
+ val factorTwip = dpi.toDouble() / 72.0 / 20.0 // .06 is "normal"
+ // factorZero is width of 0 char in default font. If assume Arial 10 pt, it is 6 + 1= 7
+ val factorZero = 7.0 //java.awt.Toolkit.getDefaultToolkit().getFontMetrics(f).charWidth('0') + 1;
+
+ while (it.hasNext()) {
+ val cellrec = it.next() as XLSRecord
+ try {
+ var newH = 255.0 // default row height
+ try {
+ val ef = cellrec.xfRec!!.font
+ var style = java.awt.Font.PLAIN
+ if (ef!!.bold)
+ style = style or java.awt.Font.BOLD
+ if (ef.italic)
+ style = style or java.awt.Font.ITALIC
+ val f = java.awt.Font(ef.fontName, style, ef.fontHeightInPoints.toInt())
+ val s = cellrec.stringVal
+ if (!cellrec.xfRec!!.wrapText)
+ // normal case, no wrap
+ newH = StringTool.getApproximateHeight(f, s, java.lang.Double.MAX_VALUE)
+ else { // wrap to column width
+ // convert column width to pixels
+ // factorZero is usually 7 // double factorZero= java.awt.Toolkit.getDefaultToolkit().getFontMetrics(f).charWidth('0') + 1;
+ val cw = ColHandle.getWidth(this.workSheetHandle.boundsheet, cellrec.colNumber.toInt()) / 256.0
+ newH = StringTool.getApproximateHeight(f, s, cw * factorZero)
+ }
+ // this doesn't work correctly newH/=factorTwip; // pixels * twips/pixels == twips)
+ newH *= 20.0 // this is better ...
+ } catch (e: Exception) {
+ Logger.logErr("RowHandle.setRowHeightAutoFit: $e")
+ }
+
+ h = Math.max(h, newH)
+ } catch (e: Exception) {
+ }
+
+ }
+ if (h > 0)
+ this.myRow.rowHeight = Math.ceil(h).toInt()
+ }
+
+ /**
+ * Determines if the row passes through
+ * a vertical merge range
+ *
+ * @return
+ */
+ fun containsVerticalMergeRange(): Boolean {
+ val c = this.cells
+ for (i in c.indices) {
+ if (c[i].mergedCellRange != null) {
+ val cr = c[i].mergedCellRange
+ try {
+ if (cr!!.rows.size > 1) return true
+ } catch (e: Exception) {
+ }
+
+ }
+ }
+ return false
+ }
+
+
+ /**
+ * Set up the format handle for this row
+ */
+ private fun setFormatHandle() {
+ if (formatter != null) return
+ formatter = FormatHandle(workBook!!, this.formatId)
+ formatter!!.setRowHandle(this)
+ }
+
+ /**
+ * Returns the array of Cells in this Row
+ *
+ * @param cache cellhandles flag
+ * @return Cell[] all Cells in this Row
+ */
+ fun getCells(cached: Boolean): Array {
+ val ct = myRow.cells
+ val it = ct.iterator()
+ val ch = arrayOfNulls | |