diff --git a/src/java/org/apache/poi/hssf/model/RecordOrderer.java b/src/java/org/apache/poi/hssf/model/RecordOrderer.java
new file mode 100644
index 000000000..ae445597d
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/model/RecordOrderer.java
@@ -0,0 +1,326 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.model;
+
+import java.util.List;
+
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.CalcCountRecord;
+import org.apache.poi.hssf.record.CalcModeRecord;
+import org.apache.poi.hssf.record.DateWindow1904Record;
+import org.apache.poi.hssf.record.DefaultRowHeightRecord;
+import org.apache.poi.hssf.record.DeltaRecord;
+import org.apache.poi.hssf.record.DimensionsRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.GridsetRecord;
+import org.apache.poi.hssf.record.GutsRecord;
+import org.apache.poi.hssf.record.HorizontalPageBreakRecord;
+import org.apache.poi.hssf.record.HyperlinkRecord;
+import org.apache.poi.hssf.record.IndexRecord;
+import org.apache.poi.hssf.record.IterationRecord;
+import org.apache.poi.hssf.record.PaneRecord;
+import org.apache.poi.hssf.record.PrecisionRecord;
+import org.apache.poi.hssf.record.PrintGridlinesRecord;
+import org.apache.poi.hssf.record.PrintHeadersRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
+import org.apache.poi.hssf.record.RefModeRecord;
+import org.apache.poi.hssf.record.SCLRecord;
+import org.apache.poi.hssf.record.SaveRecalcRecord;
+import org.apache.poi.hssf.record.SelectionRecord;
+import org.apache.poi.hssf.record.UncalcedRecord;
+import org.apache.poi.hssf.record.VerticalPageBreakRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
+import org.apache.poi.hssf.record.aggregates.DataValidityTable;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
+
+/**
+ * Finds correct insert positions for records in workbook streams
+ *
+ * See OOO excelfileformat.pdf sec. 4.2.5 'Record Order in a BIFF8 Workbook Stream'
+ *
+ * @author Josh Micich
+ */
+final class RecordOrderer {
+ // TODO - add UninterpretedRecord as base class for many of these
+ // unimplemented sids
+
+ // TODO - simplify logic using a generalised record ordering
+
+ private RecordOrderer() {
+ // no instances of this class
+ }
+ /**
+ * Adds the specified new record in the correct place in sheet records list
+ *
+ */
+ public static void addNewSheetRecord(List sheetRecords, RecordBase newRecord) {
+ int index = findSheetInsertPos(sheetRecords, newRecord.getClass());
+ sheetRecords.add(index, newRecord);
+ }
+
+ private static int findSheetInsertPos(List records, Class recClass) {
+ if (recClass == DataValidityTable.class) {
+ return findDataValidationTableInsertPos(records);
+ }
+ if (recClass == MergedCellsTable.class) {
+ return findInsertPosForNewMergedRecordTable(records);
+ }
+ if (recClass == ConditionalFormattingTable.class) {
+ return findInsertPosForNewCondFormatTable(records);
+ }
+ if (recClass == GutsRecord.class) {
+ return getGutsRecordInsertPos(records);
+ }
+ if (recClass == HorizontalPageBreakRecord.class) {
+ return getPageBreakRecordInsertPos(records, true);
+ }
+ if (recClass == VerticalPageBreakRecord.class) {
+ return getPageBreakRecordInsertPos(records, false);
+ }
+ throw new RuntimeException("Unexpected record class (" + recClass.getName() + ")");
+ }
+
+ private static int getPageBreakRecordInsertPos(List records, boolean isHorizonal) {
+ int dimensionsIndex = getDimensionsIndex(records);
+ int i = dimensionsIndex-1;
+ while (i > 0) {
+ i--;
+ Object rb = records.get(i);
+ if (isPageBreakPriorRecord(rb, isHorizonal)) {
+ return i+1;
+ }
+ }
+ throw new RuntimeException("Did not find insert point for GUTS");
+ }
+ private static boolean isPageBreakPriorRecord(Object rb, boolean newRecIsHorizontal) {
+ if (rb instanceof Record) {
+ Record record = (Record) rb;
+ switch (record.getSid()) {
+ case BOFRecord.sid:
+ case IndexRecord.sid:
+ // calc settings block
+ case UncalcedRecord.sid:
+ case CalcCountRecord.sid:
+ case CalcModeRecord.sid:
+ case PrecisionRecord.sid:
+ case RefModeRecord.sid:
+ case DeltaRecord.sid:
+ case IterationRecord.sid:
+ case DateWindow1904Record.sid:
+ case SaveRecalcRecord.sid:
+ // end calc settings
+ case PrintHeadersRecord.sid:
+ case PrintGridlinesRecord.sid:
+ case GridsetRecord.sid:
+ case DefaultRowHeightRecord.sid:
+ case 0x0081: // SHEETPR
+ return true;
+ }
+ switch (record.getSid()) {
+ // page settings block
+ case HorizontalPageBreakRecord.sid:
+ if (!newRecIsHorizontal) {
+ return true;
+ }
+ return false;
+ case VerticalPageBreakRecord.sid:
+ return false;
+ // next is case HeaderRecord.sid: case FooterRecord.sid:
+ // then more records in page settings block
+
+ }
+ }
+ return false;
+ }
+ /**
+ * Find correct position to add new CFHeader record
+ */
+ private static int findInsertPosForNewCondFormatTable(List records) {
+
+ for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
+ Object rb = records.get(i);
+ if (rb instanceof MergedCellsTable) {
+ return i + 1;
+ }
+ Record rec = (Record) rb;
+ switch (rec.getSid()) {
+ case WindowTwoRecord.sid:
+ case SCLRecord.sid:
+ case PaneRecord.sid:
+ case SelectionRecord.sid:
+ case 0x0099:// STANDARDWIDTH
+ // MergedCellsTable usually here
+ case 0x015f:// LABELRANGES
+ case 0x00ef:// PHONETICPR
+ return i + 1;
+ }
+ }
+ throw new RuntimeException("Did not find Window2 record");
+ }
+
+ private static int findInsertPosForNewMergedRecordTable(List records) {
+ for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
+ Object rb = records.get(i);
+ Record rec = (Record) rb;
+ switch (rec.getSid()) {
+ case WindowTwoRecord.sid:
+ case SCLRecord.sid:
+ case PaneRecord.sid:
+ case SelectionRecord.sid:
+ case 0x0099:// STANDARDWIDTH
+ return i + 1;
+ }
+ }
+ throw new RuntimeException("Did not find Window2 record");
+ }
+
+
+ /**
+ * Finds the index where the sheet validations header record should be inserted
+ * @param records the records for this sheet
+ *
+ * + WINDOW2
+ * o SCL
+ * o PANE
+ * oo SELECTION
+ * o STANDARDWIDTH
+ * oo MERGEDCELLS
+ * o LABELRANGES
+ * o PHONETICPR
+ * o Conditional Formatting Table
+ * o Hyperlink Table
+ * o Data Validity Table
+ * o SHEETLAYOUT
+ * o SHEETPROTECTION
+ * o RANGEPROTECTION
+ * + EOF
+ */
+ private static int findDataValidationTableInsertPos(List records) {
+ int i = records.size() - 1;
+ if (!(records.get(i) instanceof EOFRecord)) {
+ throw new IllegalStateException("Last sheet record should be EOFRecord");
+ }
+ while (i > 0) {
+ i--;
+ Object rb = records.get(i);
+ if (isDVTPriorRecord(rb)) {
+ Record nextRec = (Record) records.get(i + 1);
+ if (!isDVTSubsequentRecord(nextRec.getSid())) {
+ throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName()
+ + ") found after (" + rb.getClass().getName() + ")");
+ }
+ return i+1;
+ }
+ Record rec = (Record) rb;
+ if (!isDVTSubsequentRecord(rec.getSid())) {
+ throw new IllegalStateException("Unexpected (" + rec.getClass().getName()
+ + ") while looking for DV Table insert pos");
+ }
+ }
+ return 0;
+ }
+
+
+ private static boolean isDVTPriorRecord(Object rb) {
+ if (rb instanceof MergedCellsTable || rb instanceof ConditionalFormattingTable) {
+ return true;
+ }
+ short sid = ((Record)rb).getSid();
+ switch(sid) {
+ case WindowTwoRecord.sid:
+ case 0x00A0: // SCL
+ case PaneRecord.sid:
+ case SelectionRecord.sid:
+ case 0x0099: // STANDARDWIDTH
+ // MergedCellsTable
+ case 0x015F: // LABELRANGES
+ case 0x00EF: // PHONETICPR
+ // ConditionalFormattingTable
+ case HyperlinkRecord.sid:
+ case 0x0800: // QUICKTIP
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isDVTSubsequentRecord(short sid) {
+ switch(sid) {
+ case 0x0862: // SHEETLAYOUT
+ case 0x0867: // SHEETPROTECTION
+ case 0x0868: // RANGEPROTECTION
+ case EOFRecord.sid:
+ return true;
+ }
+ return false;
+ }
+ /**
+ * DIMENSIONS record is always present
+ */
+ private static int getDimensionsIndex(List records) {
+ int nRecs = records.size();
+ for(int i=0; i 0) {
+ i--;
+ Object rb = records.get(i);
+ if (isGutsPriorRecord(rb)) {
+ return i+1;
+ }
+ }
+ throw new RuntimeException("Did not find insert point for GUTS");
+ }
+
+ private static boolean isGutsPriorRecord(Object rb) {
+ if (rb instanceof Record) {
+ Record record = (Record) rb;
+ switch (record.getSid()) {
+ case BOFRecord.sid:
+ case IndexRecord.sid:
+ // calc settings block
+ case UncalcedRecord.sid:
+ case CalcCountRecord.sid:
+ case CalcModeRecord.sid:
+ case PrecisionRecord.sid:
+ case RefModeRecord.sid:
+ case DeltaRecord.sid:
+ case IterationRecord.sid:
+ case DateWindow1904Record.sid:
+ case SaveRecalcRecord.sid:
+ // end calc settings
+ case PrintHeadersRecord.sid:
+ case PrintGridlinesRecord.sid:
+ case GridsetRecord.sid:
+ return true;
+ // DefaultRowHeightRecord.sid is next
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java
index 993dfd7b3..3d74c9f88 100644
--- a/src/java/org/apache/poi/hssf/model/Sheet.java
+++ b/src/java/org/apache/poi/hssf/model/Sheet.java
@@ -17,22 +17,77 @@
package org.apache.poi.hssf.model;
-import org.apache.poi.hssf.record.*; // normally I don't do this, buy we literally mean ALL
-import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
-import org.apache.poi.hssf.record.aggregates.DataValidityTable;
-import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
-import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
-import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
-import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
-import org.apache.poi.hssf.util.CellRangeAddress;
-import org.apache.poi.hssf.util.PaneInformation;
-
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-
import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
+import java.util.List;
+
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BottomMarginRecord;
+import org.apache.poi.hssf.record.CFHeaderRecord;
+import org.apache.poi.hssf.record.CalcCountRecord;
+import org.apache.poi.hssf.record.CalcModeRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.ColumnInfoRecord;
+import org.apache.poi.hssf.record.DBCellRecord;
+import org.apache.poi.hssf.record.DVALRecord;
+import org.apache.poi.hssf.record.DefaultColWidthRecord;
+import org.apache.poi.hssf.record.DefaultRowHeightRecord;
+import org.apache.poi.hssf.record.DeltaRecord;
+import org.apache.poi.hssf.record.DimensionsRecord;
+import org.apache.poi.hssf.record.DrawingRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.EscherAggregate;
+import org.apache.poi.hssf.record.FooterRecord;
+import org.apache.poi.hssf.record.GridsetRecord;
+import org.apache.poi.hssf.record.GutsRecord;
+import org.apache.poi.hssf.record.HCenterRecord;
+import org.apache.poi.hssf.record.HeaderRecord;
+import org.apache.poi.hssf.record.HorizontalPageBreakRecord;
+import org.apache.poi.hssf.record.IndexRecord;
+import org.apache.poi.hssf.record.IterationRecord;
+import org.apache.poi.hssf.record.LeftMarginRecord;
+import org.apache.poi.hssf.record.Margin;
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.ObjRecord;
+import org.apache.poi.hssf.record.ObjectProtectRecord;
+import org.apache.poi.hssf.record.PageBreakRecord;
+import org.apache.poi.hssf.record.PaneRecord;
+import org.apache.poi.hssf.record.PasswordRecord;
+import org.apache.poi.hssf.record.PrintGridlinesRecord;
+import org.apache.poi.hssf.record.PrintHeadersRecord;
+import org.apache.poi.hssf.record.PrintSetupRecord;
+import org.apache.poi.hssf.record.ProtectRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
+import org.apache.poi.hssf.record.RefModeRecord;
+import org.apache.poi.hssf.record.RightMarginRecord;
+import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SCLRecord;
+import org.apache.poi.hssf.record.SaveRecalcRecord;
+import org.apache.poi.hssf.record.ScenarioProtectRecord;
+import org.apache.poi.hssf.record.SelectionRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.TopMarginRecord;
+import org.apache.poi.hssf.record.UncalcedRecord;
+import org.apache.poi.hssf.record.VCenterRecord;
+import org.apache.poi.hssf.record.VerticalPageBreakRecord;
+import org.apache.poi.hssf.record.WSBoolRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
+import org.apache.poi.hssf.record.aggregates.DataValidityTable;
+import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate;
+import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
+import org.apache.poi.hssf.util.CellRangeAddress;
+import org.apache.poi.hssf.util.PaneInformation;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
/**
* Low level model implementation of a Sheet (one workbook contains many sheets)
@@ -72,30 +127,30 @@ public final class Sheet implements Model {
protected DefaultColWidthRecord defaultcolwidth = null;
protected DefaultRowHeightRecord defaultrowheight = null;
protected GridsetRecord gridset = null;
+ private GutsRecord _gutsRecord;
protected PrintSetupRecord printSetup = null;
protected HeaderRecord header = null;
protected FooterRecord footer = null;
protected PrintGridlinesRecord printGridlines = null;
protected WindowTwoRecord windowTwo = null;
- protected MergeCellsRecord merged = null;
protected Margin[] margins = null;
- protected List mergedRecords = new ArrayList();
- protected int numMergedRegions = 0;
+ private MergedCellsTable _mergedCellsTable;
protected SelectionRecord selection = null;
- protected ColumnInfoRecordsAggregate columns = null;
+ /** always present in this POI object, not always written to Excel file */
+ /*package*/ColumnInfoRecordsAggregate _columnInfos;
protected ValueRecordsAggregate cells = null;
- protected RowRecordsAggregate rows = null;
+ protected RowRecordsAggregate _rowsAggregate = null;
private Iterator valueRecIterator = null;
private Iterator rowRecIterator = null;
protected int eofLoc = 0;
protected ProtectRecord protect = null;
- protected PageBreakRecord rowBreaks = null;
- protected PageBreakRecord colBreaks = null;
+ protected PageBreakRecord _rowBreaksRecord;
+ protected PageBreakRecord _columnBreaksRecord;
private DataValidityTable _dataValidityTable= null;
protected ObjectProtectRecord objprotect = null;
protected ScenarioProtectRecord scenprotect = null;
protected PasswordRecord password = null;
- protected List condFormatting = new ArrayList();
+ private ConditionalFormattingTable condFormatting;
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
protected boolean _isUncalced = false;
@@ -139,13 +194,70 @@ public final class Sheet implements Model {
Sheet retval = new Sheet();
ArrayList records = new ArrayList(recs.size() / 5);
boolean isfirstcell = true;
- boolean isfirstrow = true;
int bofEofNestingLevel = 0;
for (int k = offset; k < recs.size(); k++)
{
Record rec = ( Record ) recs.get(k);
+ if (rec.isValue() != (rec instanceof CellValueRecordInterface)) {
+ if (rec instanceof SharedFormulaRecord) {
+
+ } else {
+ "".length();
+ }
+ }
+ if ( rec.getSid() == DBCellRecord.sid ) {
+ continue;
+ }
+ if ( rec.getSid() == IndexRecord.sid ) {
+ // ignore INDEX record because it is only needed by Excel,
+ // and POI always re-calculates its contents
+ continue;
+ }
+ if ( rec.getSid() == StringRecord.sid ) {
+ continue;
+ }
+
+ if ( rec.getSid() == CFHeaderRecord.sid ) {
+ RecordStream rs = new RecordStream(recs, k);
+ retval.condFormatting = new ConditionalFormattingTable(rs);
+ k += rs.getCountRead()-1;
+ records.add(retval.condFormatting);
+ continue;
+ }
+
+ if (rec.getSid() == ColumnInfoRecord.sid) {
+ RecordStream rs = new RecordStream(recs, k);
+ retval._columnInfos = new ColumnInfoRecordsAggregate(rs);
+ k += rs.getCountRead()-1;
+ records.add(retval._columnInfos);
+ continue;
+ }
+ if ( rec.getSid() == DVALRecord.sid) {
+ RecordStream rs = new RecordStream(recs, k);
+ retval._dataValidityTable = new DataValidityTable(rs);
+ k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
+ records.add(retval._dataValidityTable);
+ continue; // TODO
+ }
+ if ( rec.getSid() == RowRecord.sid )
+ {
+ RowRecord row = (RowRecord)rec;
+ if (retval._rowsAggregate == null) {
+ retval._rowsAggregate = new RowRecordsAggregate();
+ records.add(retval._rowsAggregate); //only add the aggregate once
+ }
+ retval._rowsAggregate.insertRow(row);
+ continue;
+ }
+ if (rec.getSid() == MergeCellsRecord.sid) {
+ RecordStream rs = new RecordStream(recs, k);
+ retval._mergedCellsTable = new MergedCellsTable(rs);
+ records.add(retval._mergedCellsTable);
+ continue; // TODO
+ }
+
if (rec.getSid() == BOFRecord.sid)
{
bofEofNestingLevel++;
@@ -169,53 +281,15 @@ public final class Sheet implements Model {
else if (rec.getSid() == DimensionsRecord.sid)
{
// Make a columns aggregate if one hasn't ready been created.
- if (retval.columns == null)
+ if (retval._columnInfos == null)
{
- retval.columns = new ColumnInfoRecordsAggregate();
- records.add(retval.columns);
+ retval._columnInfos = new ColumnInfoRecordsAggregate();
+ records.add(retval._columnInfos);
}
retval.dims = ( DimensionsRecord ) rec;
retval.dimsloc = records.size();
}
- else if (rec.getSid() == MergeCellsRecord.sid)
- {
- retval.mergedRecords.add(rec);
- retval.merged = ( MergeCellsRecord ) rec;
- retval.numMergedRegions += retval.merged.getNumAreas();
- }
- else if ( rec.getSid() == CFHeaderRecord.sid )
- {
- CFRecordsAggregate cfAgg = CFRecordsAggregate.createCFAggregate(recs, k);
- retval.condFormatting.add(cfAgg);
- rec = cfAgg;
- }
- else if ( rec.getSid() == CFRuleRecord.sid )
- {
- // Skip it since it is processed by CFRecordsAggregate
- rec = null;
- }
- else if (rec.getSid() == ColumnInfoRecord.sid)
- {
- ColumnInfoRecord col = (ColumnInfoRecord)rec;
- if (retval.columns != null)
- {
- rec = null; //only add the aggregate once
- }
- else
- {
- rec = retval.columns = new ColumnInfoRecordsAggregate();
- }
- retval.columns.insertColumn(col);
- }
- else if (rec.getSid() == DefaultColWidthRecord.sid)
- {
- retval.defaultcolwidth = ( DefaultColWidthRecord ) rec;
- }
- else if (rec.getSid() == DefaultRowHeightRecord.sid)
- {
- retval.defaultrowheight = ( DefaultRowHeightRecord ) rec;
- }
else if ( rec.isValue() && bofEofNestingLevel == 1 )
{
if ( isfirstcell )
@@ -230,22 +304,13 @@ public final class Sheet implements Model {
rec = null;
}
}
- else if ( rec.getSid() == StringRecord.sid )
+ else if (rec.getSid() == DefaultColWidthRecord.sid)
{
- rec = null;
+ retval.defaultcolwidth = ( DefaultColWidthRecord ) rec;
}
- else if ( rec.getSid() == RowRecord.sid )
+ else if (rec.getSid() == DefaultRowHeightRecord.sid)
{
- RowRecord row = (RowRecord)rec;
- if (!isfirstrow) rec = null; //only add the aggregate once
-
- if ( isfirstrow )
- {
- retval.rows = new RowRecordsAggregate();
- rec = retval.rows;
- isfirstrow = false;
- }
- retval.rows.insertRow(row);
+ retval.defaultrowheight = ( DefaultRowHeightRecord ) rec;
}
else if ( rec.getSid() == PrintGridlinesRecord.sid )
{
@@ -291,22 +356,6 @@ public final class Sheet implements Model {
{
retval.windowTwo = (WindowTwoRecord) rec;
}
- else if ( rec.getSid() == DBCellRecord.sid )
- {
- rec = null;
- }
- else if ( rec.getSid() == IndexRecord.sid )
- {
- // ignore INDEX record because it is only needed by Excel,
- // and POI always re-calculates its contents
- rec = null;
- }
- else if ( rec.getSid() == DVALRecord.sid) {
- RecordStream rs = new RecordStream(recs, k);
- retval._dataValidityTable = new DataValidityTable(rs);
- k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
- rec = retval._dataValidityTable;
- }
else if ( rec.getSid() == ProtectRecord.sid )
{
retval.protect = (ProtectRecord) rec;
@@ -323,13 +372,13 @@ public final class Sheet implements Model {
{
retval.password = (PasswordRecord) rec;
}
- else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID)
+ else if (rec.getSid() == HorizontalPageBreakRecord.sid)
{
- retval.rowBreaks = (PageBreakRecord)rec;
+ retval._rowBreaksRecord = (HorizontalPageBreakRecord)rec;
}
- else if (rec.getSid() == PageBreakRecord.VERTICAL_SID)
+ else if (rec.getSid() == VerticalPageBreakRecord.sid)
{
- retval.colBreaks = (PageBreakRecord)rec;
+ retval._columnBreaksRecord = (VerticalPageBreakRecord)rec;
}
if (rec != null)
@@ -337,6 +386,9 @@ public final class Sheet implements Model {
records.add(rec);
}
}
+ if (retval.dimsloc < 0) {
+ throw new RuntimeException("DimensionsRecord was not found");
+ }
retval.records = records;
retval.checkRows();
retval.checkCells();
@@ -345,6 +397,17 @@ public final class Sheet implements Model {
return retval;
}
+ private static final class RecordCloner implements RecordVisitor {
+
+ private final List _destList;
+
+ public RecordCloner(List destList) {
+ _destList = destList;
+ }
+ public void visitRecord(Record r) {
+ _destList.add(r.clone());
+ }
+ }
/**
* Clones the low level records of this sheet and returns the new sheet instance.
* This method is implemented by adding methods for deep cloning to all records that
@@ -356,7 +419,13 @@ public final class Sheet implements Model {
{
ArrayList clonedRecords = new ArrayList(this.records.size());
for (int i=0; i= numMergedRegions || mergedRecords.size() == 0)
- return;
-
- int pos = 0;
- int startNumRegions = 0;
-
- //optimisation for current record
- if (numMergedRegions - index < merged.getNumAreas())
- {
- pos = mergedRecords.size() - 1;
- startNumRegions = numMergedRegions - merged.getNumAreas();
- }
- else
- {
- for (int n = 0; n < mergedRecords.size(); n++)
- {
- MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n);
- if (startNumRegions + record.getNumAreas() > index)
- {
- pos = n;
- break;
- }
- startNumRegions += record.getNumAreas();
- }
- }
-
- MergeCellsRecord rec = (MergeCellsRecord) mergedRecords.get(pos);
- rec.removeAreaAt(index - startNumRegions);
- numMergedRegions--;
- if (rec.getNumAreas() == 0)
- {
- mergedRecords.remove(pos);
- //get rid of the record from the sheet
- records.remove(merged);
- if (merged == rec) {
- //pull up the LAST record for operations when we finally
- //support continue records for mergedRegions
- if (mergedRecords.size() > 0) {
- merged = (MergeCellsRecord) mergedRecords.get(mergedRecords.size() - 1);
- } else {
- merged = null;
- }
- }
- }
+ MergedCellsTable mrt = getMergedRecords();
+ if (index >= mrt.getNumberOfMergedRegions()) {
+ return;
+ }
+ mrt.remove(index);
}
- public CellRangeAddress getMergedRegionAt(int index)
- {
+ public CellRangeAddress getMergedRegionAt(int index) {
//safety checks
- if (index >= numMergedRegions || mergedRecords.size() == 0)
- return null;
-
- int pos = 0;
- int startNumRegions = 0;
-
- //optimisation for current record
- if (numMergedRegions - index < merged.getNumAreas())
- {
- pos = mergedRecords.size() - 1;
- startNumRegions = numMergedRegions - merged.getNumAreas();
- }
- else
- {
- for (int n = 0; n < mergedRecords.size(); n++)
- {
- MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n);
- if (startNumRegions + record.getNumAreas() > index)
- {
- pos = n;
- break;
- }
- startNumRegions += record.getNumAreas();
- }
- }
- return ((MergeCellsRecord) mergedRecords.get(pos)).getAreaAt(index - startNumRegions);
+ MergedCellsTable mrt = getMergedRecords();
+ if (index >= mrt.getNumberOfMergedRegions()) {
+ return null;
+ }
+ return mrt.get(index);
}
- public int getNumMergedRegions()
- {
- return numMergedRegions;
+ public int getNumMergedRegions() {
+ return getMergedRecords().getNumberOfMergedRegions();
}
- // Find correct position to add new CF record
- private int findConditionalFormattingPosition()
- {
- // This is default.
- // If the algorithm does not find the right position,
- // this one will be used (this is a position before EOF record)
- int index = records.size()-2;
-
- for( int i=index; i>=0; i-- )
- {
- Record rec = (Record)records.get(i);
- short sid = rec.getSid();
-
- // CFRecordsAggregate records already exist, just add to the end
- if (rec instanceof CFRecordsAggregate) { return i+1; }
-
- if( sid == (short)0x00ef ) { return i+1; }// PHONETICPR
- if( sid == (short)0x015f ) { return i+1; }// LABELRANGES
- if( sid == MergeCellsRecord.sid ) { return i+1; }
- if( sid == (short)0x0099 ) { return i+1; }// STANDARDWIDTH
- if( sid == SelectionRecord.sid ) { return i+1; }
- if( sid == PaneRecord.sid ) { return i+1; }
- if( sid == SCLRecord.sid ) { return i+1; }
- if( sid == WindowTwoRecord.sid ) { return i+1; }
- }
-
- return index;
+ private ConditionalFormattingTable getConditionalFormattingTable() {
+ if (condFormatting == null) {
+ condFormatting = new ConditionalFormattingTable();
+ RecordOrderer.addNewSheetRecord(records, condFormatting);
+ }
+ return condFormatting;
}
- public int addConditionalFormatting(CFRecordsAggregate cfAggregate)
- {
- int index = findConditionalFormattingPosition();
- records.add(index, cfAggregate);
- condFormatting.add(cfAggregate);
- return condFormatting.size()-1;
+
+ public int addConditionalFormatting(CFRecordsAggregate cfAggregate) {
+ ConditionalFormattingTable cft = getConditionalFormattingTable();
+ return cft.add(cfAggregate);
}
- public void removeConditionalFormatting(int index)
- {
- if (index >= 0 && index <= condFormatting.size()-1 )
- {
- CFRecordsAggregate cfAggregate = getCFRecordsAggregateAt(index);
- records.remove(cfAggregate);
- condFormatting.remove(index);
- }
+ public void removeConditionalFormatting(int index) {
+ getConditionalFormattingTable().remove(index);
}
- public CFRecordsAggregate getCFRecordsAggregateAt(int index)
- {
- if (index >= 0 && index <= condFormatting.size()-1 )
- {
- return (CFRecordsAggregate) condFormatting.get(index);
- }
- return null;
+ public CFRecordsAggregate getCFRecordsAggregateAt(int index) {
+ return getConditionalFormattingTable().get(index);
}
- public int getNumConditionalFormattings()
- {
- return condFormatting.size();
+ public int getNumConditionalFormattings() {
+ return getConditionalFormattingTable().size();
}
/**
@@ -699,13 +675,13 @@ public final class Sheet implements Model {
log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[]
{
records.size(), cells.getPhysicalNumberOfCells(),
- rows.getPhysicalNumberOfRows(),
+ _rowsAggregate.getPhysicalNumberOfRows(),
records.size() + cells.getPhysicalNumberOfCells()
- + rows.getPhysicalNumberOfRows() - 2
+ + _rowsAggregate.getPhysicalNumberOfRows() - 2
});
}
return records.size() + cells.getPhysicalNumberOfCells()
- + rows.getPhysicalNumberOfRows() - 2;
+ + _rowsAggregate.getPhysicalNumberOfRows() - 2;
}
/**
@@ -814,7 +790,7 @@ public final class Sheet implements Model {
for (int k = 0; k < records.size(); k++)
{
- Record record = (( Record ) records.get(k));
+ RecordBase record = (RecordBase) records.get(k);
// Don't write out UncalcedRecord entries, as
// we handle those specially just below
@@ -833,7 +809,7 @@ public final class Sheet implements Model {
}
// If the BOF record was just serialized then add the IndexRecord
- if (record.getSid() == BOFRecord.sid) {
+ if (record instanceof BOFRecord) {
if (!haveSerializedIndex) {
haveSerializedIndex = true;
// Add an optional UncalcedRecord. However, we should add
@@ -846,7 +822,7 @@ public final class Sheet implements Model {
}
//Can there be more than one BOF for a sheet? If not then we can
//remove this guard. So be safe it is left here.
- if (rows != null) {
+ if (_rowsAggregate != null) {
pos += serializeIndexRecord(k, pos, data);
}
}
@@ -865,8 +841,8 @@ public final class Sheet implements Model {
private int serializeIndexRecord(final int bofRecordIndex, final int indexRecordOffset,
byte[] data) {
IndexRecord index = new IndexRecord();
- index.setFirstRow(rows.getFirstRowNum());
- index.setLastRowAdd1(rows.getLastRowNum() + 1);
+ index.setFirstRow(_rowsAggregate.getFirstRowNum());
+ index.setLastRowAdd1(_rowsAggregate.getLastRowNum() + 1);
// Calculate the size of the records from the end of the BOF
// and up to the RowRecordsAggregate...
@@ -874,7 +850,7 @@ public final class Sheet implements Model {
int sizeOfInitialSheetRecords = 0;
// start just after BOF record (INDEX is not present in this list)
for (int j = bofRecordIndex + 1; j < records.size(); j++) {
- Record tmpRec = ((Record) records.get(j));
+ RecordBase tmpRec = ((RecordBase) records.get(j));
if (tmpRec instanceof UncalcedRecord) {
continue;
}
@@ -891,7 +867,7 @@ public final class Sheet implements Model {
// Note: The offsets are relative to the Workbook BOF. Assume that this is
// 0 for now.....
- int blockCount = rows.getRowBlockCount();
+ int blockCount = _rowsAggregate.getRowBlockCount();
// Calculate the size of this IndexRecord
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
@@ -902,15 +878,15 @@ public final class Sheet implements Model {
// The offset of each DBCELL record needs to be updated in the INDEX record
// account for row records in this row-block
- currentOffset += rows.getRowBlockSize(block);
+ currentOffset += _rowsAggregate.getRowBlockSize(block);
// account for cell value records after those
- currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(rows
- .getStartRowNumberForBlock(block), rows.getEndRowNumberForBlock(block));
+ currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(_rowsAggregate
+ .getStartRowNumberForBlock(block), _rowsAggregate.getEndRowNumberForBlock(block));
// currentOffset is now the location of the DBCELL record for this row-block
index.addDbcell(currentOffset);
// Add space required to write the DBCELL record (whose reference was just added).
- currentOffset += (8 + (rows.getRowCountForBlock(block) * 2));
+ currentOffset += (8 + (_rowsAggregate.getRowCountForBlock(block) * 2));
}
return index.serialize(indexRecordOffset, data);
}
@@ -1031,11 +1007,11 @@ public final class Sheet implements Model {
}
//IndexRecord index = null;
//If the row exists remove it, so that any cells attached to the row are removed
- RowRecord existingRow = rows.getRow(row.getRowNumber());
+ RowRecord existingRow = _rowsAggregate.getRow(row.getRowNumber());
if (existingRow != null)
- rows.removeRow(existingRow);
+ _rowsAggregate.removeRow(existingRow);
- rows.insertRow(row);
+ _rowsAggregate.insertRow(row);
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "exit addRow");
@@ -1054,7 +1030,7 @@ public final class Sheet implements Model {
checkRows();
setLoc(getDimsLoc());
- rows.removeRow(row);
+ _rowsAggregate.removeRow(row);
}
/**
@@ -1108,7 +1084,7 @@ public final class Sheet implements Model {
log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
if (rowRecIterator == null)
{
- rowRecIterator = rows.getIterator();
+ rowRecIterator = _rowsAggregate.getIterator();
}
if (!rowRecIterator.hasNext())
{
@@ -1136,7 +1112,7 @@ public final class Sheet implements Model {
public RowRecord getRow(int rownum) {
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
- return rows.getRow(rownum);
+ return _rowsAggregate.getRow(rownum);
}
/**
@@ -1258,6 +1234,15 @@ public final class Sheet implements Model {
retval.setColLevelMax(( short ) 0);
return retval;
}
+ private GutsRecord getGutsRecord() {
+ if (_gutsRecord == null) {
+ GutsRecord result = createGuts();
+ RecordOrderer.addNewSheetRecord(records, result);
+ _gutsRecord = result;
+ }
+
+ return _gutsRecord;
+ }
/**
* creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff
@@ -1422,43 +1407,22 @@ public final class Sheet implements Model {
/**
* get the width of a given column in units of 1/256th of a character width
- * @param column index
+ * @param columnIndex index
* @see org.apache.poi.hssf.record.DefaultColWidthRecord
* @see org.apache.poi.hssf.record.ColumnInfoRecord
* @see #setColumnWidth(short,short)
* @return column width in units of 1/256th of a character width
*/
- public short getColumnWidth(short column)
- {
- short retval = 0;
- ColumnInfoRecord ci = null;
+ public short getColumnWidth(short columnIndex) {
- if (columns != null)
- {
- int count=columns.getNumColumns();
- for ( int k=0;k= start);
boolean inEnd = (breakLocation <= stop);
if(inStart && inEnd)
@@ -2361,17 +2275,31 @@ public final class Sheet implements Model {
}
}
+ private PageBreakRecord getRowBreaksRecord() {
+ if (_rowBreaksRecord == null) {
+ _rowBreaksRecord = new HorizontalPageBreakRecord();
+ RecordOrderer.addNewSheetRecord(records, _rowBreaksRecord);
+ dimsloc++;
+ }
+ return _rowBreaksRecord;
+ }
+
+ private PageBreakRecord getColumnBreaksRecord() {
+ if (_columnBreaksRecord == null) {
+ _columnBreaksRecord = new VerticalPageBreakRecord();
+ RecordOrderer.addNewSheetRecord(records, _columnBreaksRecord);
+ dimsloc++;
+ }
+ return _columnBreaksRecord;
+ }
+
+
/**
* Sets a page break at the indicated row
* @param row
*/
public void setRowBreak(int row, short fromCol, short toCol) {
- if (rowBreaks == null) {
- int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
- rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
- records.add(loc, rowBreaks);
- }
- rowBreaks.addBreak((short)row, fromCol, toCol);
+ getRowBreaksRecord().addBreak((short)row, fromCol, toCol);
}
/**
@@ -2379,9 +2307,9 @@ public final class Sheet implements Model {
* @param row
*/
public void removeRowBreak(int row) {
- if (rowBreaks == null)
+ if (getRowBreaks() == null)
throw new IllegalArgumentException("Sheet does not define any row breaks");
- rowBreaks.removeBreak((short)row);
+ getRowBreaksRecord().removeBreak((short)row);
}
/**
@@ -2390,7 +2318,7 @@ public final class Sheet implements Model {
* @return true if the specified row has a page break
*/
public boolean isRowBroken(int row) {
- return (rowBreaks == null) ? false : rowBreaks.getBreak((short)row) != null;
+ return getRowBreaksRecord().getBreak(row) != null;
}
/**
@@ -2398,12 +2326,7 @@ public final class Sheet implements Model {
*
*/
public void setColumnBreak(short column, short fromRow, short toRow) {
- if (colBreaks == null) {
- int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
- colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
- records.add(loc, colBreaks);
- }
- colBreaks.addBreak(column, fromRow, toRow);
+ getColumnBreaksRecord().addBreak(column, fromRow, toRow);
}
/**
@@ -2411,19 +2334,16 @@ public final class Sheet implements Model {
*
*/
public void removeColumnBreak(short column) {
- if (colBreaks == null)
- throw new IllegalArgumentException("Sheet does not define any column breaks");
-
- colBreaks.removeBreak(column);
+ getColumnBreaksRecord().removeBreak(column);
}
/**
* Queries if the specified column has a page break
*
- * @return true if the specified column has a page break
+ * @return true
if the specified column has a page break
*/
public boolean isColumnBroken(short column) {
- return (colBreaks == null) ? false : colBreaks.getBreak(column) != null;
+ return getColumnBreaksRecord().getBreak(column) != null;
}
/**
@@ -2433,7 +2353,7 @@ public final class Sheet implements Model {
* @param count
*/
public void shiftRowBreaks(int startingRow, int endingRow, int count) {
- shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count);
+ shiftBreaks(getRowBreaksRecord(), startingRow, endingRow, count);
}
/**
@@ -2443,50 +2363,46 @@ public final class Sheet implements Model {
* @param count
*/
public void shiftColumnBreaks(short startingCol, short endingCol, short count) {
- shiftBreaks(colBreaks, startingCol, endingCol, count);
+ shiftBreaks(getColumnBreaksRecord(), startingCol, endingCol, count);
}
/**
- * Returns all the row page breaks
- * @return all the row page breaks
+ * @return all the horizontal page breaks, never null
*/
- public Iterator getRowBreaks() {
- return rowBreaks.getBreaksIterator();
+ public int[] getRowBreaks() {
+ return getRowBreaksRecord().getBreaks();
}
/**
- * Returns the number of row page breaks
* @return the number of row page breaks
*/
public int getNumRowBreaks(){
- return (rowBreaks == null) ? 0 : (int)rowBreaks.getNumBreaks();
+ return getRowBreaksRecord().getNumBreaks();
}
/**
- * Returns all the column page breaks
- * @return all the column page breaks
+ * @return all the column page breaks, never null
*/
- public Iterator getColumnBreaks(){
- return colBreaks.getBreaksIterator();
+ public int[] getColumnBreaks(){
+ return getColumnBreaksRecord().getBreaks();
}
/**
- * Returns the number of column page breaks
* @return the number of column page breaks
*/
public int getNumColumnBreaks(){
- return (colBreaks == null) ? 0 : (int)colBreaks.getNumBreaks();
+ return getColumnBreaksRecord().getNumBreaks();
}
public void setColumnGroupCollapsed( short columnNumber, boolean collapsed )
{
if (collapsed)
{
- columns.collapseColumn( columnNumber );
+ _columnInfos.collapseColumn( columnNumber );
}
else
{
- columns.expandColumn( columnNumber );
+ _columnInfos.expandColumn( columnNumber );
}
}
@@ -2577,7 +2493,7 @@ public final class Sheet implements Model {
private void recalcRowGutter()
{
int maxLevel = 0;
- Iterator iterator = rows.getIterator();
+ Iterator iterator = _rowsAggregate.getIterator();
while ( iterator.hasNext() )
{
RowRecord rowRecord = (RowRecord) iterator.next();
@@ -2585,11 +2501,7 @@ public final class Sheet implements Model {
}
// Grab the guts record, adding if needed
- GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
- if(guts == null) {
- guts = new GutsRecord();
- records.add(guts);
- }
+ GutsRecord guts = getGutsRecord();
// Set the levels onto it
guts.setRowLevelMax( (short) ( maxLevel + 1 ) );
guts.setLeftRowGutter( (short) ( 29 + (12 * (maxLevel)) ) );
@@ -2599,16 +2511,18 @@ public final class Sheet implements Model {
{
if (collapse)
{
- rows.collapseRow( row );
+ _rowsAggregate.collapseRow( row );
}
else
{
- rows.expandRow( row );
+ _rowsAggregate.expandRow( row );
}
}
public DataValidityTable getOrCreateDataValidityTable() {
if (_dataValidityTable == null) {
- _dataValidityTable = DataValidityTable.createForSheet(records);
+ DataValidityTable result = new DataValidityTable();
+ RecordOrderer.addNewSheetRecord(records, result);
+ _dataValidityTable = result;
}
return _dataValidityTable;
}
diff --git a/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java b/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java
index 05b642a44..a6846300c 100644
--- a/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java
+++ b/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java
@@ -1,60 +1,67 @@
-
/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ==================================================================== */
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
package org.apache.poi.hssf.record;
-/**
- * HorizontalPageBreak record that stores page breaks at rows
- *
- * This class is just used so that SID compares work properly in the RecordFactory
- * @see PageBreakRecord
- * @author Danny Mui (dmui at apache dot org)
- */
-public class HorizontalPageBreakRecord extends PageBreakRecord {
+import java.util.Iterator;
+
+/**
+ * HorizontalPageBreak (0x001B) record that stores page breaks at rows
+ *
+ * @see PageBreakRecord
+ * @author Danny Mui (dmui at apache dot org)
+ */
+public final class HorizontalPageBreakRecord extends PageBreakRecord {
+
+ public static final short sid = 0x001B;
- public static final short sid = PageBreakRecord.HORIZONTAL_SID;
-
/**
- *
+ * Creates an empty horizontal page break record
*/
public HorizontalPageBreakRecord() {
- super();
+ //
}
/**
- * @param sid
- */
- public HorizontalPageBreakRecord(short sid) {
- super(sid);
- }
-
- /**
- * @param in the RecordInputstream to read the record from
+ * @param in
+ * the RecordInputstream to read the record from
*/
public HorizontalPageBreakRecord(RecordInputStream in) {
super(in);
}
- /* (non-Javadoc)
- * @see org.apache.poi.hssf.record.Record#getSid()
- */
+ protected void validateSid(short id) {
+ if (id != getSid()) {
+ throw new RecordFormatException(
+ "NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id);
+ }
+ }
+
public short getSid() {
return sid;
}
+ public Object clone() {
+ PageBreakRecord result = new HorizontalPageBreakRecord();
+ Iterator iterator = getBreaksIterator();
+ while (iterator.hasNext()) {
+ Break original = (Break) iterator.next();
+ result.addBreak(original.main, original.subFrom, original.subTo);
+ }
+ return result;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java
index bf41d2fc9..27ebbd118 100644
--- a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java
+++ b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java
@@ -32,68 +32,51 @@ import org.apache.poi.util.LittleEndian;
*/
public final class MergeCellsRecord extends Record {
public final static short sid = 0x00E5;
- private CellRangeAddressList _regions;
+ /** sometimes the regions array is shared with other MergedCellsRecords */
+ private CellRangeAddress[] _regions;
+ private final int _startIndex;
+ private final int _numberOfRegions;
- /**
- * Creates an empty MergedCellsRecord
- */
- public MergeCellsRecord() {
- _regions = new CellRangeAddressList();
+ public MergeCellsRecord(CellRangeAddress[] regions, int startIndex, int numberOfRegions) {
+ _regions = regions;
+ _startIndex = startIndex;
+ _numberOfRegions = numberOfRegions;
}
-
/**
* Constructs a MergedCellsRecord and sets its fields appropriately
* @param in the RecordInputstream to read the record from
*/
public MergeCellsRecord(RecordInputStream in) {
- super(in);
+ int nRegions = in.readUShort();
+ CellRangeAddress[] cras = new CellRangeAddress[nRegions];
+ for (int i = 0; i < nRegions; i++) {
+ cras[i] = new CellRangeAddress(in);
+ }
+ _numberOfRegions = nRegions;
+ _startIndex = 0;
+ _regions = cras;
}
-
protected void fillFields(RecordInputStream in) {
- _regions = new CellRangeAddressList(in);
+ throw new RuntimeException("obsolete");
}
-
/**
* get the number of merged areas. If this drops down to 0 you should just go
* ahead and delete the record.
* @return number of areas
*/
public short getNumAreas() {
- return (short)_regions.countRanges();
- }
-
- /**
- * Add an area to consider a merged cell. The index returned is only gauranteed to
- * be correct provided you do not add ahead of or remove ahead of it (in which case
- * you should increment or decrement appropriately....in other words its an arrayList)
- *
- * @param firstRow - the upper left hand corner's row
- * @param firstCol - the upper left hand corner's col
- * @param lastRow - the lower right hand corner's row
- * @param lastCol - the lower right hand corner's col
- * @return new index of said area (don't depend on it if you add/remove)
- */
- public void addArea(int firstRow, int firstCol, int lastRow, int lastCol) {
- _regions.addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
- }
-
- /**
- * essentially unmerge the cells in the "area" stored at the passed in index
- * @param areaIndex
- */
- public void removeAreaAt(int areaIndex) {
- _regions.remove(areaIndex);
+ return (short)_numberOfRegions;
}
/**
* @return MergedRegion at the given index representing the area that is Merged (r1,c1 - r2,c2)
*/
public CellRangeAddress getAreaAt(int index) {
- return _regions.getCellRangeAddress(index);
+ return _regions[_startIndex + index];
}
public int getRecordSize() {
- return 4 + _regions.getSize();
+ return 4 + CellRangeAddressList.getEncodedSize(_numberOfRegions);
}
public short getSid() {
@@ -101,11 +84,16 @@ public final class MergeCellsRecord extends Record {
}
public int serialize(int offset, byte [] data) {
- int dataSize = _regions.getSize();
+ int dataSize = CellRangeAddressList.getEncodedSize(_numberOfRegions);
- LittleEndian.putShort(data, offset + 0, sid);
+ LittleEndian.putUShort(data, offset + 0, sid);
LittleEndian.putUShort(data, offset + 2, dataSize);
- _regions.serialize(offset + 4, data);
+ int nItems = _numberOfRegions;
+ LittleEndian.putUShort(data, offset + 4, nItems);
+ int pos = 6;
+ for (int i = 0; i < _numberOfRegions; i++) {
+ pos += _regions[_startIndex + i].serialize(offset+pos, data);
+ }
return 4 + dataSize;
}
@@ -113,17 +101,16 @@ public final class MergeCellsRecord extends Record {
StringBuffer retval = new StringBuffer();
retval.append("[MERGEDCELLS]").append("\n");
- retval.append(" .sid =").append(sid).append("\n");
retval.append(" .numregions =").append(getNumAreas())
.append("\n");
- for (int k = 0; k < _regions.countRanges(); k++) {
- CellRangeAddress region = _regions.getCellRangeAddress(k);
+ for (int k = 0; k < _numberOfRegions; k++) {
+ CellRangeAddress region = _regions[_startIndex + k];
retval.append(" .rowfrom =").append(region.getFirstRow())
.append("\n");
- retval.append(" .colfrom =").append(region.getFirstColumn())
- .append("\n");
retval.append(" .rowto =").append(region.getLastRow())
+ .append("\n");
+ retval.append(" .colfrom =").append(region.getFirstColumn())
.append("\n");
retval.append(" .colto =").append(region.getLastColumn())
.append("\n");
@@ -140,13 +127,11 @@ public final class MergeCellsRecord extends Record {
}
public Object clone() {
- MergeCellsRecord rec = new MergeCellsRecord();
- for (int k = 0; k < _regions.countRanges(); k++) {
- CellRangeAddress oldRegion = _regions.getCellRangeAddress(k);
- rec.addArea(oldRegion.getFirstRow(), oldRegion.getFirstColumn(),
- oldRegion.getLastRow(), oldRegion.getLastColumn());
- }
-
- return rec;
+ int nRegions = _numberOfRegions;
+ CellRangeAddress[] clonedRegions = new CellRangeAddress[nRegions];
+ for (int i = 0; i < clonedRegions.length; i++) {
+ clonedRegions[i] = _regions[_startIndex + i].copy();
+ }
+ return new MergeCellsRecord(clonedRegions, 0, nRegions);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java
index 83eade95d..c86f460b1 100644
--- a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java
+++ b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,11 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.hssf.record;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -38,13 +36,12 @@ import org.apache.poi.util.LittleEndian;
* @see VerticalPageBreakRecord
* @author Danny Mui (dmui at apache dot org)
*/
-public class PageBreakRecord extends Record {
- public static final short HORIZONTAL_SID = (short)0x1B;
- public static final short VERTICAL_SID = (short)0x1A;
- public short sid;
- private short numBreaks;
- private List breaks;
- private Map BreakMap;
+public abstract class PageBreakRecord extends Record {
+ private static final boolean IS_EMPTY_RECORD_WRITTEN = false; //TODO - flip
+ private static final int[] EMPTY_INT_ARRAY = { };
+
+ private List _breaks;
+ private Map _breakMap;
/**
* Since both records store 2byte integers (short), no point in
@@ -53,116 +50,105 @@ public class PageBreakRecord extends Record {
* The subs (rows or columns, don't seem to be able to set but excel sets
* them automatically)
*/
- public class Break
- {
+ public class Break {
- public short main;
- public short subFrom;
- public short subTo;
+ public static final int ENCODED_SIZE = 6;
+ public int main;
+ public int subFrom;
+ public int subTo;
- public Break(short main, short subFrom, short subTo)
+ public Break(int main, int subFrom, int subTo)
{
this.main = main;
this.subFrom = subFrom;
this.subTo = subTo;
}
+
+ public Break(RecordInputStream in) {
+ main = in.readUShort() - 1;
+ subFrom = in.readUShort();
+ subTo = in.readUShort();
+ }
+
+ public int serialize(int offset, byte[] data) {
+ LittleEndian.putUShort(data, offset + 0, main + 1);
+ LittleEndian.putUShort(data, offset + 2, subFrom);
+ LittleEndian.putUShort(data, offset + 4, subTo);
+ return ENCODED_SIZE;
+ }
}
- public PageBreakRecord()
- {
-
+ protected PageBreakRecord() {
+ _breaks = new ArrayList();
+ _breakMap = new HashMap();
}
- /**
- *
- * @param sid
- */
- public PageBreakRecord(short sid) {
- super();
- this.sid = sid;
- }
-
- public PageBreakRecord(RecordInputStream in)
- {
+ protected PageBreakRecord(RecordInputStream in) {
super(in);
- this.sid = in.getSid();
}
protected void fillFields(RecordInputStream in)
{
- short loadedBreaks = in.readShort();
- setNumBreaks(loadedBreaks);
- for(int k = 0; k < loadedBreaks; k++)
- {
- addBreak((short)(in.readShort()-1), in.readShort(), in.readShort());
+ int nBreaks = in.readShort();
+ _breaks = new ArrayList(nBreaks + 2);
+ _breakMap = new HashMap();
+
+ for(int k = 0; k < nBreaks; k++) {
+ Break br = new Break(in);
+ _breaks.add(br);
+ _breakMap.put(new Integer(br.main), br);
}
}
-
- public short getSid()
- {
- return sid;
+
+ private int getDataSize() {
+ return 2 + _breaks.size() * Break.ENCODED_SIZE;
+ }
+ public int getRecordSize() {
+ int nBreaks = _breaks.size();
+ if (!IS_EMPTY_RECORD_WRITTEN && nBreaks < 1) {
+ return 0;
+ }
+ return 4 + getDataSize();
}
- public int serialize(int offset, byte data[])
- {
- int recordsize = getRecordSize();
+
+ public final int serialize(int offset, byte data[]) {
+ int nBreaks = _breaks.size();
+ if (!IS_EMPTY_RECORD_WRITTEN && nBreaks < 1) {
+ return 0;
+ }
+ int dataSize = getDataSize();
+ LittleEndian.putUShort(data, offset + 0, getSid());
+ LittleEndian.putUShort(data, offset + 2, dataSize);
+ LittleEndian.putUShort(data, offset + 4, nBreaks);
int pos = 6;
- LittleEndian.putShort(data, offset + 0, getSid());
- LittleEndian.putShort(data, offset + 2, (short)(recordsize - 4));
- LittleEndian.putShort(data, offset + 4, getNumBreaks());
- for(Iterator iterator = getBreaksIterator(); iterator.hasNext();)
- {
- Break Break = (Break)iterator.next();
- LittleEndian.putShort(data, offset + pos, (short)(Break.main + 1));
- pos += 2;
- LittleEndian.putShort(data, offset + pos, Break.subFrom);
- pos += 2;
- LittleEndian.putShort(data, offset + pos, Break.subTo);
- pos += 2;
+ for (int i=0; i
- * This class is just used so that SID compares work properly in the RecordFactory
+ * VerticalPageBreak (0x001A) record that stores page breaks at columns
+ *
* @see PageBreakRecord
- * @author Danny Mui (dmui at apache dot org)
+ * @author Danny Mui (dmui at apache dot org)
*/
-public class VerticalPageBreakRecord extends PageBreakRecord {
-
- public static final short sid = PageBreakRecord.VERTICAL_SID;
-
+public final class VerticalPageBreakRecord extends PageBreakRecord {
+
+ public static final short sid = 0x001A;
+
/**
- *
+ * Creates an empty vertical page break record
*/
public VerticalPageBreakRecord() {
- super();
+
}
/**
- * @param sid
- */
- public VerticalPageBreakRecord(short sid) {
- super(sid);
- }
-
- /**
- * @param in the RecordInputstream to read the record from
+ * @param in the RecordInputstream to read the record from
*/
public VerticalPageBreakRecord(RecordInputStream in) {
super(in);
}
- /* (non-Javadoc)
- * @see org.apache.poi.hssf.record.Record#getSid()
- */
+ protected void validateSid(short id) {
+ if (id != getSid()) {
+ throw new RecordFormatException(
+ "NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id);
+ }
+ }
+
public short getSid() {
return sid;
}
+ public Object clone() {
+ PageBreakRecord result = new VerticalPageBreakRecord();
+ Iterator iterator = getBreaksIterator();
+ while (iterator.hasNext()) {
+ Break original = (Break) iterator.next();
+ result.addBreak(original.main, original.subFrom, original.subTo);
+ }
+ return result;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
index 71754db96..eb117eae4 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
@@ -14,19 +14,19 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeaderRecord;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.CellRangeAddress;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
/**
* CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord
@@ -36,15 +36,12 @@ import org.apache.poi.util.POILogger;
* @author Dmitriy Kumshayev
*
*/
-public final class CFRecordsAggregate extends Record
-{
+public final class CFRecordsAggregate extends Record {
/** Excel allows up to 3 conditional formating rules */
private static final int MAX_CONDTIONAL_FORMAT_RULES = 3;
public final static short sid = -2008; // not a real BIFF record
- private static POILogger log = POILogFactory.getLogger(CFRecordsAggregate.class);
-
private final CFHeaderRecord header;
/** List of CFRuleRecord objects */
@@ -78,9 +75,8 @@ public final class CFRecordsAggregate extends Record
* @param offset - position of {@link CFHeaderRecord} object in the list of Record objects
* @return CFRecordsAggregate object
*/
- public static CFRecordsAggregate createCFAggregate(List recs, int pOffset)
- {
- Record rec = ( Record ) recs.get(pOffset);
+ public static CFRecordsAggregate createCFAggregate(RecordStream rs) {
+ Record rec = rs.getNext();
if (rec.getSid() != CFHeaderRecord.sid) {
throw new IllegalStateException("next record sid was " + rec.getSid()
+ " instead of " + CFHeaderRecord.sid + " as expected");
@@ -90,35 +86,10 @@ public final class CFRecordsAggregate extends Record
int nRules = header.getNumberOfConditionalFormats();
CFRuleRecord[] rules = new CFRuleRecord[nRules];
- int offset = pOffset;
- int countFound = 0;
- while (countFound < rules.length) {
- offset++;
- if(offset>=recs.size()) {
- break;
- }
- rec = (Record)recs.get(offset);
- if(rec instanceof CFRuleRecord) {
- rules[countFound] = (CFRuleRecord) rec;
- countFound++;
- } else {
- break;
- }
- }
-
- if (countFound < nRules)
- { // TODO -(MAR-2008) can this ever happen? write junit
-
- if (log.check(POILogger.DEBUG))
- {
- log.log(POILogger.DEBUG, "Expected " + nRules + " Conditional Formats, "
- + "but found " + countFound + " rules");
- }
- header.setNumberOfConditionalFormats(nRules);
- CFRuleRecord[] lessRules = new CFRuleRecord[countFound];
- System.arraycopy(rules, 0, lessRules, 0, countFound);
- rules = lessRules;
+ for (int i = 0; i < rules.length; i++) {
+ rules[i] = (CFRuleRecord) rs.getNext();
}
+
return new CFRecordsAggregate(header, rules);
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
index 6df796c2a..b24d8c5b4 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
@@ -1,72 +1,52 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.hssf.record.aggregates;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.ColumnInfoRecord;
import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.RecordInputStream;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
/**
* @author Glen Stampoultzis
* @version $Id$
*/
-public class ColumnInfoRecordsAggregate
- extends Record
-{
-// int size = 0;
- List records = null;
+public final class ColumnInfoRecordsAggregate extends RecordAggregate {
+ private final List records;
- public ColumnInfoRecordsAggregate()
- {
- records = new ArrayList();
- }
-
- /** You never fill an aggregate */
- protected void fillFields(RecordInputStream in)
- {
- }
-
- /** Not required by an aggregate */
- protected void validateSid(short id)
- {
- }
-
- /** It's an aggregate... just made something up */
- public short getSid()
- {
- return -1012;
- }
-
- public int getRecordSize()
- {
- int size = 0;
- for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
- size += ( (ColumnInfoRecord) iterator.next() ).getRecordSize();
- return size;
- }
-
- public Iterator getIterator()
- {
- return records.iterator();
- }
+ /**
+ * Creates an empty aggregate
+ */
+ public ColumnInfoRecordsAggregate() {
+ records = new ArrayList();
+ }
+ public ColumnInfoRecordsAggregate(RecordStream rs) {
+ this();
+
+ while(rs.peekNextClass() == ColumnInfoRecord.class) {
+ records.add(rs.getNext());
+ }
+ if (records.size() < 1) {
+ throw new RuntimeException("No column info records found");
+ }
+ }
/**
* Performs a deep clone of the record
@@ -105,25 +85,14 @@ public class ColumnInfoRecordsAggregate
return records.size();
}
- /**
- * called by the class that is responsible for writing this sucker.
- * Subclasses should implement this so that their data is passed back in a
- * byte array.
- *
- * @param offset offset to begin writing at
- * @param data byte array containing instance data
- * @return number of bytes written
- */
- public int serialize(int offset, byte [] data)
- {
- Iterator itr = records.iterator();
- int pos = offset;
-
- while (itr.hasNext())
- {
- pos += (( Record ) itr.next()).serialize(pos, data);
- }
- return pos - offset;
+ public void visitContainedRecords(RecordVisitor rv) {
+ int nItems = records.size();
+ if (nItems < 1) {
+ return;
+ }
+ for(int i=0; iColumnInfoRecord which contains the specified columnIndex
+ * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
+ * @return null
if no column info found for the specified column
+ */
+ public ColumnInfoRecord findColumnInfo(int columnIndex) {
+ int nInfos = records.size();
+ for(int i=0; i< nInfos; i++) {
+ ColumnInfoRecord ci = getColInfo(i);
+ if (ci.getFirstColumn() <= columnIndex && columnIndex <= ci.getLastColumn()) {
+ return ci;
+ }
+ }
+ return null;
+ }
+ public int getMaxOutlineLevel() {
+ int result = 0;
+ int count=records.size();
+ for (int i=0; i
+ *
+ * See OOO exelfileformat.pdf sec 4.12 'Conditional Formatting Table'
+ *
+ * @author Josh Micich
+ */
+public final class ConditionalFormattingTable extends RecordAggregate {
+
+ private final List _cfHeaders;
+
+ /**
+ * Creates an empty ConditionalFormattingTable
+ */
+ public ConditionalFormattingTable() {
+ _cfHeaders = new ArrayList();
+ }
+
+ public ConditionalFormattingTable(RecordStream rs) {
+
+ List temp = new ArrayList();
+ while (rs.peekNextClass() == CFHeaderRecord.class) {
+ temp.add(CFRecordsAggregate.createCFAggregate(rs));
+ }
+ _cfHeaders = temp;
+ }
+
+ public void visitContainedRecords(RecordVisitor rv) {
+ for (int i = 0; i < _cfHeaders.size(); i++) {
+ rv.visitRecord((Record) _cfHeaders.get(i));
+ }
+ }
+
+ /**
+ * @return index of the newly added CF header aggregate
+ */
+ public int add(CFRecordsAggregate cfAggregate) {
+ _cfHeaders.add(cfAggregate);
+ return _cfHeaders.size() - 1;
+ }
+
+ public int size() {
+ return _cfHeaders.size();
+ }
+
+ public CFRecordsAggregate get(int index) {
+ checkIndex(index);
+ return (CFRecordsAggregate) _cfHeaders.get(index);
+ }
+
+ public void remove(int index) {
+ checkIndex(index);
+ _cfHeaders.remove(index);
+ }
+
+ private void checkIndex(int index) {
+ if (index < 0 || index >= _cfHeaders.size()) {
+ throw new IllegalArgumentException("Specified CF index " + index
+ + " is outside the allowable range (0.." + (_cfHeaders.size() - 1) + ")");
+ }
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java b/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java
index 133386d7d..f4861b011 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java
@@ -21,17 +21,9 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.model.RecordStream;
-import org.apache.poi.hssf.record.CFHeaderRecord;
-import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.DVALRecord;
import org.apache.poi.hssf.record.DVRecord;
-import org.apache.poi.hssf.record.EOFRecord;
-import org.apache.poi.hssf.record.HyperlinkRecord;
-import org.apache.poi.hssf.record.MergeCellsRecord;
-import org.apache.poi.hssf.record.PaneRecord;
import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.SelectionRecord;
-import org.apache.poi.hssf.record.WindowTwoRecord;
/**
* Manages the DVALRecord and DVRecords for a single sheet
@@ -40,7 +32,6 @@ import org.apache.poi.hssf.record.WindowTwoRecord;
*/
public final class DataValidityTable extends RecordAggregate {
- private static final short sid = -0x01B2; // not a real record
private final DVALRecord _headerRec;
/**
* The list of data validations for the current sheet.
@@ -57,120 +48,21 @@ public final class DataValidityTable extends RecordAggregate {
_validationList = temp;
}
- private DataValidityTable() {
+ public DataValidityTable() {
_headerRec = new DVALRecord();
_validationList = new ArrayList();
}
- public short getSid() {
- return sid;
- }
-
- public int serialize(int offset, byte[] data) {
- int result = _headerRec.serialize(offset, data);
+ public void visitContainedRecords(RecordVisitor rv) {
+ if (_validationList.isEmpty()) {
+ return;
+ }
+ rv.visitRecord(_headerRec);
for (int i = 0; i < _validationList.size(); i++) {
- result += ((Record) _validationList.get(i)).serialize(offset + result, data);
+ rv.visitRecord((Record) _validationList.get(i));
}
- return result;
- }
-
- public int getRecordSize() {
- int result = _headerRec.getRecordSize();
- for (int i = _validationList.size() - 1; i >= 0; i--) {
- result += ((Record) _validationList.get(i)).getRecordSize();
- }
- return result;
- }
-
- /**
- * Creates a new DataValidityTable and inserts it in the right
- * place in the sheetRecords list.
- */
- public static DataValidityTable createForSheet(List sheetRecords) {
- int index = findDVTableInsertPos(sheetRecords);
-
- DataValidityTable result = new DataValidityTable();
- sheetRecords.add(index, result);
- return result;
}
- /**
- * Finds the index where the sheet validations header record should be inserted
- * @param records the records for this sheet
- *
- * + WINDOW2
- * o SCL
- * o PANE
- * oo SELECTION
- * o STANDARDWIDTH
- * oo MERGEDCELLS
- * o LABELRANGES
- * o PHONETICPR
- * o Conditional Formatting Table
- * o Hyperlink Table
- * o Data Validity Table
- * o SHEETLAYOUT
- * o SHEETPROTECTION
- * o RANGEPROTECTION
- * + EOF
- */
- private static int findDVTableInsertPos(List records) {
- int i = records.size() - 1;
- if (!(records.get(i) instanceof EOFRecord)) {
- throw new IllegalStateException("Last sheet record should be EOFRecord");
- }
- while (i > 0) {
- i--;
- Record rec = (Record) records.get(i);
- if (isPriorRecord(rec.getSid())) {
- Record nextRec = (Record) records.get(i + 1);
- if (!isSubsequentRecord(nextRec.getSid())) {
- throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName()
- + ") found after (" + rec.getClass().getName() + ")");
- }
- return i;
- }
- if (!isSubsequentRecord(rec.getSid())) {
- throw new IllegalStateException("Unexpected (" + rec.getClass().getName()
- + ") while looking for DV Table insert pos");
- }
- }
- return 0;
- }
-
- // TODO - add UninterpretedRecord as base class for many of these
- // unimplemented sids
-
- private static boolean isPriorRecord(short sid) {
- switch(sid) {
- case WindowTwoRecord.sid:
- case 0x00A0: // SCL
- case PaneRecord.sid:
- case SelectionRecord.sid:
- case 0x0099: // STANDARDWIDTH
- case MergeCellsRecord.sid:
- case 0x015F: // LABELRANGES
- case 0x00EF: // PHONETICPR
- case CFHeaderRecord.sid:
- case CFRuleRecord.sid:
- case HyperlinkRecord.sid:
- case 0x0800: // QUICKTIP
- return true;
- }
- return false;
- }
-
- private static boolean isSubsequentRecord(short sid) {
- switch(sid) {
- case 0x0862: // SHEETLAYOUT
- case 0x0867: // SHEETPROTECTION
- case 0x0868: // RANGEPROTECTION
- case EOFRecord.sid:
- return true;
- }
- return false;
- }
-
public void addDataValidation(DVRecord dvRecord) {
_validationList.add(dvRecord);
_headerRec.setDVRecNo(_validationList.size());
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java b/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
new file mode 100644
index 000000000..b7384a019
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
@@ -0,0 +1,122 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.aggregates;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.util.CellRangeAddress;
+import org.apache.poi.hssf.util.CellRangeAddressList;
+
+/**
+ *
+ * @author Josh Micich
+ */
+public final class MergedCellsTable extends RecordAggregate {
+ private static int MAX_MERGED_REGIONS = 1027; // enforced by the 8224 byte limit
+
+ private final List _mergedRegions;
+
+ /**
+ * Creates an empty aggregate
+ */
+ public MergedCellsTable() {
+ _mergedRegions = new ArrayList();
+ }
+
+ public MergedCellsTable(RecordStream rs) {
+ List temp = new ArrayList();
+ while (rs.peekNextClass() == MergeCellsRecord.class) {
+ MergeCellsRecord mcr = (MergeCellsRecord) rs.getNext();
+ int nRegions = mcr.getNumAreas();
+ for (int i = 0; i < nRegions; i++) {
+ temp.add(mcr.getAreaAt(i));
+ }
+ }
+ _mergedRegions = temp;
+ }
+
+ public int getRecordSize() {
+ // a bit cheaper than the default impl
+ int nRegions = _mergedRegions.size();
+ if (nRegions < 1) {
+ // no need to write a single empty MergeCellsRecord
+ return 0;
+ }
+ int nMergedCellsRecords = nRegions / MAX_MERGED_REGIONS;
+ int nLeftoverMergedRegions = nRegions % MAX_MERGED_REGIONS;
+
+ int result = nMergedCellsRecords
+ * (4 + CellRangeAddressList.getEncodedSize(MAX_MERGED_REGIONS)) + 4
+ + CellRangeAddressList.getEncodedSize(nLeftoverMergedRegions);
+ return result;
+ }
+
+ public void visitContainedRecords(RecordVisitor rv) {
+ int nRegions = _mergedRegions.size();
+ if (nRegions < 1) {
+ // no need to write a single empty MergeCellsRecord
+ return;
+ }
+
+ int nFullMergedCellsRecords = nRegions / MAX_MERGED_REGIONS;
+ int nLeftoverMergedRegions = nRegions % MAX_MERGED_REGIONS;
+ CellRangeAddress[] cras = new CellRangeAddress[nRegions];
+ _mergedRegions.toArray(cras);
+
+ for (int i = 0; i < nFullMergedCellsRecords; i++) {
+ int startIx = i * MAX_MERGED_REGIONS;
+ rv.visitRecord(new MergeCellsRecord(cras, startIx, MAX_MERGED_REGIONS));
+ }
+ if (nLeftoverMergedRegions > 0) {
+ int startIx = nFullMergedCellsRecords * MAX_MERGED_REGIONS;
+ rv.visitRecord(new MergeCellsRecord(cras, startIx, nLeftoverMergedRegions));
+ }
+ }
+
+ public void add(MergeCellsRecord mcr) {
+ _mergedRegions.add(mcr);
+ }
+
+ public CellRangeAddress get(int index) {
+ checkIndex(index);
+ return (CellRangeAddress) _mergedRegions.get(index);
+ }
+
+ public void remove(int index) {
+ checkIndex(index);
+ _mergedRegions.remove(index);
+ }
+
+ private void checkIndex(int index) {
+ if (index < 0 || index >= _mergedRegions.size()) {
+ throw new IllegalArgumentException("Specified CF index " + index
+ + " is outside the allowable range (0.." + (_mergedRegions.size() - 1) + ")");
+ }
+ }
+
+ public void addArea(int rowFrom, int colFrom, int rowTo, int colTo) {
+ _mergedRegions.add(new CellRangeAddress(rowFrom, rowTo, colFrom, colTo));
+ }
+
+ public int getNumberOfMergedRegions() {
+ return _mergedRegions.size();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
index 3a86871e8..ce0bf8945 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
@@ -18,6 +18,7 @@
package org.apache.poi.hssf.record.aggregates;
import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.RecordInputStream;
/**
@@ -27,15 +28,66 @@ import org.apache.poi.hssf.record.RecordInputStream;
*
* @author Josh Micich
*/
-public abstract class RecordAggregate extends Record {
- // TODO - convert existing aggregate classes to proper subclasses of this one
+public abstract class RecordAggregate extends RecordBase {
+ // TODO - delete these methods when all subclasses have been converted
protected final void validateSid(short id) {
- // TODO - break class hierarchy and make separate from Record
throw new RuntimeException("Should not be called");
}
protected final void fillFields(RecordInputStream in) {
throw new RuntimeException("Should not be called");
}
- // force subclassses to provide better implementation than default
- public abstract int getRecordSize();
+ public final short getSid() {
+ throw new RuntimeException("Should not be called");
+ }
+
+ public abstract void visitContainedRecords(RecordVisitor rv);
+
+ public final int serialize(int offset, byte[] data) {
+ SerializingRecordVisitor srv = new SerializingRecordVisitor(data, offset);
+ visitContainedRecords(srv);
+ return srv.countBytesWritten();
+ }
+ public int getRecordSize() {
+ RecordSizingVisitor rsv = new RecordSizingVisitor();
+ visitContainedRecords(rsv);
+ return rsv.getTotalSize();
+ }
+
+ public interface RecordVisitor {
+ void visitRecord(Record r);
+ }
+
+ private static final class SerializingRecordVisitor implements RecordVisitor {
+
+ private final byte[] _data;
+ private final int _startOffset;
+ private int _countBytesWritten;
+
+ public SerializingRecordVisitor(byte[] data, int startOffset) {
+ _data = data;
+ _startOffset = startOffset;
+ _countBytesWritten = 0;
+ }
+ public int countBytesWritten() {
+ return _countBytesWritten;
+ }
+ public void visitRecord(Record r) {
+ int currentOffset = _startOffset + _countBytesWritten;
+ _countBytesWritten += r.serialize(currentOffset, _data);
+ }
+ }
+ private static final class RecordSizingVisitor implements RecordVisitor {
+
+ private int _totalSize;
+
+ public RecordSizingVisitor() {
+ _totalSize = 0;
+ }
+ public int getTotalSize() {
+ return _totalSize;
+ }
+ public void visitRecord(Record r) {
+ _totalSize += r.getRecordSize();
+ }
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index c4c9ea619..261198d44 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -48,6 +48,7 @@ import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.record.SubRecord;
import org.apache.poi.hssf.record.TextObjectRecord;
@@ -1144,7 +1145,7 @@ public class HSSFCell
HSSFComment comment = null;
HashMap txshapes = new HashMap(); //map shapeId and TextObjectRecord
for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
- Record rec = ( Record ) it.next();
+ RecordBase rec = (RecordBase) it.next();
if (rec instanceof NoteRecord){
NoteRecord note = (NoteRecord)rec;
if (note.getRow() == row && note.getColumn() == column){
@@ -1186,7 +1187,7 @@ public class HSSFCell
*/
public HSSFHyperlink getHyperlink(){
for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
- Record rec = ( Record ) it.next();
+ RecordBase rec = (RecordBase) it.next();
if (rec instanceof HyperlinkRecord){
HyperlinkRecord link = (HyperlinkRecord)rec;
if(link.getFirstColumn() == record.getColumn() && link.getFirstRow() == record.getRow()){
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index ec104ded9..772b0a58c 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -1446,43 +1446,19 @@ public final class HSSFSheet {
}
/**
- * Retrieves all the horizontal page breaks
- * @return all the horizontal page breaks, or null if there are no row page breaks
+ * @return row indexes of all the horizontal page breaks, never null
*/
public int[] getRowBreaks(){
//we can probably cache this information, but this should be a sparsely used function
- int count = sheet.getNumRowBreaks();
- if (count > 0) {
- int[] returnValue = new int[count];
- Iterator iterator = sheet.getRowBreaks();
- int i = 0;
- while (iterator.hasNext()) {
- PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
- returnValue[i++] = breakItem.main;
- }
- return returnValue;
- }
- return null;
+ return sheet.getRowBreaks();
}
/**
- * Retrieves all the vertical page breaks
- * @return all the vertical page breaks, or null if there are no column page breaks
+ * @return column indexes of all the vertical page breaks, never null
*/
- public short[] getColumnBreaks(){
+ public int[] getColumnBreaks(){
//we can probably cache this information, but this should be a sparsely used function
- int count = sheet.getNumColumnBreaks();
- if (count > 0) {
- short[] returnValue = new short[count];
- Iterator iterator = sheet.getColumnBreaks();
- int i = 0;
- while (iterator.hasNext()) {
- PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
- returnValue[i++] = breakItem.main;
- }
- return returnValue;
- }
- return null;
+ return sheet.getColumnBreaks();
}
diff --git a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
index f901be4c4..b29a8bf3a 100644
--- a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
+++ b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
@@ -125,7 +125,14 @@ public final class CellRangeAddressList {
}
public int getSize() {
- return 2 + CellRangeAddress.getEncodedSize(_list.size());
+ return getEncodedSize(_list.size());
+ }
+ /**
+ * @return the total size of for the specified number of ranges,
+ * including the initial 2 byte range count
+ */
+ public static int getEncodedSize(int numberOfRanges) {
+ return 2 + CellRangeAddress.getEncodedSize(numberOfRanges);
}
public CellRangeAddressList copy() {
CellRangeAddressList result = new CellRangeAddressList();
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
index 4589ee5b1..22defb942 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
@@ -17,20 +17,31 @@
package org.apache.poi.hssf.model;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.eventmodel.ERFListener;
import org.apache.poi.hssf.eventmodel.EventRecordFactory;
-import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.ColumnInfoRecord;
+import org.apache.poi.hssf.record.DimensionsRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.IndexRecord;
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.UncalcedRecord;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
-
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import org.apache.poi.hssf.util.CellRangeAddress;
/**
* Unit test for the Sheet class.
@@ -55,10 +66,24 @@ public final class TestSheet extends TestCase {
assertTrue( sheet.records.get(pos++) instanceof EOFRecord );
}
+ private static final class MergedCellListener implements ERFListener {
+
+ private int _count;
+ public MergedCellListener() {
+ _count = 0;
+ }
+ public boolean processRecord(Record rec) {
+ _count++;
+ return true;
+ }
+ public int getCount() {
+ return _count;
+ }
+ }
+
public void testAddMergedRegion() {
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;
- int startRecords = sheet.getRecords().size();
//simple test that adds a load of regions
for (int n = 0; n < regionsToAdd; n++)
@@ -71,11 +96,18 @@ public final class TestSheet extends TestCase {
assertTrue(sheet.getNumMergedRegions() == regionsToAdd);
//test that the regions were spread out over the appropriate number of records
- int recordsAdded = sheet.getRecords().size() - startRecords;
+ byte[] sheetData = new byte[sheet.getSize()];
+ sheet.serialize(0, sheetData);
+ MergedCellListener mcListener = new MergedCellListener();
+ EventRecordFactory erf = new EventRecordFactory(mcListener, new short[] { MergeCellsRecord.sid, });
+// POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(sheetData));
+ erf.processRecords(new ByteArrayInputStream(sheetData));
+ int recordsAdded = mcListener.getCount();
int recordsExpected = regionsToAdd/1027;
if ((regionsToAdd % 1027) != 0)
recordsExpected++;
- assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected);
+ assertTrue("The " + regionsToAdd + " merged regions should have been spread out over "
+ + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected);
// Check we can't add one with invalid date
try {
sheet.addMergedRegion(10, (short)10, 9, (short)12);
@@ -97,22 +129,23 @@ public final class TestSheet extends TestCase {
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;
- for (int n = 0; n < regionsToAdd; n++)
- sheet.addMergedRegion(0, (short) 0, 1, (short) 1);
+ for (int n = 0; n < regionsToAdd; n++) {
+ sheet.addMergedRegion(n, 0, n, 1);
+ }
- int records = sheet.getRecords().size();
+ int nSheetRecords = sheet.getRecords().size();
//remove a third from the beginning
for (int n = 0; n < regionsToAdd/3; n++)
{
sheet.removeMergedRegion(0);
//assert they have been deleted
- assertTrue("Num of regions should be " + (regionsToAdd - n - 1) + " not " + sheet.getNumMergedRegions(), sheet.getNumMergedRegions() == regionsToAdd - n - 1);
+ assertEquals("Num of regions", regionsToAdd - n - 1, sheet.getNumMergedRegions());
}
-
- //assert any record removing was done
- int recordsRemoved = (regionsToAdd/3)/1027; //doesn't work for particular values of regionsToAdd
- assertTrue("Expected " + recordsRemoved + " record to be removed from the starting " + records + ". Currently there are " + sheet.getRecords().size() + " records", records - sheet.getRecords().size() == recordsRemoved);
+
+ // merge records are removed from within the MergedCellsTable,
+ // so the sheet record count should not change
+ assertEquals("Sheet Records", nSheetRecords, sheet.getRecords().size());
}
/**
@@ -125,8 +158,11 @@ public final class TestSheet extends TestCase {
public void testMovingMergedRegion() {
List records = new ArrayList();
- MergeCellsRecord merged = new MergeCellsRecord();
- merged.addArea(0, (short)0, 1, (short)2);
+ CellRangeAddress[] cras = {
+ new CellRangeAddress(0, 1, 0, 2),
+ };
+ MergeCellsRecord merged = new MergeCellsRecord(cras, 0, cras.length);
+ records.add(new DimensionsRecord());
records.add(new RowRecord(0));
records.add(new RowRecord(1));
records.add(new RowRecord(2));
@@ -155,6 +191,7 @@ public final class TestSheet extends TestCase {
public void testRowAggregation() {
List records = new ArrayList();
+ records.add(new DimensionsRecord());
records.add(new RowRecord(0));
records.add(new RowRecord(1));
records.add(new StringRecord());
@@ -196,10 +233,9 @@ public final class TestSheet extends TestCase {
boolean is0 = false;
boolean is11 = false;
- Iterator iterator = sheet.getRowBreaks();
- while (iterator.hasNext()) {
- PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
- int main = breakItem.main;
+ int[] rowBreaks = sheet.getRowBreaks();
+ for (int i = 0; i < rowBreaks.length; i++) {
+ int main = rowBreaks[i];
if (main != 0 && main != 10 && main != 11) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 10) is10= true;
@@ -253,10 +289,9 @@ public final class TestSheet extends TestCase {
boolean is1 = false;
boolean is15 = false;
- Iterator iterator = sheet.getColumnBreaks();
- while (iterator.hasNext()) {
- PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
- int main = breakItem.main;
+ int[] colBreaks = sheet.getColumnBreaks();
+ for (int i = 0; i < colBreaks.length; i++) {
+ int main = colBreaks[i];
if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 1) is1 = true;
@@ -297,9 +332,8 @@ public final class TestSheet extends TestCase {
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
- // TODO change return type to ColumnInfoRecord
- ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
- sheet.columns.insertColumn(nci);
+ ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
+ sheet._columnInfos.insertColumn(nci);
// single column ColumnInfoRecord
nci.setFirstColumn((short) 2);
@@ -361,6 +395,7 @@ public final class TestSheet extends TestCase {
List records = new ArrayList();
records.add(new BOFRecord());
records.add(new UncalcedRecord());
+ records.add(new DimensionsRecord());
records.add(new EOFRecord());
Sheet sheet = Sheet.createSheet(records, 0, 0);
@@ -369,7 +404,7 @@ public final class TestSheet extends TestCase {
if (serializedSize != estimatedSize) {
throw new AssertionFailedError("Identified bug 45066 b");
}
- assertEquals(50, serializedSize);
+ assertEquals(68, serializedSize);
}
/**
@@ -393,7 +428,7 @@ public final class TestSheet extends TestCase {
int dbCellRecordPos = getDbCellRecordPos(sheet);
- if (dbCellRecordPos == 264) {
+ if (dbCellRecordPos == 252) {
// The overt symptom of the bug
// DBCELL record pos is calculated wrong if VRA comes before RRA
throw new AssertionFailedError("Identified bug 45145");
@@ -405,7 +440,7 @@ public final class TestSheet extends TestCase {
assertEquals(RowRecordsAggregate.class, recs.get(rraIx).getClass());
assertEquals(ValueRecordsAggregate.class, recs.get(rraIx+1).getClass());
- assertEquals(254, dbCellRecordPos);
+ assertEquals(242, dbCellRecordPos);
}
/**
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
index f86c2941a..0962b9148 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
@@ -29,8 +29,7 @@ public final class TestSheetAdditional extends TestCase {
public void testGetCellWidth() {
Sheet sheet = Sheet.createSheet();
- // TODO change return type to ColumnInfoRecord
- ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
+ ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
// Prepare test model
nci.setFirstColumn((short)5);
@@ -38,7 +37,7 @@ public final class TestSheetAdditional extends TestCase {
nci.setColumnWidth((short)100);
- sheet.columns.insertColumn(nci);
+ sheet._columnInfos.insertColumn(nci);
assertEquals((short)100,sheet.getColumnWidth((short)5));
assertEquals((short)100,sheet.getColumnWidth((short)6));
@@ -58,6 +57,3 @@ public final class TestSheetAdditional extends TestCase {
}
}
-
-
-
diff --git a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java
index fe7d26d12..bbbe29ea5 100644
--- a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java
+++ b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java
@@ -33,8 +33,8 @@ public final class TestMergeCellsRecord extends TestCase {
* @throws Exception
*/
public void testCloneReferences() throws Exception {
- MergeCellsRecord merge = new MergeCellsRecord();
- merge.addArea(0, (short)0, 1, (short)2);
+ CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
+ MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
assertNotSame("Merged and cloned objects are the same", merge, clone);
@@ -47,7 +47,6 @@ public final class TestMergeCellsRecord extends TestCase {
assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
- merge.removeAreaAt(0);
- assertNotNull("Clone's item not removed", clone.getAreaAt(0));
+ assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
}
}
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java
index 2472d4d21..138a8bc30 100644
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java
@@ -24,6 +24,7 @@ import java.util.List;
import junit.framework.TestCase;
+import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeaderRecord;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.RecordFactory;
@@ -59,7 +60,7 @@ public final class TestCFRecordsAggregate extends TestCase
recs.add(rule2);
recs.add(rule3);
CFRecordsAggregate record;
- record = CFRecordsAggregate.createCFAggregate(recs, 0);
+ record = CFRecordsAggregate.createCFAggregate(new RecordStream(recs, 0));
// Serialize
byte [] serializedRecord = record.serialize();
@@ -81,7 +82,7 @@ public final class TestCFRecordsAggregate extends TestCase
assertEquals(2, cellRanges.length);
assertEquals(3, header.getNumberOfConditionalFormats());
- record = CFRecordsAggregate.createCFAggregate(recs, 0);
+ record = CFRecordsAggregate.createCFAggregate(new RecordStream(recs, 0));
record = record.cloneCFAggregate();
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
index 20fded35e..298829061 100644
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
@@ -19,42 +19,39 @@ package org.apache.poi.hssf.record.aggregates;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.ColumnInfoRecord;
+import org.apache.poi.hssf.record.RecordBase;
/**
* @author Glen Stampoultzis
*/
-public final class TestColumnInfoRecordsAggregate extends TestCase
-{
- ColumnInfoRecordsAggregate columnInfoRecordsAggregate;
+public final class TestColumnInfoRecordsAggregate extends TestCase {
- public void testGetRecordSize() throws Exception
- {
- columnInfoRecordsAggregate = new ColumnInfoRecordsAggregate();
- columnInfoRecordsAggregate.insertColumn( createColumn( (short)1, (short)3 ));
- columnInfoRecordsAggregate.insertColumn( createColumn( (short)4, (short)7 ));
- columnInfoRecordsAggregate.insertColumn( createColumn( (short)8, (short)8 ));
-// columnInfoRecordsAggregate.setColumn( (short)2, new Short( (short)200 ), new Integer( 1 ), new Boolean( true ), null);
- columnInfoRecordsAggregate.groupColumnRange( (short)2, (short)5, true );
- assertEquals(6, columnInfoRecordsAggregate.getNumColumns());
+ public void testGetRecordSize() {
+ ColumnInfoRecordsAggregate agg = new ColumnInfoRecordsAggregate();
+ agg.insertColumn(createColumn(1, 3));
+ agg.insertColumn(createColumn(4, 7));
+ agg.insertColumn(createColumn(8, 8));
+ agg.groupColumnRange((short) 2, (short) 5, true);
+ assertEquals(6, agg.getNumColumns());
- assertEquals(columnInfoRecordsAggregate.getRecordSize(), columnInfoRecordsAggregate.serialize().length);
+ confirmSerializedSize(agg);
- columnInfoRecordsAggregate = new ColumnInfoRecordsAggregate();
- columnInfoRecordsAggregate.groupColumnRange( (short)3, (short)6, true );
+ agg = new ColumnInfoRecordsAggregate();
+ agg.groupColumnRange((short) 3, (short) 6, true);
+ confirmSerializedSize(agg);
+ }
- assertEquals(columnInfoRecordsAggregate.getRecordSize(), serializedSize());
- }
+ private static void confirmSerializedSize(RecordBase cirAgg) {
+ int estimatedSize = cirAgg.getRecordSize();
+ byte[] buf = new byte[estimatedSize];
+ int serializedSize = cirAgg.serialize(0, buf);
+ assertEquals(estimatedSize, serializedSize);
+ }
- private int serializedSize()
- {
- return columnInfoRecordsAggregate.serialize(0, new byte[columnInfoRecordsAggregate.getRecordSize()]);
- }
-
- private ColumnInfoRecord createColumn( short firstCol, short lastCol )
- {
- ColumnInfoRecord columnInfoRecord = new ColumnInfoRecord( );
- columnInfoRecord.setFirstColumn(firstCol);
- columnInfoRecord.setLastColumn(lastCol);
- return columnInfoRecord;
- }
+ private static ColumnInfoRecord createColumn(int firstCol, int lastCol) {
+ ColumnInfoRecord columnInfoRecord = new ColumnInfoRecord();
+ columnInfoRecord.setFirstColumn((short) firstCol);
+ columnInfoRecord.setLastColumn((short) lastCol);
+ return columnInfoRecord;
+ }
}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
index 9f68e7d25..cc5784c50 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
@@ -659,7 +659,7 @@ public final class TestBugs extends TestCase {
HSSFSheet sheet = wb.getSheetAt( 0 );
int[] breaks = sheet.getRowBreaks();
- assertNull(breaks);
+ assertEquals(0, breaks.length);
//add 3 row breaks
for (int j = 1; j <= 3; j++) {