diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 2617fbb43..be8df6576 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,7 +36,8 @@ - 44200 - Enable cloning of sheets with notes + 44201 - Enable cloning of sheets with data validation rules + 44200 - Enable cloning of sheets with notes 43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly 43058 - Support setting row grouping on files from CR IX, which lack GutsRecords 31795 - Support cloning of sheets with certain drawing objects on them diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 9e93592fc..5868b0eb2 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,7 +33,8 @@ - 44200 - Enable cloning of sheets with notes + 44201 - Enable cloning of sheets with data validation rules + 44200 - Enable cloning of sheets with notes 43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly 43058 - Support setting row grouping on files from CR IX, which lack GutsRecords 31795 - Support cloning of sheets with certain drawing objects on them diff --git a/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java index 0260fc915..c5fae27ae 100644 --- a/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java +++ b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java @@ -18,7 +18,6 @@ package org.apache.poi.hssf.record; -import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -232,19 +231,7 @@ public abstract class AbstractEscherHolderRecord public Object clone() { - // Do it via a re-serialise - // It's a cheat, but it works... - byte[] b = serialize(); - RecordInputStream rinp = new RecordInputStream( - new ByteArrayInputStream(b) - ); - rinp.nextRecord(); - - Record[] r = RecordFactory.createRecord(rinp); - if(r.length != 1) { - throw new IllegalStateException("Re-serialised a record to clone it, but got " + r.length + " records back!"); - } - return r[0]; + return cloneViaReserialise(); } public void addEscherRecord(int index, EscherRecord element) diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java index 0bae009bd..e5527d61f 100644 --- a/src/java/org/apache/poi/hssf/record/DVRecord.java +++ b/src/java/org/apache/poi/hssf/record/DVRecord.java @@ -16,16 +16,16 @@ package org.apache.poi.hssf.record; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; + +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.util.HSSFCellRangeAddress; import org.apache.poi.util.BitField; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; -import org.apache.poi.hssf.util.HSSFCellRangeAddress; -import org.apache.poi.hssf.record.formula.Ptg; - -import java.io.IOException; -import java.util.Stack; -import java.util.Hashtable; -import java.util.Enumeration; /** * Title: DV Record

@@ -502,6 +502,14 @@ public class DVRecord extends Record { return this.sid; } + + /** + * Clones the object. Uses serialisation, as the + * contents are somewhat complex + */ + public Object clone() { + return cloneViaReserialise(); + } /**@todo DVRecord = Serializare */ diff --git a/src/java/org/apache/poi/hssf/record/Record.java b/src/java/org/apache/poi/hssf/record/Record.java index 3205c5774..c1b8a0cfd 100644 --- a/src/java/org/apache/poi/hssf/record/Record.java +++ b/src/java/org/apache/poi/hssf/record/Record.java @@ -19,6 +19,8 @@ package org.apache.poi.hssf.record; +import java.io.ByteArrayInputStream; + /** * Title: Record * Description: All HSSF Records inherit from this class. It @@ -147,4 +149,30 @@ public abstract class Record public Object clone() { throw new RuntimeException("The class "+getClass().getName()+" needs to define a clone method"); } + + /** + * Clone the current record, via a call to serialise + * it, and another to create a new record from the + * bytes. + * May only be used for classes which don't have + * internal counts / ids in them. For those which + * do, a full record-aware serialise is needed, which + * allocates new ids / counts as needed. + */ + public Record cloneViaReserialise() + { + // Do it via a re-serialise + // It's a cheat, but it works... + byte[] b = serialize(); + RecordInputStream rinp = new RecordInputStream( + new ByteArrayInputStream(b) + ); + rinp.nextRecord(); + + Record[] r = RecordFactory.createRecord(rinp); + if(r.length != 1) { + throw new IllegalStateException("Re-serialised a record to clone it, but got " + r.length + " records back!"); + } + return r[0]; + } } diff --git a/src/testcases/org/apache/poi/hssf/data/44201.xls b/src/testcases/org/apache/poi/hssf/data/44201.xls new file mode 100644 index 000000000..593d5aa18 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/44201.xls differ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index a3154e306..006b60c3d 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -934,6 +934,26 @@ extends TestCase { } + /** + * Bug 44201: Sheet not cloneable when validation added to excel cell + */ + public void test44201() throws Exception { + FileInputStream in = new FileInputStream(new File(cwd, "44201.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + wb.cloneSheet(0); + assertTrue("No Exceptions while cloning sheet", true); + + //serialize and read again + ByteArrayOutputStream out = new ByteArrayOutputStream(); + wb.write(out); + out.close(); + + wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); + assertTrue("No Exceptions while reading file", true); + + } }