From 8befcb660a84cb5ba93e0ab98c242017f1856e28 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Mon, 29 Sep 2008 20:38:55 +0000 Subject: [PATCH] Merged revisions 700005,700203-700204 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r700005 | josh | 2008-09-29 00:27:14 -0700 (Mon, 29 Sep 2008) | 1 line Fix for bug 45890 - made HSSFSheet.shiftRows also update conditional formats ........ r700203 | josh | 2008-09-29 11:43:53 -0700 (Mon, 29 Sep 2008) | 1 line Refactoring row-blocks record reading logic in Sheet ........ r700204 | josh | 2008-09-29 11:48:43 -0700 (Mon, 29 Sep 2008) | 1 line Should have been submitted with c700203 (Refactoring row-blocks record reading logic in Sheet) ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@700243 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 1 + src/documentation/content/xdocs/status.xml | 1 + .../poi/hssf/eventmodel/ModelFactory.java | 32 +- .../apache/poi/hssf/model/RecordOrderer.java | 38 +- .../poi/hssf/model/RowBlocksReader.java | 30 +- src/java/org/apache/poi/hssf/model/Sheet.java | 336 ++++++++---------- .../apache/poi/hssf/record/BlankRecord.java | 65 +--- .../apache/poi/hssf/record/BoolErrRecord.java | 80 ++--- .../apache/poi/hssf/record/CFRuleRecord.java | 12 + .../apache/poi/hssf/record/DBCellRecord.java | 4 - .../apache/poi/hssf/record/FormulaRecord.java | 8 - .../apache/poi/hssf/record/LabelRecord.java | 63 +--- .../poi/hssf/record/LabelSSTRecord.java | 62 ++-- .../apache/poi/hssf/record/NumberRecord.java | 74 ++-- .../org/apache/poi/hssf/record/RKRecord.java | 71 ++-- .../org/apache/poi/hssf/record/Record.java | 18 - .../org/apache/poi/hssf/record/RowRecord.java | 131 ++----- .../hssf/record/SharedValueRecordBase.java | 16 - .../apache/poi/hssf/record/StringRecord.java | 25 +- .../record/aggregates/CFRecordsAggregate.java | 69 +++- .../ConditionalFormattingTable.java | 12 + .../aggregates/FormulaRecordAggregate.java | 12 +- .../aggregates/RowRecordsAggregate.java | 2 +- .../apache/poi/hssf/usermodel/HSSFSheet.java | 4 +- .../HSSFSheetConditionalFormatting.java | 15 +- .../poi/hssf/usermodel/HSSFWorkbook.java | 8 +- .../org/apache/poi/hssf/model/TestSheet.java | 13 +- .../hssf/record/TestExternalNameRecord.java | 4 - .../aggregates/TestValueRecordsAggregate.java | 2 +- .../TestHSSFConditionalFormatting.java | 46 ++- 30 files changed, 522 insertions(+), 732 deletions(-) diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 7dfc886884..e74bf9296f 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -67,6 +67,7 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 45890 - fixed HSSFSheet.shiftRows to also update conditional formats 45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas Optimised the FormulaEvaluator to take cell dependencies into account 16936 - Initial support for whole-row cell styling diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 09014b72c5..c331931b21 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -64,6 +64,7 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 45890 - fixed HSSFSheet.shiftRows to also update conditional formats 45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas Optimised the FormulaEvaluator to take cell dependencies into account 16936 - Initial support for whole-row cell styling diff --git a/src/java/org/apache/poi/hssf/eventmodel/ModelFactory.java b/src/java/org/apache/poi/hssf/eventmodel/ModelFactory.java index d75ca6c2e6..8f49e67b98 100644 --- a/src/java/org/apache/poi/hssf/eventmodel/ModelFactory.java +++ b/src/java/org/apache/poi/hssf/eventmodel/ModelFactory.java @@ -31,9 +31,9 @@ import org.apache.poi.hssf.record.Record; /** - * ModelFactory creates workbook and sheet models based upon + * ModelFactory creates workbook and sheet models based upon * events thrown by them there events from the EventRecordFactory. - * + * * @see org.apache.poi.hssf.eventmodel.EventRecordFactory * @author Andrew C. Oliver acoliver@apache.org */ @@ -43,7 +43,7 @@ public class ModelFactory implements ERFListener List listeners; Model currentmodel; boolean lastEOF; - + /** * Constructor for ModelFactory. Does practically nothing. */ @@ -52,15 +52,15 @@ public class ModelFactory implements ERFListener super(); listeners = new ArrayList(1); } - + /** - * register a ModelFactoryListener so that it can receive + * register a ModelFactoryListener so that it can receive * Models as they are created. */ public void registerListener(ModelFactoryListener listener) { listeners.add(listener); } - + /** * Start processing the Workbook stream into Model events. */ @@ -75,31 +75,31 @@ public class ModelFactory implements ERFListener { if (rec.getSid() == BOFRecord.sid) { if (lastEOF != true) { - throw new RuntimeException("Not yet handled embedded models"); + throw new RuntimeException("Not yet handled embedded models"); } else { BOFRecord bof = (BOFRecord)rec; switch (bof.getType()) { case BOFRecord.TYPE_WORKBOOK: - currentmodel = new Workbook(); + currentmodel = new Workbook(); break; case BOFRecord.TYPE_WORKSHEET: - currentmodel = new Sheet(); + currentmodel = Sheet.createSheet(); break; default: throw new RuntimeException("Unsupported model type "+bof.getType()); - } - - } + } + + } } - + if (rec.getSid() == EOFRecord.sid) { lastEOF = true; throwEvent(currentmodel); } else { - lastEOF = false; + lastEOF = false; } - - + + return true; } diff --git a/src/java/org/apache/poi/hssf/model/RecordOrderer.java b/src/java/org/apache/poi/hssf/model/RecordOrderer.java index 291bd07715..394825917d 100644 --- a/src/java/org/apache/poi/hssf/model/RecordOrderer.java +++ b/src/java/org/apache/poi/hssf/model/RecordOrderer.java @@ -19,7 +19,10 @@ package org.apache.poi.hssf.model; import java.util.List; +import org.apache.poi.hssf.record.ArrayRecord; import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.CalcCountRecord; import org.apache.poi.hssf.record.CalcModeRecord; import org.apache.poi.hssf.record.DVALRecord; @@ -30,22 +33,30 @@ import org.apache.poi.hssf.record.DimensionsRecord; import org.apache.poi.hssf.record.DrawingRecord; import org.apache.poi.hssf.record.DrawingSelectionRecord; import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.GridsetRecord; import org.apache.poi.hssf.record.GutsRecord; 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.LabelRecord; +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.ObjRecord; 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.RKRecord; 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.RowRecord; 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.SharedFormulaRecord; +import org.apache.poi.hssf.record.TableRecord; import org.apache.poi.hssf.record.TextObjectRecord; import org.apache.poi.hssf.record.UncalcedRecord; import org.apache.poi.hssf.record.UnknownRecord; @@ -324,7 +335,7 @@ final class RecordOrderer { * It is assumed that at least one row or cell value record has been found prior to the current * record */ - public static boolean isEndOfRowBlock(short sid) { + public static boolean isEndOfRowBlock(int sid) { switch(sid) { case DrawingRecord.sid: case DrawingSelectionRecord.sid: @@ -344,4 +355,29 @@ final class RecordOrderer { } return PageSettingsBlock.isComponentRecord(sid); } + + /** + * @return true if the specified record id normally appears in the row blocks section + * of the sheet records + */ + public static boolean isRowBlockRecord(int sid) { + switch (sid) { + case RowRecord.sid: + + case BlankRecord.sid: + case BoolErrRecord.sid: + case FormulaRecord.sid: + case LabelRecord.sid: + case LabelSSTRecord.sid: + case NumberRecord.sid: + case RKRecord.sid: + + case ArrayRecord.sid: + case SharedFormulaRecord.sid: + case TableRecord.sid: + return true; + + } + return false; + } } diff --git a/src/java/org/apache/poi/hssf/model/RowBlocksReader.java b/src/java/org/apache/poi/hssf/model/RowBlocksReader.java index 963838862f..020d489417 100644 --- a/src/java/org/apache/poi/hssf/model/RowBlocksReader.java +++ b/src/java/org/apache/poi/hssf/model/RowBlocksReader.java @@ -39,30 +39,28 @@ public final class RowBlocksReader { private final List _plainRecords; private final SharedValueManager _sfm; private final MergeCellsRecord[] _mergedCellsRecords; - private final int _totalNumberOfRecords; /** * Also collects any loose MergeCellRecords and puts them in the supplied * mergedCellsTable */ - public RowBlocksReader(List recs, int startIx) { + public RowBlocksReader(RecordStream rs) { List plainRecords = new ArrayList(); List shFrmRecords = new ArrayList(); List arrayRecords = new ArrayList(); List tableRecords = new ArrayList(); List mergeCellRecords = new ArrayList(); - int endIx = -1; - for (int i = startIx; i < recs.size(); i++) { - Record rec = (Record) recs.get(i); - if (RecordOrderer.isEndOfRowBlock(rec.getSid())) { - // End of row/cell records for the current sheet - // Note - It is important that this code does not inadvertently any sheet - // records from a subsequent sheet. For example, if SharedFormulaRecords - // are taken from the wrong sheet, this could cause bug 44449. - endIx = i; - break; + while(!RecordOrderer.isEndOfRowBlock(rs.peekNextSid())) { + // End of row/cell records for the current sheet + // Note - It is important that this code does not inadvertently add any sheet + // records from a subsequent sheet. For example, if SharedFormulaRecords + // are taken from the wrong sheet, this could cause bug 44449. + if (!rs.hasNext()) { + throw new RuntimeException("Failed to find end of row/cell records"); + } + Record rec = rs.getNext(); List dest; switch (rec.getSid()) { case MergeCellsRecord.sid: dest = mergeCellRecords; break; @@ -73,9 +71,6 @@ public final class RowBlocksReader { } dest.add(rec); } - if (endIx < 0) { - throw new RuntimeException("Failed to find end of row/cell records"); - } SharedFormulaRecord[] sharedFormulaRecs = new SharedFormulaRecord[shFrmRecords.size()]; ArrayRecord[] arrayRecs = new ArrayRecord[arrayRecords.size()]; TableRecord[] tableRecs = new TableRecord[tableRecords.size()]; @@ -87,7 +82,6 @@ public final class RowBlocksReader { _sfm = SharedValueManager.create(sharedFormulaRecs, arrayRecs, tableRecs); _mergedCellsRecords = new MergeCellsRecord[mergeCellRecords.size()]; mergeCellRecords.toArray(_mergedCellsRecords); - _totalNumberOfRecords = endIx - startIx; } /** @@ -99,10 +93,6 @@ public final class RowBlocksReader { return _mergedCellsRecords; } - public int getTotalNumberOfRecords() { - return _totalNumberOfRecords; - } - public SharedValueManager getSharedFormulaManager() { return _sfm; } diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index ba62b225c5..c5e78af44d 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -58,7 +58,6 @@ import org.apache.poi.hssf.record.SelectionRecord; import org.apache.poi.hssf.record.UncalcedRecord; 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; @@ -68,6 +67,7 @@ import org.apache.poi.hssf.record.aggregates.RecordAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; +import org.apache.poi.hssf.record.formula.FormulaShifter; import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.util.POILogFactory; @@ -104,7 +104,6 @@ public final class Sheet implements Model { private static POILogger log = POILogFactory.getLogger(Sheet.class); protected ArrayList records = null; - protected int dimsloc = -1; // TODO - remove dimsloc protected PrintGridlinesRecord printGridlines = null; protected GridsetRecord gridset = null; private GutsRecord _gutsRecord; @@ -117,7 +116,7 @@ public final class Sheet implements Model { protected ObjectProtectRecord objprotect = null; protected ScenarioProtectRecord scenprotect = null; protected PasswordRecord password = null; - + protected WindowTwoRecord windowTwo = null; protected SelectionRecord selection = null; /** java object always present, but if empty no BIFF records are written */ @@ -127,29 +126,20 @@ public final class Sheet implements Model { /** the DimensionsRecord is always present */ private DimensionsRecord _dimensions; /** always present */ - protected RowRecordsAggregate _rowsAggregate; + protected final RowRecordsAggregate _rowsAggregate; private DataValidityTable _dataValidityTable= null; private ConditionalFormattingTable condFormatting; - protected int eofLoc = 0; private Iterator rowRecIterator = null; /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ protected boolean _isUncalced = false; - + public static final byte PANE_LOWER_RIGHT = (byte)0; public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_LOWER_LEFT = (byte)2; public static final byte PANE_UPPER_LEFT = (byte)3; - /** - * Creates new Sheet with no initialization --useless at this point - * @see #createSheet(List,int,int) - */ - public Sheet() { - _mergedCellsTable = new MergedCellsTable(); - } - /** * read support (offset used as starting point for search) for low level * API. Pass in an array of Record objects, the sheet number (0 based) and @@ -167,178 +157,170 @@ public final class Sheet implements Model { * @see org.apache.poi.hssf.model.Workbook * @see org.apache.poi.hssf.record.Record */ - public static Sheet createSheet(List inRecs, int sheetnum, int offset) - { - if (log.check( POILogger.DEBUG )) - log.logFormatted(POILogger.DEBUG, - "Sheet createSheet (existing file) with %", - new Integer(inRecs.size())); - Sheet retval = new Sheet(); - ArrayList records = new ArrayList(inRecs.size() / 5); + public static Sheet createSheet(RecordStream rs) { + return new Sheet(rs); + } + private Sheet(RecordStream rs) { + _mergedCellsTable = new MergedCellsTable(); + RowRecordsAggregate rra = null; + + records = new ArrayList(128); // TODO - take chart streams off into separate java objects int bofEofNestingLevel = 0; // nesting level can only get to 2 (when charts are present) + int dimsloc = -1; - for (int k = offset; k < inRecs.size(); k++) { - Record rec = ( Record ) inRecs.get(k); - if ( rec.getSid() == IndexRecord.sid ) { - // ignore INDEX record because it is only needed by Excel, - // and POI always re-calculates its contents - continue; - } + while (rs.hasNext()) { + int recSid = rs.peekNextSid(); - if ( rec.getSid() == CFHeaderRecord.sid ) { - RecordStream rs = new RecordStream(inRecs, k); - retval.condFormatting = new ConditionalFormattingTable(rs); - k += rs.getCountRead()-1; - records.add(retval.condFormatting); + if ( recSid == CFHeaderRecord.sid ) { + condFormatting = new ConditionalFormattingTable(rs); + records.add(condFormatting); continue; } - - if (rec.getSid() == ColumnInfoRecord.sid) { - RecordStream rs = new RecordStream(inRecs, k); - retval._columnInfos = new ColumnInfoRecordsAggregate(rs); - k += rs.getCountRead()-1; - records.add(retval._columnInfos); + + if (recSid == ColumnInfoRecord.sid) { + _columnInfos = new ColumnInfoRecordsAggregate(rs); + records.add(_columnInfos); continue; } - if ( rec.getSid() == DVALRecord.sid) { - RecordStream rs = new RecordStream(inRecs, k); - retval._dataValidityTable = new DataValidityTable(rs); - k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based - records.add(retval._dataValidityTable); + if ( recSid == DVALRecord.sid) { + _dataValidityTable = new DataValidityTable(rs); + records.add(_dataValidityTable); continue; } - // TODO construct RowRecordsAggregate from RecordStream - if ((rec.getSid() == RowRecord.sid || rec.isValue()) && bofEofNestingLevel == 1 ) { + + if (RecordOrderer.isRowBlockRecord(recSid) && bofEofNestingLevel == 1 ) { //only add the aggregate once - if (retval._rowsAggregate != null) { + if (rra != null) { throw new RuntimeException("row/cell records found in the wrong place"); } - RowBlocksReader rbr = new RowBlocksReader(inRecs, k); - retval._mergedCellsTable.addRecords(rbr.getLooseMergedCells()); - retval._rowsAggregate = new RowRecordsAggregate(rbr.getPlainRecordStream(), rbr.getSharedFormulaManager()); - records.add(retval._rowsAggregate); //only add the aggregate once - k += rbr.getTotalNumberOfRecords() - 1; + RowBlocksReader rbr = new RowBlocksReader(rs); + _mergedCellsTable.addRecords(rbr.getLooseMergedCells()); + rra = new RowRecordsAggregate(rbr.getPlainRecordStream(), rbr.getSharedFormulaManager()); + records.add(rra); //only add the aggregate once continue; } - - if (PageSettingsBlock.isComponentRecord(rec.getSid())) { - RecordStream rs = new RecordStream(inRecs, k); + + if (PageSettingsBlock.isComponentRecord(recSid)) { PageSettingsBlock psb = new PageSettingsBlock(rs); if (bofEofNestingLevel == 1) { - if (retval._psBlock == null) { - retval._psBlock = psb; + if (_psBlock == null) { + _psBlock = psb; } else { // more than one 'Page Settings Block' at nesting level 1 ? // apparently this happens in about 15 test sample files } } records.add(psb); - k += rs.getCountRead()-1; continue; } - - if (rec.getSid() == MergeCellsRecord.sid) { + + if (recSid == MergeCellsRecord.sid) { // when the MergedCellsTable is found in the right place, we expect those records to be contiguous - RecordStream rs = new RecordStream(inRecs, k); - retval._mergedCellsTable.read(rs); - k += rs.getCountRead()-1; + _mergedCellsTable.read(rs); + continue; + } + + Record rec = rs.getNext(); + if ( recSid == IndexRecord.sid ) { + // ignore INDEX record because it is only needed by Excel, + // and POI always re-calculates its contents continue; } - if (rec.getSid() == UncalcedRecord.sid) { + + + if (recSid == UncalcedRecord.sid) { // don't add UncalcedRecord to the list - retval._isUncalced = true; // this flag is enough + _isUncalced = true; // this flag is enough continue; } - if (rec.getSid() == BOFRecord.sid) + if (recSid == BOFRecord.sid) { bofEofNestingLevel++; if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel); } - else if (rec.getSid() == EOFRecord.sid) + else if (recSid == EOFRecord.sid) { --bofEofNestingLevel; if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel); if (bofEofNestingLevel == 0) { records.add(rec); - retval.eofLoc = k; break; } } - else if (rec.getSid() == DimensionsRecord.sid) + else if (recSid == DimensionsRecord.sid) { // Make a columns aggregate if one hasn't ready been created. - if (retval._columnInfos == null) + if (_columnInfos == null) { - retval._columnInfos = new ColumnInfoRecordsAggregate(); - records.add(retval._columnInfos); + _columnInfos = new ColumnInfoRecordsAggregate(); + records.add(_columnInfos); } - retval._dimensions = ( DimensionsRecord ) rec; - retval.dimsloc = records.size(); + _dimensions = ( DimensionsRecord ) rec; + dimsloc = records.size(); } - else if (rec.getSid() == DefaultColWidthRecord.sid) + else if (recSid == DefaultColWidthRecord.sid) { - retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; + defaultcolwidth = ( DefaultColWidthRecord ) rec; } - else if (rec.getSid() == DefaultRowHeightRecord.sid) + else if (recSid == DefaultRowHeightRecord.sid) { - retval.defaultrowheight = ( DefaultRowHeightRecord ) rec; + defaultrowheight = ( DefaultRowHeightRecord ) rec; } - else if ( rec.getSid() == PrintGridlinesRecord.sid ) + else if ( recSid == PrintGridlinesRecord.sid ) { - retval.printGridlines = (PrintGridlinesRecord) rec; + printGridlines = (PrintGridlinesRecord) rec; } - else if ( rec.getSid() == GridsetRecord.sid ) + else if ( recSid == GridsetRecord.sid ) { - retval.gridset = (GridsetRecord) rec; + gridset = (GridsetRecord) rec; } - else if ( rec.getSid() == SelectionRecord.sid ) + else if ( recSid == SelectionRecord.sid ) { - retval.selection = (SelectionRecord) rec; + selection = (SelectionRecord) rec; } - else if ( rec.getSid() == WindowTwoRecord.sid ) + else if ( recSid == WindowTwoRecord.sid ) { - retval.windowTwo = (WindowTwoRecord) rec; + windowTwo = (WindowTwoRecord) rec; } - else if ( rec.getSid() == ProtectRecord.sid ) + else if ( recSid == ProtectRecord.sid ) { - retval.protect = (ProtectRecord) rec; + protect = (ProtectRecord) rec; } - else if ( rec.getSid() == ObjectProtectRecord.sid ) + else if ( recSid == ObjectProtectRecord.sid ) { - retval.objprotect = (ObjectProtectRecord) rec; + objprotect = (ObjectProtectRecord) rec; } - else if ( rec.getSid() == ScenarioProtectRecord.sid ) + else if ( recSid == ScenarioProtectRecord.sid ) { - retval.scenprotect = (ScenarioProtectRecord) rec; + scenprotect = (ScenarioProtectRecord) rec; } - else if ( rec.getSid() == PasswordRecord.sid ) + else if ( recSid == PasswordRecord.sid ) { - retval.password = (PasswordRecord) rec; + password = (PasswordRecord) rec; } records.add(rec); } - if (retval._dimensions == null) { + if (_dimensions == null) { throw new RuntimeException("DimensionsRecord was not found"); } - if (retval.windowTwo == null) { + if (windowTwo == null) { throw new RuntimeException("WINDOW2 was not found"); } - if (retval._rowsAggregate == null) { - retval._rowsAggregate = new RowRecordsAggregate(); - records.add(retval.dimsloc + 1, retval._rowsAggregate); + if (rra == null) { + rra = new RowRecordsAggregate(); + records.add(dimsloc + 1, rra); } + _rowsAggregate = rra; // put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */ - RecordOrderer.addNewSheetRecord(records, retval._mergedCellsTable); - retval.records = records; + RecordOrderer.addNewSheetRecord(records, _mergedCellsTable); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); - return retval; } private static final class RecordCloner implements RecordVisitor { @@ -361,7 +343,7 @@ public final class Sheet implements Model { * belongs to a sheet. */ public Sheet cloneSheet() { - ArrayList clonedRecords = new ArrayList(this.records.size()); + List clonedRecords = new ArrayList(this.records.size()); for (int i = 0; i < this.records.size(); i++) { RecordBase rb = (RecordBase) this.records.get(i); if (rb instanceof RecordAggregate) { @@ -371,25 +353,7 @@ public final class Sheet implements Model { Record rec = (Record) ((Record) rb).clone(); clonedRecords.add(rec); } - return createSheet(clonedRecords, 0, 0); - } - - - /** - * read support (offset = 0) Same as createSheet(Record[] recs, int, int) - * only the record offset is assumed to be 0. - * - * @param records array containing those records in the sheet in sequence (normally obtained from RecordFactory) - * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release) - * @return Sheet object - */ - - public static Sheet createSheet(List records, int sheetnum) - { - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, - "Sheet createSheet (exisiting file) assumed offset 0"); - return createSheet(records, sheetnum, 0); + return createSheet(new RecordStream(clonedRecords, 0)); } /** @@ -399,19 +363,18 @@ public final class Sheet implements Model { * * @return Sheet object with all values set to defaults */ - - public static Sheet createSheet() - { - // TODO - convert this method to a constructor + public static Sheet createSheet() { + return new Sheet(); + } + private Sheet() { + _mergedCellsTable = new MergedCellsTable(); + records = new ArrayList(32); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "Sheet createsheet from scratch called"); - Sheet retval = new Sheet(); - ArrayList records = new ArrayList(30); records.add(createBOF()); - // records.add(retval.createIndex()); records.add(createCalcMode()); records.add(createCalcCount() ); records.add(createRefMode() ); @@ -419,50 +382,46 @@ public final class Sheet implements Model { records.add(createDelta() ); records.add(createSaveRecalc() ); records.add(createPrintHeaders() ); - retval.printGridlines = createPrintGridlines(); - records.add( retval.printGridlines ); - retval.gridset = createGridset(); - records.add( retval.gridset ); - retval._gutsRecord = createGuts(); - records.add( retval._gutsRecord ); - retval.defaultrowheight = createDefaultRowHeight(); - records.add( retval.defaultrowheight ); - records.add( retval.createWSBool() ); - + printGridlines = createPrintGridlines(); + records.add( printGridlines ); + gridset = createGridset(); + records.add( gridset ); + _gutsRecord = createGuts(); + records.add( _gutsRecord ); + defaultrowheight = createDefaultRowHeight(); + records.add( defaultrowheight ); + records.add( createWSBool() ); + // 'Page Settings Block' - retval._psBlock = new PageSettingsBlock(); - records.add(retval._psBlock); - + _psBlock = new PageSettingsBlock(); + records.add(_psBlock); + // 'Worksheet Protection Block' (after 'Page Settings Block' and before DEFCOLWIDTH) // PROTECT record normally goes here, don't add yet since the flag is initially false - - retval.defaultcolwidth = createDefaultColWidth(); - records.add( retval.defaultcolwidth); + + defaultcolwidth = createDefaultColWidth(); + records.add( defaultcolwidth); ColumnInfoRecordsAggregate columns = new ColumnInfoRecordsAggregate(); records.add( columns ); - retval._columnInfos = columns; - retval._dimensions = createDimensions(); - records.add(retval._dimensions); - retval.dimsloc = records.size()-1; - retval._rowsAggregate = new RowRecordsAggregate(); - records.add(retval._rowsAggregate); + _columnInfos = columns; + _dimensions = createDimensions(); + records.add(_dimensions); + _rowsAggregate = new RowRecordsAggregate(); + records.add(_rowsAggregate); // 'Sheet View Settings' - records.add(retval.windowTwo = retval.createWindowTwo()); - retval.selection = createSelection(); - records.add(retval.selection); + records.add(windowTwo = createWindowTwo()); + selection = createSelection(); + records.add(selection); - records.add(retval._mergedCellsTable); // MCT comes after 'Sheet View Settings' + records.add(_mergedCellsTable); // MCT comes after 'Sheet View Settings' records.add(EOFRecord.instance); - - retval.records = records; if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit"); - return retval; } public RowRecordsAggregate getRowsAggregate() { - return _rowsAggregate; + return _rowsAggregate; } private MergedCellsTable getMergedRecords() { @@ -470,6 +429,15 @@ public final class Sheet implements Model { return _mergedCellsTable; } + /** + * Updates formulas in cells and conditional formats due to moving of cells + * @param externSheetIndex the externSheet index of this sheet + */ + public void updateFormulasAfterCellShift(FormulaShifter shifter, int externSheetIndex) { + getRowsAggregate().updateFormulasAfterRowShift(shifter, externSheetIndex); + getConditionalFormattingTable().updateFormulasAfterCellShift(shifter, externSheetIndex); + // TODO - adjust data validations + } public int addMergedRegion(int rowFrom, int colFrom, int rowTo, int colTo) { // Validate input @@ -509,7 +477,7 @@ public final class Sheet implements Model { public int getNumMergedRegions() { return getMergedRecords().getNumberOfMergedRegions(); } - private ConditionalFormattingTable getConditionalFormattingTable() { + public ConditionalFormattingTable getConditionalFormattingTable() { if (condFormatting == null) { condFormatting = new ConditionalFormattingTable(); RecordOrderer.addNewSheetRecord(records, condFormatting); @@ -517,24 +485,6 @@ public final class Sheet implements Model { return condFormatting; } - - public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { - ConditionalFormattingTable cft = getConditionalFormattingTable(); - return cft.add(cfAggregate); - } - - public void removeConditionalFormatting(int index) { - getConditionalFormattingTable().remove(index); - } - - public CFRecordsAggregate getCFRecordsAggregateAt(int index) { - return getConditionalFormattingTable().get(index); - } - - public int getNumConditionalFormattings() { - return getConditionalFormattingTable().size(); - } - /** * Per an earlier reported bug in working with Andy Khan's excel read library. This * sets the values in the sheet's DimensionsRecord object to be correct. Excel doesn't @@ -565,7 +515,7 @@ public final class Sheet implements Model { public void visitContainedRecords(RecordVisitor rv, int offset) { PositionTrackingVisitor ptv = new PositionTrackingVisitor(rv, offset); - + boolean haveSerializedIndex = false; for (int k = 0; k < records.size(); k++) @@ -1074,7 +1024,7 @@ public final class Sheet implements Model { /** * set the width for a given column in 1/256th of a character width units - * + * * @param column - * the column number * @param width @@ -1340,7 +1290,7 @@ public final class Sheet implements Model { public WindowTwoRecord getWindowTwo() { return windowTwo; } - + /** * Returns the PrintGridlinesRecord. * @return PrintGridlinesRecord for the sheet. @@ -1367,11 +1317,6 @@ public final class Sheet implements Model { windowTwo.setSelected(sel); } - public int getEofLoc() - { - return eofLoc; - } - /** * Creates a split (freezepane). Any existing freezepane or split pane is overwritten. * @param colSplit Horizonatal position of split. @@ -1481,7 +1426,7 @@ public final class Sheet implements Model { if (log.check( POILogger.DEBUG )) { log.log(POILogger.DEBUG, "create protect record with protection disabled"); } - ProtectRecord retval = new ProtectRecord(); + ProtectRecord retval = new ProtectRecord(); retval.setProtect(false); // TODO - supply param to constructor return retval; } @@ -1683,24 +1628,23 @@ public final class Sheet implements Model { } } - + public PageSettingsBlock getPageSettings() { if (_psBlock == null) { _psBlock = new PageSettingsBlock(); RecordOrderer.addNewSheetRecord(records, _psBlock); - dimsloc++; } return _psBlock; } public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) { - if (collapsed) { - _columnInfos.collapseColumn(columnNumber); - } else { - _columnInfos.expandColumn(columnNumber); - } - } + if (collapsed) { + _columnInfos.collapseColumn(columnNumber); + } else { + _columnInfos.expandColumn(columnNumber); + } + } /** * protect a spreadsheet with a password (not encypted, just sets protect diff --git a/src/java/org/apache/poi/hssf/record/BlankRecord.java b/src/java/org/apache/poi/hssf/record/BlankRecord.java index bfb308bd58..cf1b97f5a5 100644 --- a/src/java/org/apache/poi/hssf/record/BlankRecord.java +++ b/src/java/org/apache/poi/hssf/record/BlankRecord.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,19 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - -/* - * BlankRecord.java - * - * Created on December 10, 2001, 12:07 PM - */ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; /** - * Title: Blank cell record

+ * Title: Blank cell record (0x0201)

* Description: Represents a column in a row with no value but with styling.

* REFERENCE: PG 287 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) @@ -35,13 +29,12 @@ import org.apache.poi.util.LittleEndian; * @version 2.0-pre */ public final class BlankRecord extends Record implements CellValueRecordInterface { - public final static short sid = 0x201; + public final static short sid = 0x0201; private int field_1_row; private short field_2_col; private short field_3_xf; /** Creates a new instance of BlankRecord */ - public BlankRecord() { } @@ -50,7 +43,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * Constructs a BlankRecord and sets its fields appropriately * @param in the RecordInputstream to read the record from */ - public BlankRecord(RecordInputStream in) { super(in); @@ -58,7 +50,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac protected void fillFields(RecordInputStream in) { - //field_1_row = LittleEndian.getShort(data, 0 + offset); field_1_row = in.readUShort(); field_2_col = in.readShort(); field_3_xf = in.readShort(); @@ -70,7 +61,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * * @param id alleged id for this record */ - protected void validateSid(short id) { if (id != sid) @@ -83,8 +73,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * set the row this cell occurs on * @param row the row this cell occurs within */ - - //public void setRow(short row) public void setRow(int row) { field_1_row = row; @@ -95,8 +83,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * * @return the row */ - - //public short getRow() public int getRow() { return field_1_row; @@ -107,7 +93,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * * @return the column */ - public short getColumn() { return field_2_col; @@ -119,7 +104,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * @param xf - the 0-based index of the extended format * @see org.apache.poi.hssf.record.ExtendedFormatRecord */ - public void setXFIndex(short xf) { field_3_xf = xf; @@ -130,7 +114,6 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * * @return extended format index */ - public short getXFIndex() { return field_3_xf; @@ -147,20 +130,9 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac field_2_col = col; } - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; - } - /** * return the non static version of the id for this record. */ - public short getSid() { return sid; @@ -168,17 +140,14 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac public String toString() { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[BLANK]\n"); - buffer.append("row = ").append(Integer.toHexString(getRow())) - .append("\n"); - buffer.append("col = ").append(Integer.toHexString(getColumn())) - .append("\n"); - buffer.append("xf = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append("[/BLANK]\n"); - return buffer.toString(); + StringBuffer sb = new StringBuffer(); + + sb.append("[BLANK]\n"); + sb.append(" row= ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" col= ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + sb.append("[/BLANK]\n"); + return sb.toString(); } /** @@ -188,15 +157,13 @@ public final class BlankRecord extends Record implements CellValueRecordInterfac * * @return byte array containing instance data */ - public int serialize(int offset, byte [] data) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 6); - //LittleEndian.putShort(data, 4 + offset, getRow()); - LittleEndian.putShort(data, 4 + offset, ( short ) getRow()); - LittleEndian.putShort(data, 6 + offset, getColumn()); - LittleEndian.putShort(data, 8 + offset, getXFIndex()); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, 6); + LittleEndian.putUShort(data, 4 + offset, getRow()); + LittleEndian.putUShort(data, 6 + offset, getColumn()); + LittleEndian.putUShort(data, 8 + offset, getXFIndex()); return getRecordSize(); } diff --git a/src/java/org/apache/poi/hssf/record/BoolErrRecord.java b/src/java/org/apache/poi/hssf/record/BoolErrRecord.java index 43bdda900c..11f562d559 100644 --- a/src/java/org/apache/poi/hssf/record/BoolErrRecord.java +++ b/src/java/org/apache/poi/hssf/record/BoolErrRecord.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,26 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - -/* - * BoolErrRecord.java - * - * Created on January 19, 2002, 9:30 AM - */ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; /** - * Creates new BoolErrRecord.

+ * Creates new BoolErrRecord. (0x0205)

* REFERENCE: PG ??? Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Michael P. Harhen * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ public final class BoolErrRecord extends Record implements CellValueRecordInterface { - public final static short sid = 0x205; + public final static short sid = 0x0205; private int field_1_row; private short field_2_column; private short field_3_xf_index; @@ -51,7 +45,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @param in the RecordInputstream to read the record from */ - public BoolErrRecord(RecordInputStream in) { super(in); @@ -60,7 +53,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf /** * @param in the RecordInputstream to read the record from */ - protected void fillFields(RecordInputStream in) { //field_1_row = LittleEndian.getShort(data, 0 + offset); @@ -71,7 +63,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf field_5_fError = in.readByte(); } - //public void setRow(short row) public void setRow(int row) { field_1_row = row; @@ -87,7 +78,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * @see org.apache.poi.hssf.record.ExtendedFormatRecord * @param xf index to the XF record */ - public void setXFIndex(short xf) { field_3_xf_index = xf; @@ -98,7 +88,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @param value representing the boolean value */ - public void setValue(boolean value) { field_4_bBoolErr = value ? ( byte ) 1 @@ -113,7 +102,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * this value can only be 0,7,15,23,29,36 or 42 * see bugzilla bug 16560 for an explanation */ - public void setValue(byte value) { if ( (value==0)||(value==7)||(value==15)||(value==23)||(value==29)||(value==36)||(value==42)) { @@ -124,7 +112,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf } } - //public short getRow() public int getRow() { return field_1_row; @@ -140,7 +127,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * @see org.apache.poi.hssf.record.ExtendedFormatRecord * @return index to the XF record */ - public short getXFIndex() { return field_3_xf_index; @@ -151,7 +137,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @return boolean representing the boolean value */ - public boolean getBooleanValue() { return (field_4_bBoolErr != 0); @@ -162,7 +147,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @return byte representing the error value */ - public byte getErrorValue() { return field_4_bBoolErr; @@ -173,7 +157,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @return boolean true if the cell holds a boolean value */ - public boolean isBoolean() { return (field_5_fError == ( byte ) 0); @@ -194,50 +177,40 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf public boolean isError() { - return (field_5_fError != ( byte ) 0); + return field_5_fError != 0; } public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - buffer.append("[BOOLERR]\n"); - buffer.append(" .row = ") - .append(Integer.toHexString(getRow())).append("\n"); - buffer.append(" .col = ") - .append(Integer.toHexString(getColumn())).append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - if (isBoolean()) - { - buffer.append(" .booleanValue = ").append(getBooleanValue()) - .append("\n"); - } - else - { - buffer.append(" .errorValue = ").append(getErrorValue()) - .append("\n"); + sb.append("[BOOLERR]\n"); + sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" .col = ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" .xfindex= ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + if (isBoolean()) { + sb.append(" .booleanValue = ").append(getBooleanValue()).append("\n"); + } else { + sb.append(" .errorValue = ").append(getErrorValue()).append("\n"); } - buffer.append("[/BOOLERR]\n"); - return buffer.toString(); + sb.append("[/BOOLERR]\n"); + return sb.toString(); } /** * 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. - * + * * @return byte array containing instance data */ - public int serialize(int offset, byte [] data) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 8); - //LittleEndian.putShort(data, 4 + offset, getRow()); - LittleEndian.putShort(data, 4 + offset, ( short ) getRow()); - LittleEndian.putShort(data, 6 + offset, getColumn()); - LittleEndian.putShort(data, 8 + offset, getXFIndex()); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, 8); + LittleEndian.putUShort(data, 4 + offset, getRow()); + LittleEndian.putUShort(data, 6 + offset, getColumn()); + LittleEndian.putUShort(data, 8 + offset, getXFIndex()); data[ 10 + offset ] = field_4_bBoolErr; data[ 11 + offset ] = field_5_fError; return getRecordSize(); @@ -254,7 +227,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf * * @param id alleged id for this record */ - protected void validateSid(short id) { if (id != BoolErrRecord.sid) @@ -268,16 +240,6 @@ public final class BoolErrRecord extends Record implements CellValueRecordInterf return sid; } - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; - } - public Object clone() { BoolErrRecord rec = new BoolErrRecord(); rec.field_1_row = field_1_row; diff --git a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java index cca4e6c652..e676d43120 100644 --- a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java +++ b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java @@ -420,6 +420,15 @@ public final class CFRuleRecord extends Record { { return field_17_formula1; } + public void setParsedExpression1(Ptg[] ptgs) { + field_17_formula1 = safeClone(ptgs); + } + private static Ptg[] safeClone(Ptg[] ptgs) { + if (ptgs == null) { + return null; + } + return (Ptg[]) ptgs.clone(); + } /** * get the stack of the 2nd expression as a list @@ -434,6 +443,9 @@ public final class CFRuleRecord extends Record { { return field_18_formula2; } + public void setParsedExpression2(Ptg[] ptgs) { + field_18_formula2 = safeClone(ptgs); + } /** * called by constructor, should throw runtime exception in the event of a diff --git a/src/java/org/apache/poi/hssf/record/DBCellRecord.java b/src/java/org/apache/poi/hssf/record/DBCellRecord.java index d14e689ed5..1aef298e1f 100644 --- a/src/java/org/apache/poi/hssf/record/DBCellRecord.java +++ b/src/java/org/apache/poi/hssf/record/DBCellRecord.java @@ -182,10 +182,6 @@ public final class DBCellRecord extends Record { return sid; } - public boolean isInValueSection() - { - return true; - } public Object clone() { // TODO - make immutable. // this should be safe because only the instantiating code mutates these objects diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index b9616e0db7..e4b599a0e9 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -406,14 +406,6 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf return 4 + getDataSize(); } - public boolean isInValueSection() { - return true; - } - - public boolean isValue() { - return true; - } - public String toString() { StringBuffer sb = new StringBuffer(); diff --git a/src/java/org/apache/poi/hssf/record/LabelRecord.java b/src/java/org/apache/poi/hssf/record/LabelRecord.java index ae3b82f36f..844d86a0c6 100644 --- a/src/java/org/apache/poi/hssf/record/LabelRecord.java +++ b/src/java/org/apache/poi/hssf/record/LabelRecord.java @@ -17,8 +17,10 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; + /** - * Label Record - read only support for strings stored directly in the cell.. Don't + * Label Record (0x0204) - read only support for strings stored directly in the cell.. Don't * use this (except to read), use LabelSST instead

* REFERENCE: PG 325 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) @@ -27,7 +29,7 @@ package org.apache.poi.hssf.record; * @see org.apache.poi.hssf.record.LabelSSTRecord */ public final class LabelRecord extends Record implements CellValueRecordInterface { - public final static short sid = 0x204; + public final static short sid = 0x0204; private int field_1_row; private short field_2_column; @@ -37,7 +39,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac private String field_6_value; /** Creates new LabelRecord */ - public LabelRecord() { } @@ -47,7 +48,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac * * @param in the RecordInputstream to read the record from */ - public LabelRecord(RecordInputStream in) { super(in); @@ -59,7 +59,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac * * @param id alleged id for this record */ - protected void validateSid(short id) { if (id != sid) @@ -71,7 +70,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac /** * @param in the RecordInputstream to read the record from */ - protected void fillFields(RecordInputStream in) { field_1_row = in.readUShort(); @@ -92,11 +90,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac /* * READ ONLY ACCESS... THIS IS FOR COMPATIBILITY ONLY...USE LABELSST! public - * void setRow(short row) { field_1_row = row; } - * - * public void setColumn(short col) { field_2_column = col; } - * - * public void setXFIndex(short index) { field_3_xf_index = index; } */ public int getRow() { @@ -117,7 +110,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac * get the number of characters this string contains * @return number of characters */ - public short getStringLength() { return field_4_string_len; @@ -127,7 +119,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac * is this uncompressed unicode (16bit)? Or just 8-bit compressed? * @return isUnicode - True for 16bit- false for 8bit */ - public boolean isUnCompressedUnicode() { return (field_5_unicode_flag == 1); @@ -139,7 +130,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac * @return the text string * @see #getStringLength() */ - public String getValue() { return field_6_value; @@ -148,7 +138,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac /** * THROWS A RUNTIME EXCEPTION.. USE LABELSSTRecords. YOU HAVE NO REASON to use LABELRecord!! */ - public int serialize(int offset, byte [] data) { throw new RecordFormatException( @@ -162,38 +151,21 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("[LABEL]\n"); - buffer.append(" .row = ") - .append(Integer.toHexString(getRow())).append("\n"); - buffer.append(" .column = ") - .append(Integer.toHexString(getColumn())).append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append(" .string_len = ") - .append(Integer.toHexString(field_4_string_len)).append("\n"); - buffer.append(" .unicode_flag = ") - .append(Integer.toHexString(field_5_unicode_flag)).append("\n"); - buffer.append(" .value = ") - .append(getValue()).append("\n"); - buffer.append("[/LABEL]\n"); - return buffer.toString(); - } - - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; + StringBuffer sb = new StringBuffer(); + sb.append("[LABEL]\n"); + sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" .xfindex = ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + sb.append(" .string_len= ").append(HexDump.shortToHex(field_4_string_len)).append("\n"); + sb.append(" .unicode_flag= ").append(HexDump.byteToHex(field_5_unicode_flag)).append("\n"); + sb.append(" .value = ").append(getValue()).append("\n"); + sb.append("[/LABEL]\n"); + return sb.toString(); } /** - * NO-OP! - */ - + * NO-OP! + */ public void setColumn(short col) { } @@ -201,8 +173,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac /** * NO-OP! */ - - //public void setRow(short row) public void setRow(int row) { } @@ -210,7 +180,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac /** * no op! */ - public void setXFIndex(short xf) { } diff --git a/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java b/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java index a8d68bac2c..92b3436d36 100644 --- a/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java +++ b/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java @@ -17,6 +17,7 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; /** @@ -30,10 +31,10 @@ import org.apache.poi.util.LittleEndian; */ public final class LabelSSTRecord extends Record implements CellValueRecordInterface { public final static short sid = 0xfd; - private int field_1_row; - private short field_2_column; - private short field_3_xf_index; - private int field_4_sst_index; + private int field_1_row; + private int field_2_column; + private int field_3_xf_index; + private int field_4_sst_index; public LabelSSTRecord() { @@ -43,7 +44,6 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter * Constructs an LabelSST record and sets its fields appropriately. * @param in the RecordInputstream to read the record from */ - public LabelSSTRecord(RecordInputStream in) { super(in); @@ -60,14 +60,12 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter protected void fillFields(RecordInputStream in) { - //field_1_row = LittleEndian.getShort(data, 0 + offset); field_1_row = in.readUShort(); - field_2_column = in.readShort(); - field_3_xf_index = in.readShort(); + field_2_column = in.readUShort(); + field_3_xf_index = in.readUShort(); field_4_sst_index = in.readInt(); } - //public void setRow(short row) public void setRow(int row) { field_1_row = row; @@ -102,7 +100,6 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter field_4_sst_index = index; } - //public short getRow() public int getRow() { return field_1_row; @@ -110,7 +107,7 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter public short getColumn() { - return field_2_column; + return (short)field_2_column; } /** @@ -122,7 +119,7 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter public short getXFIndex() { - return field_3_xf_index; + return (short)field_3_xf_index; } /** @@ -139,29 +136,24 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - buffer.append("[LABELSST]\n"); - buffer.append(" .row = ") - .append(Integer.toHexString(getRow())).append("\n"); - buffer.append(" .column = ") - .append(Integer.toHexString(getColumn())).append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append(" .sstindex = ") - .append(Integer.toHexString(getSSTIndex())).append("\n"); - buffer.append("[/LABELSST]\n"); - return buffer.toString(); + sb.append("[LABELSST]\n"); + sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" .xfindex = ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + sb.append(" .sstindex= ").append(HexDump.intToHex(getSSTIndex())).append("\n"); + sb.append("[/LABELSST]\n"); + return sb.toString(); } public int serialize(int offset, byte [] data) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 10); - //LittleEndian.putShort(data, 4 + offset, getRow()); - LittleEndian.putShort(data, 4 + offset, ( short )getRow()); - LittleEndian.putShort(data, 6 + offset, getColumn()); - LittleEndian.putShort(data, 8 + offset, getXFIndex()); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, 10); + LittleEndian.putUShort(data, 4 + offset, getRow()); + LittleEndian.putUShort(data, 6 + offset, getColumn()); + LittleEndian.putUShort(data, 8 + offset, getXFIndex()); LittleEndian.putInt(data, 10 + offset, getSSTIndex()); return getRecordSize(); } @@ -176,16 +168,6 @@ public final class LabelSSTRecord extends Record implements CellValueRecordInter return sid; } - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; - } - public Object clone() { LabelSSTRecord rec = new LabelSSTRecord(); rec.field_1_row = field_1_row; diff --git a/src/java/org/apache/poi/hssf/record/NumberRecord.java b/src/java/org/apache/poi/hssf/record/NumberRecord.java index eeb5cf62ad..f3d906155c 100644 --- a/src/java/org/apache/poi/hssf/record/NumberRecord.java +++ b/src/java/org/apache/poi/hssf/record/NumberRecord.java @@ -17,22 +17,23 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; import org.apache.poi.hssf.record.Record; /** - * Contains a numeric cell value.

+ * NUMBER (0x0203) Contains a numeric cell value.

* REFERENCE: PG 334 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ public final class NumberRecord extends Record implements CellValueRecordInterface { - public static final short sid = 0x203; - private int field_1_row; - private short field_2_col; - private short field_3_xf; - private double field_4_value; + public static final short sid = 0x0203; + private int field_1_row; + private int field_2_col; + private int field_3_xf; + private double field_4_value; /** Creates new NumberRecord */ public NumberRecord() @@ -44,7 +45,6 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa * * @param in the RecordInputstream to read the record from */ - public NumberRecord(RecordInputStream in) { super(in); @@ -53,17 +53,14 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa /** * @param in the RecordInputstream to read the record from */ - protected void fillFields(RecordInputStream in) { - //field_1_row = LittleEndian.getShort(data, 0 + offset); field_1_row = in.readUShort(); - field_2_col = in.readShort(); - field_3_xf = in.readShort(); + field_2_col = in.readUShort(); + field_3_xf = in.readUShort(); field_4_value = in.readDouble(); } - //public void setRow(short row) public void setRow(int row) { field_1_row = row; @@ -79,7 +76,6 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa * @see org.apache.poi.hssf.record.ExtendedFormatRecord * @param xf index to the XF record */ - public void setXFIndex(short xf) { field_3_xf = xf; @@ -90,13 +86,11 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa * * @param value double representing the value */ - public void setValue(double value) { field_4_value = value; } - //public short getRow() public int getRow() { return field_1_row; @@ -104,7 +98,7 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa public short getColumn() { - return field_2_col; + return (short)field_2_col; } /** @@ -112,10 +106,9 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa * @see org.apache.poi.hssf.record.ExtendedFormatRecord * @return index to the XF record */ - public short getXFIndex() { - return field_3_xf; + return (short)field_3_xf; } /** @@ -123,7 +116,6 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa * * @return double representing the value */ - public double getValue() { return field_4_value; @@ -131,37 +123,31 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - buffer.append("[NUMBER]\n"); - buffer.append(" .row = ") - .append(Integer.toHexString(getRow())).append("\n"); - buffer.append(" .col = ") - .append(Integer.toHexString(getColumn())).append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append(" .value = ").append(getValue()) - .append("\n"); - buffer.append("[/NUMBER]\n"); - return buffer.toString(); + sb.append("[NUMBER]\n"); + sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" .col = ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" .xfindex= ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + sb.append(" .value = ").append(getValue()).append("\n"); + sb.append("[/NUMBER]\n"); + return sb.toString(); } /** * 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. - * + * * @return byte array containing instance data */ - public int serialize(int offset, byte [] data) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 14); - //LittleEndian.putShort(data, 4 + offset, getRow()); - LittleEndian.putShort(data, 4 + offset, ( short ) getRow()); - LittleEndian.putShort(data, 6 + offset, getColumn()); - LittleEndian.putShort(data, 8 + offset, getXFIndex()); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, 14); + LittleEndian.putUShort(data, 4 + offset, getRow()); + LittleEndian.putUShort(data, 6 + offset, getColumn()); + LittleEndian.putUShort(data, 8 + offset, getXFIndex()); LittleEndian.putDouble(data, 10 + offset, getValue()); return getRecordSize(); } @@ -191,16 +177,6 @@ public final class NumberRecord extends Record implements CellValueRecordInterfa return sid; } - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; - } - public Object clone() { NumberRecord rec = new NumberRecord(); rec.field_1_row = field_1_row; diff --git a/src/java/org/apache/poi/hssf/record/RKRecord.java b/src/java/org/apache/poi/hssf/record/RKRecord.java index 2a99e16047..ce9c84c6ec 100644 --- a/src/java/org/apache/poi/hssf/record/RKRecord.java +++ b/src/java/org/apache/poi/hssf/record/RKRecord.java @@ -18,9 +18,10 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.util.RKUtil; +import org.apache.poi.util.HexDump; /** - * Title: RK Record + * Title: RK Record (0x027E) * Description: An internal 32 bit number with the two most significant bits * storing the type. This is part of a bizarre scheme to save disk * space and memory (gee look at all the other whole records that @@ -37,15 +38,15 @@ import org.apache.poi.hssf.util.RKUtil; * @see org.apache.poi.hssf.record.NumberRecord */ public final class RKRecord extends Record implements CellValueRecordInterface { - public final static short sid = 0x27e; + public final static short sid = 0x027E; public final static short RK_IEEE_NUMBER = 0; public final static short RK_IEEE_NUMBER_TIMES_100 = 1; public final static short RK_INTEGER = 2; public final static short RK_INTEGER_TIMES_100 = 3; - private int field_1_row; - private short field_2_col; - private short field_3_xf_index; - private int field_4_rk_number; + private int field_1_row; + private int field_2_col; + private int field_3_xf_index; + private int field_4_rk_number; public RKRecord() { @@ -55,7 +56,6 @@ public final class RKRecord extends Record implements CellValueRecordInterface { * Constructs a RK record and sets its fields appropriately. * @param in the RecordInputstream to read the record from */ - public RKRecord(RecordInputStream in) { super(in); @@ -71,14 +71,12 @@ public final class RKRecord extends Record implements CellValueRecordInterface { protected void fillFields(RecordInputStream in) { - //field_1_row = LittleEndian.getShort(data, 0 + offset); field_1_row = in.readUShort(); - field_2_col = in.readShort(); - field_3_xf_index = in.readShort(); + field_2_col = in.readUShort(); + field_3_xf_index = in.readUShort(); field_4_rk_number = in.readInt(); } - //public short getRow() public int getRow() { return field_1_row; @@ -86,12 +84,12 @@ public final class RKRecord extends Record implements CellValueRecordInterface { public short getColumn() { - return field_2_col; + return (short) field_2_col; } public short getXFIndex() { - return field_3_xf_index; + return (short) field_3_xf_index; } public int getRKField() @@ -110,7 +108,6 @@ public final class RKRecord extends Record implements CellValueRecordInterface { *

  • RK_INTEGER_TIMES_100
  • * */ - public short getRKType() { return ( short ) (field_4_rk_number & 3); @@ -133,7 +130,6 @@ public final class RKRecord extends Record implements CellValueRecordInterface { * @return the value as a proper double (hey, it could * happen) */ - public double getRKNumber() { return RKUtil.decodeNumber(field_4_rk_number); @@ -142,26 +138,20 @@ public final class RKRecord extends Record implements CellValueRecordInterface { public String toString() { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[RK]\n"); - buffer.append(" .row = ") - .append(Integer.toHexString(getRow())).append("\n"); - buffer.append(" .col = ") - .append(Integer.toHexString(getColumn())).append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append(" .rknumber = ") - .append(Integer.toHexString(getRKField())).append("\n"); - buffer.append(" .rktype = ") - .append(Integer.toHexString(getRKType())).append("\n"); - buffer.append(" .rknumber = ").append(getRKNumber()) - .append("\n"); - buffer.append("[/RK]\n"); - return buffer.toString(); - } - -//temporarily just constructs a new number record and returns its value + StringBuffer sb = new StringBuffer(); + + sb.append("[RK]\n"); + sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n"); + sb.append(" .col = ").append(HexDump.shortToHex(getColumn())).append("\n"); + sb.append(" .xfindex = ").append(HexDump.shortToHex(getXFIndex())).append("\n"); + sb.append(" .rknumber = ").append(HexDump.intToHex(getRKField())).append("\n"); + sb.append(" .rktype = ").append(HexDump.byteToHex(getRKType())).append("\n"); + sb.append(" .rknumber= ").append(getRKNumber()).append("\n"); + sb.append("[/RK]\n"); + return sb.toString(); + } + +// temporarily just constructs a new number record and returns its value public int serialize(int offset, byte [] data) { NumberRecord rec = new NumberRecord(); @@ -209,21 +199,10 @@ public final class RKRecord extends Record implements CellValueRecordInterface { return sid; } - public boolean isInValueSection() - { - return true; - } - - public boolean isValue() - { - return true; - } - public void setColumn(short col) { } - //public void setRow(short row) public void setRow(int row) { } diff --git a/src/java/org/apache/poi/hssf/record/Record.java b/src/java/org/apache/poi/hssf/record/Record.java index 3af38601ff..c33da57deb 100644 --- a/src/java/org/apache/poi/hssf/record/Record.java +++ b/src/java/org/apache/poi/hssf/record/Record.java @@ -98,24 +98,6 @@ public abstract class Record extends RecordBase { return serialize().length; } - /** - * tells whether this type of record contains a value - */ - - public boolean isValue() - { - return false; - } - - /** - * DBCELL, ROW, VALUES all say yes - */ - - public boolean isInValueSection() - { - return false; - } - /** * get a string representation of the record (for biffview/debugging) */ diff --git a/src/java/org/apache/poi/hssf/record/RowRecord.java b/src/java/org/apache/poi/hssf/record/RowRecord.java index 2ef8763984..8b49523a86 100644 --- a/src/java/org/apache/poi/hssf/record/RowRecord.java +++ b/src/java/org/apache/poi/hssf/record/RowRecord.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; /** @@ -29,7 +30,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ -public final class RowRecord extends Record implements Comparable { +public final class RowRecord extends Record { public final static short sid = 0x0208; public static final int ENCODED_SIZE = 20; @@ -77,7 +78,6 @@ public final class RowRecord extends Record implements Comparable { * Constructs a Row record and sets its fields appropriately. * @param in the RecordInputstream to read the record from */ - public RowRecord(RecordInputStream in) { super(in); @@ -107,8 +107,6 @@ public final class RowRecord extends Record implements Comparable { * set the logical row number for this row (0 based index) * @param row - the row number */ - - //public void setRowNumber(short row) public void setRowNumber(int row) { field_1_row_number = row; @@ -118,7 +116,6 @@ public final class RowRecord extends Record implements Comparable { * set the logical col number for the first cell this row (0 based index) * @param col - the col number */ - public void setFirstCol(short col) { field_2_first_col = col; @@ -128,7 +125,6 @@ public final class RowRecord extends Record implements Comparable { * set the logical col number for the last cell this row (0 based index) * @param col - the col number */ - public void setLastCol(short col) { field_3_last_col = col; @@ -138,7 +134,6 @@ public final class RowRecord extends Record implements Comparable { * set the height of the row * @param height of the row */ - public void setHeight(short height) { field_4_height = height; @@ -148,31 +143,17 @@ public final class RowRecord extends Record implements Comparable { * set whether to optimize or not (set to 0) * @param optimize (set to 0) */ - public void setOptimize(short optimize) { field_5_optimize = optimize; } - /** - * sets the option bitmask. (use the individual bit setters that refer to this - * method) - * @param options - the bitmask - */ - - public void setOptionFlags(short options) - { - field_7_option_flags = options | OPTION_BITS_ALWAYS_SET; - } - // option bitfields /** * set the outline level of this row * @param ol - the outline level - * @see #setOptionFlags(short) */ - public void setOutlineLevel(short ol) { field_7_option_flags = outlineLevel.setValue(field_7_option_flags, ol); @@ -181,9 +162,7 @@ public final class RowRecord extends Record implements Comparable { /** * set whether or not to collapse this row * @param c - collapse or not - * @see #setOptionFlags(short) */ - public void setColapsed(boolean c) { field_7_option_flags = colapsed.setBoolean(field_7_option_flags, c); @@ -192,9 +171,7 @@ public final class RowRecord extends Record implements Comparable { /** * set whether or not to display this row with 0 height * @param z height is zero or not. - * @see #setOptionFlags(short) */ - public void setZeroHeight(boolean z) { field_7_option_flags = zeroHeight.setBoolean(field_7_option_flags, z); @@ -203,9 +180,7 @@ public final class RowRecord extends Record implements Comparable { /** * set whether the font and row height are not compatible * @param f true if they aren't compatible (damn not logic) - * @see #setOptionFlags(short) */ - public void setBadFontHeight(boolean f) { field_7_option_flags = badFontHeight.setBoolean(field_7_option_flags, f); @@ -214,9 +189,7 @@ public final class RowRecord extends Record implements Comparable { /** * set whether the row has been formatted (even if its got all blank cells) * @param f formatted or not - * @see #setOptionFlags(short) */ - public void setFormatted(boolean f) { field_7_option_flags = formatted.setBoolean(field_7_option_flags, f); @@ -229,7 +202,6 @@ public final class RowRecord extends Record implements Comparable { * @see org.apache.poi.hssf.record.ExtendedFormatRecord * @param index to the XF record */ - public void setXFIndex(short index) { field_8_xf_index = index; @@ -239,8 +211,6 @@ public final class RowRecord extends Record implements Comparable { * get the logical row number for this row (0 based index) * @return row - the row number */ - - //public short getRowNumber() public int getRowNumber() { return field_1_row_number; @@ -250,7 +220,6 @@ public final class RowRecord extends Record implements Comparable { * get the logical col number for the first cell this row (0 based index) * @return col - the col number */ - public short getFirstCol() { return field_2_first_col; @@ -260,7 +229,6 @@ public final class RowRecord extends Record implements Comparable { * get the logical col number for the last cell this row plus one (0 based index) * @return col - the last col number + 1 */ - public short getLastCol() { return field_3_last_col; @@ -270,7 +238,6 @@ public final class RowRecord extends Record implements Comparable { * get the height of the row * @return height of the row */ - public short getHeight() { return field_4_height; @@ -280,7 +247,6 @@ public final class RowRecord extends Record implements Comparable { * get whether to optimize or not (set to 0) * @return optimize (set to 0) */ - public short getOptimize() { return field_5_optimize; @@ -291,7 +257,6 @@ public final class RowRecord extends Record implements Comparable { * method) * @return options - the bitmask */ - public short getOptionFlags() { return (short)field_7_option_flags; @@ -304,7 +269,6 @@ public final class RowRecord extends Record implements Comparable { * @return ol - the outline level * @see #getOptionFlags() */ - public short getOutlineLevel() { return (short)outlineLevel.getValue(field_7_option_flags); @@ -315,7 +279,6 @@ public final class RowRecord extends Record implements Comparable { * @return c - colapse or not * @see #getOptionFlags() */ - public boolean getColapsed() { return (colapsed.isSet(field_7_option_flags)); @@ -326,7 +289,6 @@ public final class RowRecord extends Record implements Comparable { * @return - z height is zero or not. * @see #getOptionFlags() */ - public boolean getZeroHeight() { return zeroHeight.isSet(field_7_option_flags); @@ -367,44 +329,27 @@ public final class RowRecord extends Record implements Comparable { return field_8_xf_index; } - public boolean isInValueSection() - { - return true; - } - public String toString() { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[ROW]\n"); - buffer.append(" .rownumber = ") - .append(Integer.toHexString(getRowNumber())).append("\n"); - buffer.append(" .firstcol = ") - .append(Integer.toHexString(getFirstCol())).append("\n"); - buffer.append(" .lastcol = ") - .append(Integer.toHexString(getLastCol())).append("\n"); - buffer.append(" .height = ") - .append(Integer.toHexString(getHeight())).append("\n"); - buffer.append(" .optimize = ") - .append(Integer.toHexString(getOptimize())).append("\n"); - buffer.append(" .reserved = ") - .append(Integer.toHexString(field_6_reserved)).append("\n"); - buffer.append(" .optionflags = ") - .append(Integer.toHexString(getOptionFlags())).append("\n"); - buffer.append(" .outlinelvl = ") - .append(Integer.toHexString(getOutlineLevel())).append("\n"); - buffer.append(" .colapsed = ").append(getColapsed()) - .append("\n"); - buffer.append(" .zeroheight = ").append(getZeroHeight()) - .append("\n"); - buffer.append(" .badfontheig= ").append(getBadFontHeight()) - .append("\n"); - buffer.append(" .formatted = ").append(getFormatted()) - .append("\n"); - buffer.append(" .xfindex = ") - .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append("[/ROW]\n"); - return buffer.toString(); + StringBuffer sb = new StringBuffer(); + + sb.append("[ROW]\n"); + sb.append(" .rownumber = ").append(Integer.toHexString(getRowNumber())) + .append("\n"); + sb.append(" .firstcol = ").append(HexDump.shortToHex(getFirstCol())).append("\n"); + sb.append(" .lastcol = ").append(HexDump.shortToHex(getLastCol())).append("\n"); + sb.append(" .height = ").append(HexDump.shortToHex(getHeight())).append("\n"); + sb.append(" .optimize = ").append(HexDump.shortToHex(getOptimize())).append("\n"); + sb.append(" .reserved = ").append(HexDump.shortToHex(field_6_reserved)).append("\n"); + sb.append(" .optionflags = ").append(HexDump.shortToHex(getOptionFlags())).append("\n"); + sb.append(" .outlinelvl = ").append(Integer.toHexString(getOutlineLevel())).append("\n"); + sb.append(" .colapsed = ").append(getColapsed()).append("\n"); + sb.append(" .zeroheight = ").append(getZeroHeight()).append("\n"); + sb.append(" .badfontheig= ").append(getBadFontHeight()).append("\n"); + sb.append(" .formatted = ").append(getFormatted()).append("\n"); + sb.append(" .xfindex = ").append(Integer.toHexString(getXFIndex())).append("\n"); + sb.append("[/ROW]\n"); + return sb.toString(); } public int serialize(int offset, byte [] data) @@ -433,40 +378,6 @@ public final class RowRecord extends Record implements Comparable { return sid; } - public int compareTo(Object obj) - { - RowRecord loc = ( RowRecord ) obj; - - if (this.getRowNumber() == loc.getRowNumber()) - { - return 0; - } - if (this.getRowNumber() < loc.getRowNumber()) - { - return -1; - } - if (this.getRowNumber() > loc.getRowNumber()) - { - return 1; - } - return -1; - } - - public boolean equals(Object obj) - { - if (!(obj instanceof RowRecord)) - { - return false; - } - RowRecord loc = ( RowRecord ) obj; - - if (this.getRowNumber() == loc.getRowNumber()) - { - return true; - } - return false; - } - public Object clone() { RowRecord rec = new RowRecord(field_1_row_number); rec.field_2_first_col = field_2_first_col; diff --git a/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java b/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java index d2cd4c0e43..16a73d0a81 100644 --- a/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java +++ b/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java @@ -115,20 +115,4 @@ public abstract class SharedValueRecordBase extends Record { CellRangeAddress8Bit r = getRange(); return r.getFirstRow() == rowIx && r.getFirstColumn() == colIx; } - - /** - * Mirroring formula records so it is registered in the - * ValueRecordsAggregate - */ - public final boolean isInValueSection() { - return true; - } - - /** - * Register it in the ValueRecordsAggregate so it can go into the - * FormulaRecordAggregate - */ - public final boolean isValue() { - return true; - } } diff --git a/src/java/org/apache/poi/hssf/record/StringRecord.java b/src/java/org/apache/poi/hssf/record/StringRecord.java index b3a42aaba4..d7eb11efcf 100644 --- a/src/java/org/apache/poi/hssf/record/StringRecord.java +++ b/src/java/org/apache/poi/hssf/record/StringRecord.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,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; @@ -23,14 +21,12 @@ import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; /** - * Supports the STRING record structure. + * Supports the STRING record structure. (0x0207) * * @author Glen Stampoultzis (glens at apache.org) */ -public class StringRecord - extends Record -{ - public final static short sid = 0x207; +public class StringRecord extends Record { + public final static short sid = 0x0207; private int field_1_string_length; private byte field_2_unicode_flag; private String field_3_string; @@ -73,7 +69,7 @@ public class StringRecord field_1_string_length = in.readShort(); field_2_unicode_flag = in.readByte(); byte[] data = in.readRemainder(); - //Why isnt this using the in.readString methods??? + //Why isn't this using the in.readString methods??? if (isUnCompressedUnicode()) { field_3_string = StringUtil.getFromUnicodeLE(data, 0, field_1_string_length ); @@ -92,11 +88,6 @@ public class StringRecord } } - public boolean isInValueSection() - { - return true; - } - private int getStringByteLength() { return isUnCompressedUnicode() ? field_1_string_length * 2 : field_1_string_length; @@ -130,8 +121,8 @@ public class StringRecord */ public int serialize( int offset, byte[] data ) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) (3 + getStringByteLength())); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, 3 + getStringByteLength()); LittleEndian.putUShort(data, 4 + offset, field_1_string_length); data[6 + offset] = field_2_unicode_flag; if (isUnCompressedUnicode()) @@ -180,8 +171,6 @@ public class StringRecord setCompressedFlag(StringUtil.hasMultibyte(string) ? (byte)1 : (byte)0); } - - public String toString() { StringBuffer buffer = new StringBuffer(); @@ -199,7 +188,5 @@ public class StringRecord rec.field_2_unicode_flag= this.field_2_unicode_flag; rec.field_3_string = this.field_3_string; return rec; - } - } 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 d3a3a673e0..b9e4d833ba 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java @@ -24,7 +24,10 @@ 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.ss.util.Region; +import org.apache.poi.hssf.record.formula.AreaErrPtg; +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.hssf.record.formula.FormulaShifter; +import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.ss.util.CellRangeAddress; /** @@ -175,4 +178,68 @@ public final class CFRecordsAggregate extends RecordAggregate { rv.visitRecord(rule); } } + + /** + * @return false if this whole {@link CFHeaderRecord} / {@link CFRuleRecord}s should be deleted + */ + public boolean updateFormulasAfterCellShift(FormulaShifter shifter, int currentExternSheetIx) { + CellRangeAddress[] cellRanges = header.getCellRanges(); + boolean changed = false; + List temp = new ArrayList(); + for (int i = 0; i < cellRanges.length; i++) { + CellRangeAddress craOld = cellRanges[i]; + CellRangeAddress craNew = shiftRange(shifter, craOld, currentExternSheetIx); + if (craNew == null) { + changed = true; + continue; + } + temp.add(craNew); + if (craNew != craOld) { + changed = true; + } + } + + if (changed) { + int nRanges = temp.size(); + if (nRanges == 0) { + return false; + } + CellRangeAddress[] newRanges = new CellRangeAddress[nRanges]; + temp.toArray(newRanges); + header.setCellRanges(newRanges); + } + + for(int i=0; i @@ -85,4 +86,15 @@ public final class ConditionalFormattingTable extends RecordAggregate { + " is outside the allowable range (0.." + (_cfHeaders.size() - 1) + ")"); } } + + public void updateFormulasAfterCellShift(FormulaShifter shifter, int externSheetIndex) { + for (int i = 0; i < _cfHeaders.size(); i++) { + CFRecordsAggregate subAgg = (CFRecordsAggregate) _cfHeaders.get(i); + boolean shouldKeep = subAgg.updateFormulasAfterCellShift(shifter, externSheetIndex); + if (!shouldKeep) { + _cfHeaders.remove(i); + i--; + } + } + } } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java index 06bb53a38d..2e86b13821 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java @@ -47,12 +47,12 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel } boolean hasStringRec = stringRec != null; boolean hasCachedStringFlag = formulaRec.hasCachedResultString(); - if (hasStringRec != hasCachedStringFlag) { - throw new RecordFormatException("String record was " - + (hasStringRec ? "": "not ") + " supplied but formula record flag is " - + (hasCachedStringFlag ? "" : "not ") + " set"); - } - + if (hasStringRec != hasCachedStringFlag) { + throw new RecordFormatException("String record was " + + (hasStringRec ? "": "not ") + " supplied but formula record flag is " + + (hasCachedStringFlag ? "" : "not ") + " set"); + } + if (formulaRec.isSharedFormula()) { svm.convertSharedFormulaRecord(formulaRec); } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java index c7610de1ea..cfa6afc77e 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -83,7 +83,7 @@ public final class RowRecordsAggregate extends RecordAggregate { // might need to keep track of where exactly these belong continue; } - if (!rec.isValue()) { + if (!(rec instanceof CellValueRecordInterface)) { throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")"); } _valuesAgg.construct((CellValueRecordInterface)rec, rs, svm); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index dead7cabfc..75568f4dad 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -1278,7 +1278,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet int sheetIndex = workbook.getSheetIndex(this); short externSheetIndex = book.checkExternSheet(sheetIndex); FormulaShifter shifter = FormulaShifter.createForRowShift(externSheetIndex, startRow, endRow, n); - sheet.getRowsAggregate().updateFormulasAfterRowShift(shifter, externSheetIndex); + sheet.updateFormulasAfterCellShift(shifter, externSheetIndex); int nSheets = workbook.getNumberOfSheets(); for(int i=0; iCellRangeAddress instead of Region @@ -134,7 +135,7 @@ public final class HSSFSheetConditionalFormatting { rules[i] = cfRules[i].getCfRuleRecord(); } CFRecordsAggregate cfra = new CFRecordsAggregate(regions, rules); - return _sheet.addConditionalFormatting(cfra); + return _conditionalFormattingTable.add(cfra); } public int addConditionalFormatting(CellRangeAddress[] regions, @@ -166,7 +167,7 @@ public final class HSSFSheetConditionalFormatting { * @return Conditional Formatting object */ public HSSFConditionalFormatting getConditionalFormattingAt(int index) { - CFRecordsAggregate cf = _sheet.getCFRecordsAggregateAt(index); + CFRecordsAggregate cf = _conditionalFormattingTable.get(index); if (cf == null) { return null; } @@ -177,7 +178,7 @@ public final class HSSFSheetConditionalFormatting { * @return number of Conditional Formatting objects of the sheet */ public int getNumConditionalFormattings() { - return _sheet.getNumConditionalFormattings(); + return _conditionalFormattingTable.size(); } /** @@ -185,6 +186,6 @@ public final class HSSFSheetConditionalFormatting { * @param index of a Conditional Formatting object to remove */ public void removeConditionalFormatting(int index) { - _sheet.removeConditionalFormatting(index); + _conditionalFormattingTable.remove(index); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 22043fa6d6..aa0b720132 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -33,6 +33,7 @@ import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBitmapBlip; import org.apache.poi.ddf.EscherBlipRecord; import org.apache.poi.ddf.EscherRecord; +import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.AbstractEscherHolderRecord; @@ -277,10 +278,9 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm // convert all LabelRecord records to LabelSSTRecord convertLabelRecords(records, recOffset); - while (recOffset < records.size()) { - Sheet sheet = Sheet.createSheet(records, sheetNum++, recOffset ); - - recOffset = sheet.getEofLoc()+1; // TODO - use better technique to keep track of the used records + RecordStream rs = new RecordStream(records, recOffset); + while (rs.hasNext()) { + Sheet sheet = Sheet.createSheet(rs); _sheets.add(new HSSFSheet(this, sheet)); } diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index 3bc79299b5..f19af7cb31 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -56,6 +56,11 @@ import org.apache.poi.hssf.util.CellRangeAddress; * @author Glen Stampoultzis (glens at apache.org) */ public final class TestSheet extends TestCase { + private static Sheet createSheet(List inRecs) { + return Sheet.createSheet(new RecordStream(inRecs, 0)); + } + + public void testCreateSheet() { // Check we're adding row and cell aggregates List records = new ArrayList(); @@ -63,7 +68,7 @@ public final class TestSheet extends TestCase { records.add( new DimensionsRecord() ); records.add(createWindow2Record()); records.add(EOFRecord.instance); - Sheet sheet = Sheet.createSheet( records, 0, 0 ); + Sheet sheet = createSheet(records); int pos = 0; assertTrue( sheet.records.get(pos++) instanceof BOFRecord ); @@ -187,7 +192,7 @@ public final class TestSheet extends TestCase { records.add(EOFRecord.instance); records.add(merged); - Sheet sheet = Sheet.createSheet(records, 0); + Sheet sheet = createSheet(records); sheet.records.remove(0); //stub object to throw off list INDEX operations @@ -222,7 +227,7 @@ public final class TestSheet extends TestCase { records.add(createWindow2Record()); records.add(EOFRecord.instance); - Sheet sheet = Sheet.createSheet(records, 0); + Sheet sheet = createSheet(records); assertNotNull("Row [2] was skipped", sheet.getRow(2)); } @@ -446,7 +451,7 @@ public final class TestSheet extends TestCase { records.add(new DimensionsRecord()); records.add(createWindow2Record()); records.add(EOFRecord.instance); - Sheet sheet = Sheet.createSheet(records, 0, 0); + Sheet sheet = createSheet(records); // The original bug was due to different logic for collecting records for sizing and // serialization. The code has since been refactored into a single method for visiting diff --git a/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java b/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java index 7a9acb087b..e55876e6f6 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java @@ -82,11 +82,9 @@ public final class TestExternalNameRecord extends TestCase { assertTrue(enr.isAutomaticLink()); assertFalse(enr.isBuiltInName()); assertFalse(enr.isIconifiedPictureLink()); - assertFalse(enr.isInValueSection()); assertFalse(enr.isOLELink()); assertFalse(enr.isPicureLink()); assertTrue(enr.isStdDocumentNameIdentifier()); - assertFalse(enr.isValue()); TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataAutoDocName, enr.serialize()); } @@ -98,11 +96,9 @@ public final class TestExternalNameRecord extends TestCase { assertFalse(enr.isAutomaticLink()); assertFalse(enr.isBuiltInName()); assertFalse(enr.isIconifiedPictureLink()); - assertFalse(enr.isInValueSection()); assertFalse(enr.isOLELink()); assertFalse(enr.isPicureLink()); assertFalse(enr.isStdDocumentNameIdentifier()); - assertFalse(enr.isValue()); TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataPlainName, enr.serialize()); } diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java index 5e2fdab49e..c62f725238 100755 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java @@ -65,7 +65,7 @@ public final class TestValueRecordsAggregate extends TestCase { } private void constructValueRecord(List records) { - RowBlocksReader rbr = new RowBlocksReader(records, 0); + RowBlocksReader rbr = new RowBlocksReader(new RecordStream(records, 0)); SharedValueManager sfrh = rbr.getSharedFormulaManager(); RecordStream rs = rbr.getPlainRecordStream(); while(rs.hasNext()) { diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java index f9e62ffbf9..5d0416fc7c 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java @@ -29,10 +29,8 @@ import org.apache.poi.ss.util.Region; * * @author Dmitriy Kumshayev */ -public final class TestHSSFConditionalFormatting extends TestCase -{ - public void testCreateCF() - { +public final class TestHSSFConditionalFormatting extends TestCase { + public void testCreateCF() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); String formula = "7"; @@ -150,4 +148,44 @@ public final class TestHSSFConditionalFormatting extends TestCase } assertEquals(2, wb.getNumberOfSheets()); } + + public void testShiftRows() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFSheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting(); + + HSSFConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule( + ComparisonOperator.BETWEEN, "sum(A10:A15)", "1+sum(B16:B30)"); + HSSFFontFormatting fontFmt = rule1.createFontFormatting(); + fontFmt.setFontStyle(true, false); + + HSSFPatternFormatting patternFmt = rule1.createPatternFormatting(); + patternFmt.setFillBackgroundColor(HSSFColor.YELLOW.index); + HSSFConditionalFormattingRule [] cfRules = { rule1, }; + + CellRangeAddress [] regions = { + new CellRangeAddress(2, 4, 0, 0), // A3:A5 + }; + sheetCF.addConditionalFormatting(regions, cfRules); + + // This row-shift should destroy the CF region + sheet.shiftRows(10, 20, -9); + assertEquals(0, sheetCF.getNumConditionalFormattings()); + + // re-add the CF + sheetCF.addConditionalFormatting(regions, cfRules); + + // This row shift should only affect the formulas + sheet.shiftRows(14, 17, 8); + HSSFConditionalFormatting cf = sheetCF.getConditionalFormattingAt(0); + assertEquals("SUM(A10:A23)", cf.getRule(0).getFormula1()); + assertEquals("1+SUM(B24:B30)", cf.getRule(0).getFormula2()); + + sheet.shiftRows(0, 8, 21); + cf = sheetCF.getConditionalFormattingAt(0); + assertEquals("SUM(A10:A21)", cf.getRule(0).getFormula1()); + assertEquals("1+SUM(#REF!)", cf.getRule(0).getFormula2()); + } } -- 2.39.5