diff --git a/build.xml b/build.xml index dab532f48..abece8810 100644 --- a/build.xml +++ b/build.xml @@ -459,7 +459,8 @@ under the License. fork="yes" srcdir="${scratchpad.src.test}"> - + + @@ -694,6 +695,7 @@ under the License. + diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index 175b92088..15177d0d9 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -129,6 +129,8 @@ public final class BiffViewer { case BoolErrRecord.sid: return new BoolErrRecord(in); case BottomMarginRecord.sid: return new BottomMarginRecord(in); case BoundSheetRecord.sid: return new BoundSheetRecord(in); + case CFHeaderRecord.sid: return new CFHeaderRecord(in); + case CFRuleRecord.sid: return new CFRuleRecord(in); case CalcCountRecord.sid: return new CalcCountRecord(in); case CalcModeRecord.sid: return new CalcModeRecord(in); case CategorySeriesAxisRecord.sid: return new CategorySeriesAxisRecord(in); @@ -288,10 +290,10 @@ public final class BiffViewer { } PrintStream ps; if (false) { // set to true to output to file - OutputStream os = new FileOutputStream(inFileName + ".out"); - ps = new PrintStream(os); + OutputStream os = new FileOutputStream(inFileName + ".out"); + ps = new PrintStream(os); } else { - ps = System.out; + ps = System.out; } BiffViewer viewer = new BiffViewer(inputFile, ps); diff --git a/src/java/org/apache/poi/hssf/model/RecordOrderer.java b/src/java/org/apache/poi/hssf/model/RecordOrderer.java new file mode 100644 index 000000000..ae445597d --- /dev/null +++ b/src/java/org/apache/poi/hssf/model/RecordOrderer.java @@ -0,0 +1,326 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.model; + +import java.util.List; + +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.CalcCountRecord; +import org.apache.poi.hssf.record.CalcModeRecord; +import org.apache.poi.hssf.record.DateWindow1904Record; +import org.apache.poi.hssf.record.DefaultRowHeightRecord; +import org.apache.poi.hssf.record.DeltaRecord; +import org.apache.poi.hssf.record.DimensionsRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.GridsetRecord; +import org.apache.poi.hssf.record.GutsRecord; +import org.apache.poi.hssf.record.HorizontalPageBreakRecord; +import org.apache.poi.hssf.record.HyperlinkRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.IterationRecord; +import org.apache.poi.hssf.record.PaneRecord; +import org.apache.poi.hssf.record.PrecisionRecord; +import org.apache.poi.hssf.record.PrintGridlinesRecord; +import org.apache.poi.hssf.record.PrintHeadersRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; +import org.apache.poi.hssf.record.RefModeRecord; +import org.apache.poi.hssf.record.SCLRecord; +import org.apache.poi.hssf.record.SaveRecalcRecord; +import org.apache.poi.hssf.record.SelectionRecord; +import org.apache.poi.hssf.record.UncalcedRecord; +import org.apache.poi.hssf.record.VerticalPageBreakRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; +import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; +import org.apache.poi.hssf.record.aggregates.DataValidityTable; +import org.apache.poi.hssf.record.aggregates.MergedCellsTable; + +/** + * Finds correct insert positions for records in workbook streams

+ * + * See OOO excelfileformat.pdf sec. 4.2.5 'Record Order in a BIFF8 Workbook Stream' + * + * @author Josh Micich + */ +final class RecordOrderer { + // TODO - add UninterpretedRecord as base class for many of these + // unimplemented sids + + // TODO - simplify logic using a generalised record ordering + + private RecordOrderer() { + // no instances of this class + } + /** + * Adds the specified new record in the correct place in sheet records list + * + */ + public static void addNewSheetRecord(List sheetRecords, RecordBase newRecord) { + int index = findSheetInsertPos(sheetRecords, newRecord.getClass()); + sheetRecords.add(index, newRecord); + } + + private static int findSheetInsertPos(List records, Class recClass) { + if (recClass == DataValidityTable.class) { + return findDataValidationTableInsertPos(records); + } + if (recClass == MergedCellsTable.class) { + return findInsertPosForNewMergedRecordTable(records); + } + if (recClass == ConditionalFormattingTable.class) { + return findInsertPosForNewCondFormatTable(records); + } + if (recClass == GutsRecord.class) { + return getGutsRecordInsertPos(records); + } + if (recClass == HorizontalPageBreakRecord.class) { + return getPageBreakRecordInsertPos(records, true); + } + if (recClass == VerticalPageBreakRecord.class) { + return getPageBreakRecordInsertPos(records, false); + } + throw new RuntimeException("Unexpected record class (" + recClass.getName() + ")"); + } + + private static int getPageBreakRecordInsertPos(List records, boolean isHorizonal) { + int dimensionsIndex = getDimensionsIndex(records); + int i = dimensionsIndex-1; + while (i > 0) { + i--; + Object rb = records.get(i); + if (isPageBreakPriorRecord(rb, isHorizonal)) { + return i+1; + } + } + throw new RuntimeException("Did not find insert point for GUTS"); + } + private static boolean isPageBreakPriorRecord(Object rb, boolean newRecIsHorizontal) { + if (rb instanceof Record) { + Record record = (Record) rb; + switch (record.getSid()) { + case BOFRecord.sid: + case IndexRecord.sid: + // calc settings block + case UncalcedRecord.sid: + case CalcCountRecord.sid: + case CalcModeRecord.sid: + case PrecisionRecord.sid: + case RefModeRecord.sid: + case DeltaRecord.sid: + case IterationRecord.sid: + case DateWindow1904Record.sid: + case SaveRecalcRecord.sid: + // end calc settings + case PrintHeadersRecord.sid: + case PrintGridlinesRecord.sid: + case GridsetRecord.sid: + case DefaultRowHeightRecord.sid: + case 0x0081: // SHEETPR + return true; + } + switch (record.getSid()) { + // page settings block + case HorizontalPageBreakRecord.sid: + if (!newRecIsHorizontal) { + return true; + } + return false; + case VerticalPageBreakRecord.sid: + return false; + // next is case HeaderRecord.sid: case FooterRecord.sid: + // then more records in page settings block + + } + } + return false; + } + /** + * Find correct position to add new CFHeader record + */ + private static int findInsertPosForNewCondFormatTable(List records) { + + for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record + Object rb = records.get(i); + if (rb instanceof MergedCellsTable) { + return i + 1; + } + Record rec = (Record) rb; + switch (rec.getSid()) { + case WindowTwoRecord.sid: + case SCLRecord.sid: + case PaneRecord.sid: + case SelectionRecord.sid: + case 0x0099:// STANDARDWIDTH + // MergedCellsTable usually here + case 0x015f:// LABELRANGES + case 0x00ef:// PHONETICPR + return i + 1; + } + } + throw new RuntimeException("Did not find Window2 record"); + } + + private static int findInsertPosForNewMergedRecordTable(List records) { + for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record + Object rb = records.get(i); + Record rec = (Record) rb; + switch (rec.getSid()) { + case WindowTwoRecord.sid: + case SCLRecord.sid: + case PaneRecord.sid: + case SelectionRecord.sid: + case 0x0099:// STANDARDWIDTH + return i + 1; + } + } + throw new RuntimeException("Did not find Window2 record"); + } + + + /** + * Finds the index where the sheet validations header record should be inserted + * @param records the records for this sheet + * + * + WINDOW2 + * o SCL + * o PANE + * oo SELECTION + * o STANDARDWIDTH + * oo MERGEDCELLS + * o LABELRANGES + * o PHONETICPR + * o Conditional Formatting Table + * o Hyperlink Table + * o Data Validity Table + * o SHEETLAYOUT + * o SHEETPROTECTION + * o RANGEPROTECTION + * + EOF + */ + private static int findDataValidationTableInsertPos(List records) { + int i = records.size() - 1; + if (!(records.get(i) instanceof EOFRecord)) { + throw new IllegalStateException("Last sheet record should be EOFRecord"); + } + while (i > 0) { + i--; + Object rb = records.get(i); + if (isDVTPriorRecord(rb)) { + Record nextRec = (Record) records.get(i + 1); + if (!isDVTSubsequentRecord(nextRec.getSid())) { + throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName() + + ") found after (" + rb.getClass().getName() + ")"); + } + return i+1; + } + Record rec = (Record) rb; + if (!isDVTSubsequentRecord(rec.getSid())) { + throw new IllegalStateException("Unexpected (" + rec.getClass().getName() + + ") while looking for DV Table insert pos"); + } + } + return 0; + } + + + private static boolean isDVTPriorRecord(Object rb) { + if (rb instanceof MergedCellsTable || rb instanceof ConditionalFormattingTable) { + return true; + } + short sid = ((Record)rb).getSid(); + switch(sid) { + case WindowTwoRecord.sid: + case 0x00A0: // SCL + case PaneRecord.sid: + case SelectionRecord.sid: + case 0x0099: // STANDARDWIDTH + // MergedCellsTable + case 0x015F: // LABELRANGES + case 0x00EF: // PHONETICPR + // ConditionalFormattingTable + case HyperlinkRecord.sid: + case 0x0800: // QUICKTIP + return true; + } + return false; + } + + private static boolean isDVTSubsequentRecord(short sid) { + switch(sid) { + case 0x0862: // SHEETLAYOUT + case 0x0867: // SHEETPROTECTION + case 0x0868: // RANGEPROTECTION + case EOFRecord.sid: + return true; + } + return false; + } + /** + * DIMENSIONS record is always present + */ + private static int getDimensionsIndex(List records) { + int nRecs = records.size(); + for(int i=0; i 0) { + i--; + Object rb = records.get(i); + if (isGutsPriorRecord(rb)) { + return i+1; + } + } + throw new RuntimeException("Did not find insert point for GUTS"); + } + + private static boolean isGutsPriorRecord(Object rb) { + if (rb instanceof Record) { + Record record = (Record) rb; + switch (record.getSid()) { + case BOFRecord.sid: + case IndexRecord.sid: + // calc settings block + case UncalcedRecord.sid: + case CalcCountRecord.sid: + case CalcModeRecord.sid: + case PrecisionRecord.sid: + case RefModeRecord.sid: + case DeltaRecord.sid: + case IterationRecord.sid: + case DateWindow1904Record.sid: + case SaveRecalcRecord.sid: + // end calc settings + case PrintHeadersRecord.sid: + case PrintGridlinesRecord.sid: + case GridsetRecord.sid: + return true; + // DefaultRowHeightRecord.sid is next + } + } + return false; + } +} diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 1f9cfdff4..a17984b49 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -17,22 +17,77 @@ package org.apache.poi.hssf.model; -import org.apache.poi.hssf.record.*; // normally I don't do this, buy we literally mean ALL -import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; -import org.apache.poi.hssf.record.aggregates.DataValidityTable; -import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; -import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; -import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; -import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; -import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.hssf.util.PaneInformation; - -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - import java.util.ArrayList; import java.util.Iterator; -import java.util.List; +import java.util.List; + +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BottomMarginRecord; +import org.apache.poi.hssf.record.CFHeaderRecord; +import org.apache.poi.hssf.record.CalcCountRecord; +import org.apache.poi.hssf.record.CalcModeRecord; +import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.ColumnInfoRecord; +import org.apache.poi.hssf.record.DBCellRecord; +import org.apache.poi.hssf.record.DVALRecord; +import org.apache.poi.hssf.record.DefaultColWidthRecord; +import org.apache.poi.hssf.record.DefaultRowHeightRecord; +import org.apache.poi.hssf.record.DeltaRecord; +import org.apache.poi.hssf.record.DimensionsRecord; +import org.apache.poi.hssf.record.DrawingRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.EscherAggregate; +import org.apache.poi.hssf.record.FooterRecord; +import org.apache.poi.hssf.record.GridsetRecord; +import org.apache.poi.hssf.record.GutsRecord; +import org.apache.poi.hssf.record.HCenterRecord; +import org.apache.poi.hssf.record.HeaderRecord; +import org.apache.poi.hssf.record.HorizontalPageBreakRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.IterationRecord; +import org.apache.poi.hssf.record.LeftMarginRecord; +import org.apache.poi.hssf.record.Margin; +import org.apache.poi.hssf.record.MergeCellsRecord; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.ObjectProtectRecord; +import org.apache.poi.hssf.record.PageBreakRecord; +import org.apache.poi.hssf.record.PaneRecord; +import org.apache.poi.hssf.record.PasswordRecord; +import org.apache.poi.hssf.record.PrintGridlinesRecord; +import org.apache.poi.hssf.record.PrintHeadersRecord; +import org.apache.poi.hssf.record.PrintSetupRecord; +import org.apache.poi.hssf.record.ProtectRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; +import org.apache.poi.hssf.record.RefModeRecord; +import org.apache.poi.hssf.record.RightMarginRecord; +import org.apache.poi.hssf.record.RowRecord; +import org.apache.poi.hssf.record.SCLRecord; +import org.apache.poi.hssf.record.SaveRecalcRecord; +import org.apache.poi.hssf.record.ScenarioProtectRecord; +import org.apache.poi.hssf.record.SelectionRecord; +import org.apache.poi.hssf.record.SharedFormulaRecord; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.record.TopMarginRecord; +import org.apache.poi.hssf.record.UncalcedRecord; +import org.apache.poi.hssf.record.VCenterRecord; +import org.apache.poi.hssf.record.VerticalPageBreakRecord; +import org.apache.poi.hssf.record.WSBoolRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; +import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; +import org.apache.poi.hssf.record.aggregates.DataValidityTable; +import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.hssf.record.aggregates.MergedCellsTable; +import org.apache.poi.hssf.record.aggregates.RecordAggregate; +import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.hssf.util.PaneInformation; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; /** * Low level model implementation of a Sheet (one workbook contains many sheets) @@ -72,30 +127,30 @@ public final class Sheet implements Model { protected DefaultColWidthRecord defaultcolwidth = null; protected DefaultRowHeightRecord defaultrowheight = null; protected GridsetRecord gridset = null; + private GutsRecord _gutsRecord; protected PrintSetupRecord printSetup = null; protected HeaderRecord header = null; protected FooterRecord footer = null; protected PrintGridlinesRecord printGridlines = null; protected WindowTwoRecord windowTwo = null; - protected MergeCellsRecord merged = null; protected Margin[] margins = null; - protected List mergedRecords = new ArrayList(); - protected int numMergedRegions = 0; + private MergedCellsTable _mergedCellsTable; protected SelectionRecord selection = null; - protected ColumnInfoRecordsAggregate columns = null; + /** always present in this POI object, not always written to Excel file */ + /*package*/ColumnInfoRecordsAggregate _columnInfos; protected ValueRecordsAggregate cells = null; - protected RowRecordsAggregate rows = null; + protected RowRecordsAggregate _rowsAggregate = null; private Iterator valueRecIterator = null; private Iterator rowRecIterator = null; protected int eofLoc = 0; protected ProtectRecord protect = null; - protected PageBreakRecord rowBreaks = null; - protected PageBreakRecord colBreaks = null; + protected PageBreakRecord _rowBreaksRecord; + protected PageBreakRecord _columnBreaksRecord; private DataValidityTable _dataValidityTable= null; protected ObjectProtectRecord objprotect = null; protected ScenarioProtectRecord scenprotect = null; protected PasswordRecord password = null; - protected List condFormatting = new ArrayList(); + private ConditionalFormattingTable condFormatting; /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ protected boolean _isUncalced = false; @@ -139,13 +194,70 @@ public final class Sheet implements Model { Sheet retval = new Sheet(); ArrayList records = new ArrayList(recs.size() / 5); boolean isfirstcell = true; - boolean isfirstrow = true; int bofEofNestingLevel = 0; for (int k = offset; k < recs.size(); k++) { Record rec = ( Record ) recs.get(k); + if (rec.isValue() != (rec instanceof CellValueRecordInterface)) { + if (rec instanceof SharedFormulaRecord) { + + } else { + "".length(); + } + } + if ( rec.getSid() == DBCellRecord.sid ) { + continue; + } + if ( rec.getSid() == IndexRecord.sid ) { + // ignore INDEX record because it is only needed by Excel, + // and POI always re-calculates its contents + continue; + } + if ( rec.getSid() == StringRecord.sid ) { + continue; + } + + if ( rec.getSid() == CFHeaderRecord.sid ) { + RecordStream rs = new RecordStream(recs, k); + retval.condFormatting = new ConditionalFormattingTable(rs); + k += rs.getCountRead()-1; + records.add(retval.condFormatting); + continue; + } + + if (rec.getSid() == ColumnInfoRecord.sid) { + RecordStream rs = new RecordStream(recs, k); + retval._columnInfos = new ColumnInfoRecordsAggregate(rs); + k += rs.getCountRead()-1; + records.add(retval._columnInfos); + continue; + } + if ( rec.getSid() == DVALRecord.sid) { + RecordStream rs = new RecordStream(recs, k); + retval._dataValidityTable = new DataValidityTable(rs); + k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based + records.add(retval._dataValidityTable); + continue; // TODO + } + if ( rec.getSid() == RowRecord.sid ) + { + RowRecord row = (RowRecord)rec; + if (retval._rowsAggregate == null) { + retval._rowsAggregate = new RowRecordsAggregate(); + records.add(retval._rowsAggregate); //only add the aggregate once + } + retval._rowsAggregate.insertRow(row); + continue; + } + if (rec.getSid() == MergeCellsRecord.sid) { + RecordStream rs = new RecordStream(recs, k); + retval._mergedCellsTable = new MergedCellsTable(rs); + records.add(retval._mergedCellsTable); + continue; // TODO + } + if (rec.getSid() == BOFRecord.sid) { bofEofNestingLevel++; @@ -169,53 +281,15 @@ public final class Sheet implements Model { else if (rec.getSid() == DimensionsRecord.sid) { // Make a columns aggregate if one hasn't ready been created. - if (retval.columns == null) + if (retval._columnInfos == null) { - retval.columns = new ColumnInfoRecordsAggregate(); - records.add(retval.columns); + retval._columnInfos = new ColumnInfoRecordsAggregate(); + records.add(retval._columnInfos); } retval.dims = ( DimensionsRecord ) rec; retval.dimsloc = records.size(); } - else if (rec.getSid() == MergeCellsRecord.sid) - { - retval.mergedRecords.add(rec); - retval.merged = ( MergeCellsRecord ) rec; - retval.numMergedRegions += retval.merged.getNumAreas(); - } - else if ( rec.getSid() == CFHeaderRecord.sid ) - { - CFRecordsAggregate cfAgg = CFRecordsAggregate.createCFAggregate(recs, k); - retval.condFormatting.add(cfAgg); - rec = cfAgg; - } - else if ( rec.getSid() == CFRuleRecord.sid ) - { - // Skip it since it is processed by CFRecordsAggregate - rec = null; - } - else if (rec.getSid() == ColumnInfoRecord.sid) - { - ColumnInfoRecord col = (ColumnInfoRecord)rec; - if (retval.columns != null) - { - rec = null; //only add the aggregate once - } - else - { - rec = retval.columns = new ColumnInfoRecordsAggregate(); - } - retval.columns.insertColumn(col); - } - else if (rec.getSid() == DefaultColWidthRecord.sid) - { - retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; - } - else if (rec.getSid() == DefaultRowHeightRecord.sid) - { - retval.defaultrowheight = ( DefaultRowHeightRecord ) rec; - } else if ( rec.isValue() && bofEofNestingLevel == 1 ) { if ( isfirstcell ) @@ -230,22 +304,13 @@ public final class Sheet implements Model { rec = null; } } - else if ( rec.getSid() == StringRecord.sid ) + else if (rec.getSid() == DefaultColWidthRecord.sid) { - rec = null; + retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; } - else if ( rec.getSid() == RowRecord.sid ) + else if (rec.getSid() == DefaultRowHeightRecord.sid) { - RowRecord row = (RowRecord)rec; - if (!isfirstrow) rec = null; //only add the aggregate once - - if ( isfirstrow ) - { - retval.rows = new RowRecordsAggregate(); - rec = retval.rows; - isfirstrow = false; - } - retval.rows.insertRow(row); + retval.defaultrowheight = ( DefaultRowHeightRecord ) rec; } else if ( rec.getSid() == PrintGridlinesRecord.sid ) { @@ -291,22 +356,6 @@ public final class Sheet implements Model { { retval.windowTwo = (WindowTwoRecord) rec; } - else if ( rec.getSid() == DBCellRecord.sid ) - { - rec = null; - } - else if ( rec.getSid() == IndexRecord.sid ) - { - // ignore INDEX record because it is only needed by Excel, - // and POI always re-calculates its contents - rec = null; - } - else if ( rec.getSid() == DVALRecord.sid) { - RecordStream rs = new RecordStream(recs, k); - retval._dataValidityTable = new DataValidityTable(rs); - k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based - rec = retval._dataValidityTable; - } else if ( rec.getSid() == ProtectRecord.sid ) { retval.protect = (ProtectRecord) rec; @@ -323,13 +372,13 @@ public final class Sheet implements Model { { retval.password = (PasswordRecord) rec; } - else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID) + else if (rec.getSid() == HorizontalPageBreakRecord.sid) { - retval.rowBreaks = (PageBreakRecord)rec; + retval._rowBreaksRecord = (HorizontalPageBreakRecord)rec; } - else if (rec.getSid() == PageBreakRecord.VERTICAL_SID) + else if (rec.getSid() == VerticalPageBreakRecord.sid) { - retval.colBreaks = (PageBreakRecord)rec; + retval._columnBreaksRecord = (VerticalPageBreakRecord)rec; } if (rec != null) @@ -337,6 +386,9 @@ public final class Sheet implements Model { records.add(rec); } } + if (retval.dimsloc < 0) { + throw new RuntimeException("DimensionsRecord was not found"); + } retval.records = records; retval.checkRows(); retval.checkCells(); @@ -345,6 +397,17 @@ public final class Sheet implements Model { return retval; } + private static final class RecordCloner implements RecordVisitor { + + private final List _destList; + + public RecordCloner(List destList) { + _destList = destList; + } + public void visitRecord(Record r) { + _destList.add(r.clone()); + } + } /** * Clones the low level records of this sheet and returns the new sheet instance. * This method is implemented by adding methods for deep cloning to all records that @@ -356,7 +419,13 @@ public final class Sheet implements Model { { ArrayList clonedRecords = new ArrayList(this.records.size()); for (int i=0; i= numMergedRegions || mergedRecords.size() == 0) - return; - - int pos = 0; - int startNumRegions = 0; - - //optimisation for current record - if (numMergedRegions - index < merged.getNumAreas()) - { - pos = mergedRecords.size() - 1; - startNumRegions = numMergedRegions - merged.getNumAreas(); - } - else - { - for (int n = 0; n < mergedRecords.size(); n++) - { - MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n); - if (startNumRegions + record.getNumAreas() > index) - { - pos = n; - break; - } - startNumRegions += record.getNumAreas(); - } - } - - MergeCellsRecord rec = (MergeCellsRecord) mergedRecords.get(pos); - rec.removeAreaAt(index - startNumRegions); - numMergedRegions--; - if (rec.getNumAreas() == 0) - { - mergedRecords.remove(pos); - //get rid of the record from the sheet - records.remove(merged); - if (merged == rec) { - //pull up the LAST record for operations when we finally - //support continue records for mergedRegions - if (mergedRecords.size() > 0) { - merged = (MergeCellsRecord) mergedRecords.get(mergedRecords.size() - 1); - } else { - merged = null; - } - } - } + MergedCellsTable mrt = getMergedRecords(); + if (index >= mrt.getNumberOfMergedRegions()) { + return; + } + mrt.remove(index); } - public CellRangeAddress getMergedRegionAt(int index) - { + public CellRangeAddress getMergedRegionAt(int index) { //safety checks - if (index >= numMergedRegions || mergedRecords.size() == 0) - return null; - - int pos = 0; - int startNumRegions = 0; - - //optimisation for current record - if (numMergedRegions - index < merged.getNumAreas()) - { - pos = mergedRecords.size() - 1; - startNumRegions = numMergedRegions - merged.getNumAreas(); - } - else - { - for (int n = 0; n < mergedRecords.size(); n++) - { - MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n); - if (startNumRegions + record.getNumAreas() > index) - { - pos = n; - break; - } - startNumRegions += record.getNumAreas(); - } - } - return ((MergeCellsRecord) mergedRecords.get(pos)).getAreaAt(index - startNumRegions); + MergedCellsTable mrt = getMergedRecords(); + if (index >= mrt.getNumberOfMergedRegions()) { + return null; + } + return mrt.get(index); } - public int getNumMergedRegions() - { - return numMergedRegions; + public int getNumMergedRegions() { + return getMergedRecords().getNumberOfMergedRegions(); } - // Find correct position to add new CF record - private int findConditionalFormattingPosition() - { - // This is default. - // If the algorithm does not find the right position, - // this one will be used (this is a position before EOF record) - int index = records.size()-2; - - for( int i=index; i>=0; i-- ) - { - Record rec = (Record)records.get(i); - short sid = rec.getSid(); - - // CFRecordsAggregate records already exist, just add to the end - if (rec instanceof CFRecordsAggregate) { return i+1; } - - if( sid == (short)0x00ef ) { return i+1; }// PHONETICPR - if( sid == (short)0x015f ) { return i+1; }// LABELRANGES - if( sid == MergeCellsRecord.sid ) { return i+1; } - if( sid == (short)0x0099 ) { return i+1; }// STANDARDWIDTH - if( sid == SelectionRecord.sid ) { return i+1; } - if( sid == PaneRecord.sid ) { return i+1; } - if( sid == SCLRecord.sid ) { return i+1; } - if( sid == WindowTwoRecord.sid ) { return i+1; } - } - - return index; + private ConditionalFormattingTable getConditionalFormattingTable() { + if (condFormatting == null) { + condFormatting = new ConditionalFormattingTable(); + RecordOrderer.addNewSheetRecord(records, condFormatting); + } + return condFormatting; } - public int addConditionalFormatting(CFRecordsAggregate cfAggregate) - { - int index = findConditionalFormattingPosition(); - records.add(index, cfAggregate); - condFormatting.add(cfAggregate); - return condFormatting.size()-1; + + public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { + ConditionalFormattingTable cft = getConditionalFormattingTable(); + return cft.add(cfAggregate); } - public void removeConditionalFormatting(int index) - { - if (index >= 0 && index <= condFormatting.size()-1 ) - { - CFRecordsAggregate cfAggregate = getCFRecordsAggregateAt(index); - records.remove(cfAggregate); - condFormatting.remove(index); - } + public void removeConditionalFormatting(int index) { + getConditionalFormattingTable().remove(index); } - public CFRecordsAggregate getCFRecordsAggregateAt(int index) - { - if (index >= 0 && index <= condFormatting.size()-1 ) - { - return (CFRecordsAggregate) condFormatting.get(index); - } - return null; + public CFRecordsAggregate getCFRecordsAggregateAt(int index) { + return getConditionalFormattingTable().get(index); } - public int getNumConditionalFormattings() - { - return condFormatting.size(); + public int getNumConditionalFormattings() { + return getConditionalFormattingTable().size(); } /** @@ -699,13 +675,13 @@ public final class Sheet implements Model { log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[] { records.size(), cells.getPhysicalNumberOfCells(), - rows.getPhysicalNumberOfRows(), + _rowsAggregate.getPhysicalNumberOfRows(), records.size() + cells.getPhysicalNumberOfCells() - + rows.getPhysicalNumberOfRows() - 2 + + _rowsAggregate.getPhysicalNumberOfRows() - 2 }); } return records.size() + cells.getPhysicalNumberOfCells() - + rows.getPhysicalNumberOfRows() - 2; + + _rowsAggregate.getPhysicalNumberOfRows() - 2; } /** @@ -814,7 +790,7 @@ public final class Sheet implements Model { for (int k = 0; k < records.size(); k++) { - Record record = (( Record ) records.get(k)); + RecordBase record = (RecordBase) records.get(k); // Don't write out UncalcedRecord entries, as // we handle those specially just below @@ -833,7 +809,7 @@ public final class Sheet implements Model { } // If the BOF record was just serialized then add the IndexRecord - if (record.getSid() == BOFRecord.sid) { + if (record instanceof BOFRecord) { if (!haveSerializedIndex) { haveSerializedIndex = true; // Add an optional UncalcedRecord. However, we should add @@ -846,7 +822,7 @@ public final class Sheet implements Model { } //Can there be more than one BOF for a sheet? If not then we can //remove this guard. So be safe it is left here. - if (rows != null) { + if (_rowsAggregate != null) { pos += serializeIndexRecord(k, pos, data); } } @@ -865,8 +841,8 @@ public final class Sheet implements Model { private int serializeIndexRecord(final int bofRecordIndex, final int indexRecordOffset, byte[] data) { IndexRecord index = new IndexRecord(); - index.setFirstRow(rows.getFirstRowNum()); - index.setLastRowAdd1(rows.getLastRowNum() + 1); + index.setFirstRow(_rowsAggregate.getFirstRowNum()); + index.setLastRowAdd1(_rowsAggregate.getLastRowNum() + 1); // Calculate the size of the records from the end of the BOF // and up to the RowRecordsAggregate... @@ -874,7 +850,7 @@ public final class Sheet implements Model { int sizeOfInitialSheetRecords = 0; // start just after BOF record (INDEX is not present in this list) for (int j = bofRecordIndex + 1; j < records.size(); j++) { - Record tmpRec = ((Record) records.get(j)); + RecordBase tmpRec = ((RecordBase) records.get(j)); if (tmpRec instanceof UncalcedRecord) { continue; } @@ -891,7 +867,7 @@ public final class Sheet implements Model { // Note: The offsets are relative to the Workbook BOF. Assume that this is // 0 for now..... - int blockCount = rows.getRowBlockCount(); + int blockCount = _rowsAggregate.getRowBlockCount(); // Calculate the size of this IndexRecord int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount); @@ -902,15 +878,15 @@ public final class Sheet implements Model { // The offset of each DBCELL record needs to be updated in the INDEX record // account for row records in this row-block - currentOffset += rows.getRowBlockSize(block); + currentOffset += _rowsAggregate.getRowBlockSize(block); // account for cell value records after those - currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(rows - .getStartRowNumberForBlock(block), rows.getEndRowNumberForBlock(block)); + currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(_rowsAggregate + .getStartRowNumberForBlock(block), _rowsAggregate.getEndRowNumberForBlock(block)); // currentOffset is now the location of the DBCELL record for this row-block index.addDbcell(currentOffset); // Add space required to write the DBCELL record (whose reference was just added). - currentOffset += (8 + (rows.getRowCountForBlock(block) * 2)); + currentOffset += (8 + (_rowsAggregate.getRowCountForBlock(block) * 2)); } return index.serialize(indexRecordOffset, data); } @@ -1031,11 +1007,11 @@ public final class Sheet implements Model { } //IndexRecord index = null; //If the row exists remove it, so that any cells attached to the row are removed - RowRecord existingRow = rows.getRow(row.getRowNumber()); + RowRecord existingRow = _rowsAggregate.getRow(row.getRowNumber()); if (existingRow != null) - rows.removeRow(existingRow); + _rowsAggregate.removeRow(existingRow); - rows.insertRow(row); + _rowsAggregate.insertRow(row); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "exit addRow"); @@ -1054,7 +1030,7 @@ public final class Sheet implements Model { checkRows(); setLoc(getDimsLoc()); - rows.removeRow(row); + _rowsAggregate.removeRow(row); } /** @@ -1108,7 +1084,7 @@ public final class Sheet implements Model { log.log(POILogger.DEBUG, "getNextRow loc= " + loc); if (rowRecIterator == null) { - rowRecIterator = rows.getIterator(); + rowRecIterator = _rowsAggregate.getIterator(); } if (!rowRecIterator.hasNext()) { @@ -1136,7 +1112,7 @@ public final class Sheet implements Model { public RowRecord getRow(int rownum) { if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "getNextRow loc= " + loc); - return rows.getRow(rownum); + return _rowsAggregate.getRow(rownum); } /** @@ -1258,6 +1234,15 @@ public final class Sheet implements Model { retval.setColLevelMax(( short ) 0); return retval; } + private GutsRecord getGutsRecord() { + if (_gutsRecord == null) { + GutsRecord result = createGuts(); + RecordOrderer.addNewSheetRecord(records, result); + _gutsRecord = result; + } + + return _gutsRecord; + } /** * creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff @@ -1422,43 +1407,22 @@ public final class Sheet implements Model { /** * get the width of a given column in units of 1/256th of a character width - * @param column index + * @param columnIndex index * @see org.apache.poi.hssf.record.DefaultColWidthRecord * @see org.apache.poi.hssf.record.ColumnInfoRecord * @see #setColumnWidth(short,short) * @return column width in units of 1/256th of a character width */ - public short getColumnWidth(short column) - { - short retval = 0; - ColumnInfoRecord ci = null; + public short getColumnWidth(short columnIndex) { - if (columns != null) - { - int count=columns.getNumColumns(); - for ( int k=0;k

- * This class is just used so that SID compares work properly in the RecordFactory - * @see PageBreakRecord - * @author Danny Mui (dmui at apache dot org) - */ -public class HorizontalPageBreakRecord extends PageBreakRecord { +import java.util.Iterator; + +/** + * HorizontalPageBreak (0x001B) record that stores page breaks at rows

+ * + * @see PageBreakRecord + * @author Danny Mui (dmui at apache dot org) + */ +public final class HorizontalPageBreakRecord extends PageBreakRecord { + + public static final short sid = 0x001B; - public static final short sid = PageBreakRecord.HORIZONTAL_SID; - /** - * + * Creates an empty horizontal page break record */ public HorizontalPageBreakRecord() { - super(); + // } /** - * @param sid - */ - public HorizontalPageBreakRecord(short sid) { - super(sid); - } - - /** - * @param in the RecordInputstream to read the record from + * @param in + * the RecordInputstream to read the record from */ public HorizontalPageBreakRecord(RecordInputStream in) { super(in); } - /* (non-Javadoc) - * @see org.apache.poi.hssf.record.Record#getSid() - */ + protected void validateSid(short id) { + if (id != getSid()) { + throw new RecordFormatException( + "NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id); + } + } + public short getSid() { return sid; } + public Object clone() { + PageBreakRecord result = new HorizontalPageBreakRecord(); + Iterator iterator = getBreaksIterator(); + while (iterator.hasNext()) { + Break original = (Break) iterator.next(); + result.addBreak(original.main, original.subFrom, original.subTo); + } + return result; + } } diff --git a/src/java/org/apache/poi/hssf/record/LegendRecord.java b/src/java/org/apache/poi/hssf/record/LegendRecord.java index 40ddb887c..e9c529ea3 100644 --- a/src/java/org/apache/poi/hssf/record/LegendRecord.java +++ b/src/java/org/apache/poi/hssf/record/LegendRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * Defines a legend for a chart. @@ -30,10 +29,16 @@ import org.apache.poi.util.*; * @author Andrew C. Oliver (acoliver at apache.org) */ -public class LegendRecord - extends Record -{ - public final static short sid = 0x1015; +public final class LegendRecord extends Record { + public final static short sid = 0x1015; + + private static final BitField autoPosition = BitFieldFactory.getInstance(0x01); + private static final BitField autoSeries = BitFieldFactory.getInstance(0x02); + private static final BitField autoXPositioning = BitFieldFactory.getInstance(0x04); + private static final BitField autoYPositioning = BitFieldFactory.getInstance(0x08); + private static final BitField vertical = BitFieldFactory.getInstance(0x10); + private static final BitField dataTable = BitFieldFactory.getInstance(0x20); + private int field_1_xAxisUpperLeft; private int field_2_yAxisUpperLeft; private int field_3_xSize; @@ -50,12 +55,6 @@ public class LegendRecord public final static byte SPACING_MEDIUM = 1; public final static byte SPACING_OPEN = 2; private short field_7_options; - private BitField autoPosition = BitFieldFactory.getInstance(0x1); - private BitField autoSeries = BitFieldFactory.getInstance(0x2); - private BitField autoXPositioning = BitFieldFactory.getInstance(0x4); - private BitField autoYPositioning = BitFieldFactory.getInstance(0x8); - private BitField vertical = BitFieldFactory.getInstance(0x10); - private BitField dataTable = BitFieldFactory.getInstance(0x20); public LegendRecord() @@ -437,10 +436,4 @@ public class LegendRecord { return dataTable.isSet(field_7_options); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/LineFormatRecord.java b/src/java/org/apache/poi/hssf/record/LineFormatRecord.java index 5e359ab82..8caa8e4a4 100644 --- a/src/java/org/apache/poi/hssf/record/LineFormatRecord.java +++ b/src/java/org/apache/poi/hssf/record/LineFormatRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * Describes a line format record. The line format record controls how a line on a chart appears. @@ -30,10 +29,13 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class LineFormatRecord - extends Record -{ - public final static short sid = 0x1007; +public final class LineFormatRecord extends Record { + public final static short sid = 0x1007; + + private static final BitField auto = BitFieldFactory.getInstance(0x1); + private static final BitField drawTicks = BitFieldFactory.getInstance(0x4); + private static final BitField unknown = BitFieldFactory.getInstance(0x4); + private int field_1_lineColor; private short field_2_linePattern; public final static short LINE_PATTERN_SOLID = 0; @@ -51,9 +53,6 @@ public class LineFormatRecord public final static short WEIGHT_MEDIUM = 1; public final static short WEIGHT_WIDE = 2; private short field_4_format; - private BitField auto = BitFieldFactory.getInstance(0x1); - private BitField drawTicks = BitFieldFactory.getInstance(0x4); - private BitField unknown = BitFieldFactory.getInstance(0x4); private short field_5_colourPaletteIndex; @@ -342,10 +341,4 @@ public class LineFormatRecord { return unknown.isSet(field_4_format); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java b/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java index 46d52bf09..093c1a86c 100644 --- a/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java +++ b/src/java/org/apache/poi/hssf/record/LinkedDataRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * Describes a linked data record. This record referes to the series data or text. @@ -30,10 +29,11 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class LinkedDataRecord - extends Record -{ - public final static short sid = 0x1051; +public final class LinkedDataRecord extends Record { + public final static short sid = 0x1051; + + private static final BitField customNumberFormat= BitFieldFactory.getInstance(0x1); + private byte field_1_linkType; public final static byte LINK_TYPE_TITLE_OR_TEXT = 0; public final static byte LINK_TYPE_VALUES = 1; @@ -45,7 +45,6 @@ public class LinkedDataRecord public final static byte REFERENCE_TYPE_NOT_USED = 3; public final static byte REFERENCE_TYPE_ERROR_REPORTED = 4; private short field_3_options; - private BitField customNumberFormat = BitFieldFactory.getInstance(0x1); private short field_4_indexNumberFmtRecord; private LinkedDataFormulaField field_5_formulaOfLink; @@ -86,7 +85,7 @@ public class LinkedDataRecord field_2_referenceType = in.readByte(); field_3_options = in.readShort(); field_4_indexNumberFmtRecord = in.readShort(); - field_5_formulaOfLink = new org.apache.poi.hssf.record.LinkedDataFormulaField(); + field_5_formulaOfLink = new LinkedDataFormulaField(); field_5_formulaOfLink.fillField(in); } @@ -156,7 +155,7 @@ public class LinkedDataRecord rec.field_2_referenceType = field_2_referenceType; rec.field_3_options = field_3_options; rec.field_4_indexNumberFmtRecord = field_4_indexNumberFmtRecord; - rec.field_5_formulaOfLink = ((org.apache.poi.hssf.record.LinkedDataFormulaField)field_5_formulaOfLink.clone());; + rec.field_5_formulaOfLink = ((LinkedDataFormulaField)field_5_formulaOfLink.clone());; return rec; } @@ -286,10 +285,4 @@ public class LinkedDataRecord { return customNumberFormat.isSet(field_3_options); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java index 2e0a417e0..525749dff 100644 --- a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java +++ b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java @@ -32,68 +32,51 @@ import org.apache.poi.util.LittleEndian; */ public final class MergeCellsRecord extends Record { public final static short sid = 0x00E5; - private CellRangeAddressList _regions; + /** sometimes the regions array is shared with other MergedCellsRecords */ + private CellRangeAddress[] _regions; + private final int _startIndex; + private final int _numberOfRegions; - /** - * Creates an empty MergedCellsRecord - */ - public MergeCellsRecord() { - _regions = new CellRangeAddressList(); + public MergeCellsRecord(CellRangeAddress[] regions, int startIndex, int numberOfRegions) { + _regions = regions; + _startIndex = startIndex; + _numberOfRegions = numberOfRegions; } - /** * Constructs a MergedCellsRecord and sets its fields appropriately * @param in the RecordInputstream to read the record from */ public MergeCellsRecord(RecordInputStream in) { - super(in); + int nRegions = in.readUShort(); + CellRangeAddress[] cras = new CellRangeAddress[nRegions]; + for (int i = 0; i < nRegions; i++) { + cras[i] = new org.apache.poi.hssf.util.CellRangeAddress(in); + } + _numberOfRegions = nRegions; + _startIndex = 0; + _regions = cras; } - protected void fillFields(RecordInputStream in) { - _regions = new org.apache.poi.hssf.util.CellRangeAddressList(in); + throw new RuntimeException("obsolete"); } - /** * get the number of merged areas. If this drops down to 0 you should just go * ahead and delete the record. * @return number of areas */ public short getNumAreas() { - return (short)_regions.countRanges(); - } - - /** - * Add an area to consider a merged cell. The index returned is only gauranteed to - * be correct provided you do not add ahead of or remove ahead of it (in which case - * you should increment or decrement appropriately....in other words its an arrayList) - * - * @param firstRow - the upper left hand corner's row - * @param firstCol - the upper left hand corner's col - * @param lastRow - the lower right hand corner's row - * @param lastCol - the lower right hand corner's col - * @return new index of said area (don't depend on it if you add/remove) - */ - public void addArea(int firstRow, int firstCol, int lastRow, int lastCol) { - _regions.addCellRangeAddress(firstRow, firstCol, lastRow, lastCol); - } - - /** - * essentially unmerge the cells in the "area" stored at the passed in index - * @param areaIndex - */ - public void removeAreaAt(int areaIndex) { - _regions.remove(areaIndex); + return (short)_numberOfRegions; } /** * @return MergedRegion at the given index representing the area that is Merged (r1,c1 - r2,c2) */ public CellRangeAddress getAreaAt(int index) { - return _regions.getCellRangeAddress(index); + return _regions[_startIndex + index]; } public int getRecordSize() { - return 4 + _regions.getSize(); + return 4 + CellRangeAddressList.getEncodedSize(_numberOfRegions); } public short getSid() { @@ -101,11 +84,16 @@ public final class MergeCellsRecord extends Record { } public int serialize(int offset, byte [] data) { - int dataSize = _regions.getSize(); + int dataSize = CellRangeAddressList.getEncodedSize(_numberOfRegions); - LittleEndian.putShort(data, offset + 0, sid); + LittleEndian.putUShort(data, offset + 0, sid); LittleEndian.putUShort(data, offset + 2, dataSize); - _regions.serialize(offset + 4, data); + int nItems = _numberOfRegions; + LittleEndian.putUShort(data, offset + 4, nItems); + int pos = 6; + for (int i = 0; i < _numberOfRegions; i++) { + pos += _regions[_startIndex + i].serialize(offset+pos, data); + } return 4 + dataSize; } @@ -113,17 +101,16 @@ public final class MergeCellsRecord extends Record { StringBuffer retval = new StringBuffer(); retval.append("[MERGEDCELLS]").append("\n"); - retval.append(" .sid =").append(sid).append("\n"); retval.append(" .numregions =").append(getNumAreas()) .append("\n"); - for (int k = 0; k < _regions.countRanges(); k++) { - CellRangeAddress region = _regions.getCellRangeAddress(k); + for (int k = 0; k < _numberOfRegions; k++) { + CellRangeAddress region = _regions[_startIndex + k]; retval.append(" .rowfrom =").append(region.getFirstRow()) .append("\n"); - retval.append(" .colfrom =").append(region.getFirstColumn()) - .append("\n"); retval.append(" .rowto =").append(region.getLastRow()) + .append("\n"); + retval.append(" .colfrom =").append(region.getFirstColumn()) .append("\n"); retval.append(" .colto =").append(region.getLastColumn()) .append("\n"); @@ -140,13 +127,11 @@ public final class MergeCellsRecord extends Record { } public Object clone() { - MergeCellsRecord rec = new MergeCellsRecord(); - for (int k = 0; k < _regions.countRanges(); k++) { - CellRangeAddress oldRegion = _regions.getCellRangeAddress(k); - rec.addArea(oldRegion.getFirstRow(), oldRegion.getFirstColumn(), - oldRegion.getLastRow(), oldRegion.getLastColumn()); - } - - return rec; + int nRegions = _numberOfRegions; + CellRangeAddress[] clonedRegions = new CellRangeAddress[nRegions]; + for (int i = 0; i < clonedRegions.length; i++) { + clonedRegions[i] = _regions[_startIndex + i].copy(); + } + return new MergeCellsRecord(clonedRegions, 0, nRegions); } } diff --git a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java index 83eade95d..f11e3395c 100644 --- a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java +++ b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,11 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -29,140 +27,128 @@ import org.apache.poi.util.LittleEndian; /** *

Record that contains the functionality page breaks (horizontal and vertical)

- * + * *

The other two classes just specifically set the SIDS for record creation.

- * + * *

REFERENCE: Microsoft Excel SDK page 322 and 420

- * + * * @see HorizontalPageBreakRecord * @see VerticalPageBreakRecord * @author Danny Mui (dmui at apache dot org) */ -public class PageBreakRecord extends Record { - public static final short HORIZONTAL_SID = (short)0x1B; - public static final short VERTICAL_SID = (short)0x1A; - public short sid; - private short numBreaks; - private List breaks; - private Map BreakMap; - +public abstract class PageBreakRecord extends Record { + private static final boolean IS_EMPTY_RECORD_WRITTEN = false; + private static final int[] EMPTY_INT_ARRAY = { }; + + private List _breaks; + private Map _breakMap; + /** - * Since both records store 2byte integers (short), no point in + * Since both records store 2byte integers (short), no point in * differentiating it in the records. *

* The subs (rows or columns, don't seem to be able to set but excel sets * them automatically) */ - public class Break - { + public class Break { - public short main; - public short subFrom; - public short subTo; + public static final int ENCODED_SIZE = 6; + public int main; + public int subFrom; + public int subTo; - public Break(short main, short subFrom, short subTo) + public Break(int main, int subFrom, int subTo) { this.main = main; this.subFrom = subFrom; this.subTo = subTo; } + + public Break(RecordInputStream in) { + main = in.readUShort() - 1; + subFrom = in.readUShort(); + subTo = in.readUShort(); + } + + public int serialize(int offset, byte[] data) { + LittleEndian.putUShort(data, offset + 0, main + 1); + LittleEndian.putUShort(data, offset + 2, subFrom); + LittleEndian.putUShort(data, offset + 4, subTo); + return ENCODED_SIZE; + } } - public PageBreakRecord() - { - + protected PageBreakRecord() { + _breaks = new ArrayList(); + _breakMap = new HashMap(); } - /** - * - * @param sid - */ - public PageBreakRecord(short sid) { - super(); - this.sid = sid; - } - - public PageBreakRecord(RecordInputStream in) - { + protected PageBreakRecord(RecordInputStream in) { super(in); - this.sid = in.getSid(); } protected void fillFields(RecordInputStream in) { - short loadedBreaks = in.readShort(); - setNumBreaks(loadedBreaks); - for(int k = 0; k < loadedBreaks; k++) - { - addBreak((short)(in.readShort()-1), in.readShort(), in.readShort()); + int nBreaks = in.readShort(); + _breaks = new ArrayList(nBreaks + 2); + _breakMap = new HashMap(); + + for(int k = 0; k < nBreaks; k++) { + Break br = new Break(in); + _breaks.add(br); + _breakMap.put(new Integer(br.main), br); } } - public short getSid() - { - return sid; + private int getDataSize() { + return 2 + _breaks.size() * Break.ENCODED_SIZE; + } + public int getRecordSize() { + int nBreaks = _breaks.size(); + if (!IS_EMPTY_RECORD_WRITTEN && nBreaks < 1) { + return 0; + } + return 4 + getDataSize(); } - public int serialize(int offset, byte data[]) - { - int recordsize = getRecordSize(); + + public final int serialize(int offset, byte data[]) { + int nBreaks = _breaks.size(); + if (!IS_EMPTY_RECORD_WRITTEN && nBreaks < 1) { + return 0; + } + int dataSize = getDataSize(); + LittleEndian.putUShort(data, offset + 0, getSid()); + LittleEndian.putUShort(data, offset + 2, dataSize); + LittleEndian.putUShort(data, offset + 4, nBreaks); int pos = 6; - LittleEndian.putShort(data, offset + 0, getSid()); - LittleEndian.putShort(data, offset + 2, (short)(recordsize - 4)); - LittleEndian.putShort(data, offset + 4, getNumBreaks()); - for(Iterator iterator = getBreaksIterator(); iterator.hasNext();) - { - Break Break = (Break)iterator.next(); - LittleEndian.putShort(data, offset + pos, (short)(Break.main + 1)); - pos += 2; - LittleEndian.putShort(data, offset + pos, Break.subFrom); - pos += 2; - LittleEndian.putShort(data, offset + pos, Break.subTo); - pos += 2; + for (int i=0; i @@ -32,11 +30,11 @@ import org.apache.poi.util.BitFieldFactory; * @author aviks : string fixes for UserDefined Style * @version 2.0-pre */ +public final class StyleRecord extends Record { + public final static short sid = 0x0293; + + private static final BitField fHighByte = BitFieldFactory.getInstance(0x01); -public class StyleRecord - extends Record -{ - public final static short sid = 0x293; public final static short STYLE_USER_DEFINED = 0; public final static short STYLE_BUILT_IN = 1; @@ -50,7 +48,6 @@ public class StyleRecord // only for user defined styles private short field_2_name_length; //OO doc says 16 bit length, so we believe private byte field_3_string_options; - private BitField fHighByte; private String field_4_name; public StyleRecord() @@ -77,8 +74,6 @@ public class StyleRecord protected void fillFields(RecordInputStream in) { - fHighByte = BitFieldFactory.getInstance(0x01); //have to init here, since we are being called - //from super, and class level init hasnt been done. field_1_xf_index = in.readShort(); if (getType() == STYLE_BUILT_IN) { diff --git a/src/java/org/apache/poi/hssf/record/TableRecord.java b/src/java/org/apache/poi/hssf/record/TableRecord.java index 7a48e5e0e..237b2cb40 100644 --- a/src/java/org/apache/poi/hssf/record/TableRecord.java +++ b/src/java/org/apache/poi/hssf/record/TableRecord.java @@ -14,8 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - +package org.apache.poi.hssf.record; + +import org.apache.poi.hssf.record.formula.TblPtg; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndian; /** * TableRecord - The record specifies a data table. * This record is preceded by a single Formula record that @@ -24,15 +29,18 @@ * * See p536 of the June 08 binary docs */ -package org.apache.poi.hssf.record; - -import org.apache.poi.hssf.record.formula.TblPtg; -import org.apache.poi.util.BitField; -import org.apache.poi.util.BitFieldFactory; -import org.apache.poi.util.LittleEndian; - -public class TableRecord extends Record { +public final class TableRecord extends Record { public static final short sid = 566; + + private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001); + private static final BitField reserved1 = BitFieldFactory.getInstance(0x0002); + private static final BitField rowOrColInpCell = BitFieldFactory.getInstance(0x0004); + private static final BitField oneOrTwoVar = BitFieldFactory.getInstance(0x0008); + private static final BitField rowDeleted = BitFieldFactory.getInstance(0x0010); + private static final BitField colDeleted = BitFieldFactory.getInstance(0x0020); + private static final BitField reserved2 = BitFieldFactory.getInstance(0x0040); + private static final BitField reserved3 = BitFieldFactory.getInstance(0x0080); + private short field_1_ref_rowFirst; private short field_2_ref_rowLast; private short field_3_ref_colFirst; @@ -45,14 +53,6 @@ public class TableRecord extends Record { private short field_9_rowInputCol; private short field_10_colInputCol; - private BitField alwaysCalc = BitFieldFactory.getInstance(0x0001); - private BitField reserved1 = BitFieldFactory.getInstance(0x0002); - private BitField rowOrColInpCell = BitFieldFactory.getInstance(0x0004); - private BitField oneOrTwoVar = BitFieldFactory.getInstance(0x0008); - private BitField rowDeleted = BitFieldFactory.getInstance(0x0010); - private BitField colDeleted = BitFieldFactory.getInstance(0x0020); - private BitField reserved2 = BitFieldFactory.getInstance(0x0040); - private BitField reserved3 = BitFieldFactory.getInstance(0x0080); protected void fillFields(RecordInputStream in) { field_1_ref_rowFirst = in.readShort(); diff --git a/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java index 4d3dbb43b..2d649247b 100644 --- a/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java +++ b/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java @@ -32,25 +32,25 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class TextObjectBaseRecord - extends Record -{ +public class TextObjectBaseRecord extends Record { public final static short sid = 0x1B6; + + private static final BitField reserved1 = BitFieldFactory.getInstance(0x0001); + private static final BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E); + private static final BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070); + private static final BitField reserved2 = BitFieldFactory.getInstance(0x0180); + private static final BitField textLocked = BitFieldFactory.getInstance(0x0200); + private static final BitField reserved3 = BitFieldFactory.getInstance(0xFC00); + private short field_1_options; - private BitField reserved1 = BitFieldFactory.getInstance(0x1); - private BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E); public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1; public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2; public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3; public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4; - private BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070); public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1; public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2; public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3; public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4; - private BitField reserved2 = BitFieldFactory.getInstance(0x0180); - private BitField textLocked = BitFieldFactory.getInstance(0x200); - private BitField reserved3 = BitFieldFactory.getInstance(0xFC00); private short field_2_textOrientation; public final static short TEXT_ORIENTATION_NONE = 0; public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1; @@ -452,10 +452,4 @@ public class TextObjectBaseRecord { return reserved3.getShortValue(field_1_options); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/TextRecord.java b/src/java/org/apache/poi/hssf/record/TextRecord.java index 702dfbe16..0840fe193 100644 --- a/src/java/org/apache/poi/hssf/record/TextRecord.java +++ b/src/java/org/apache/poi/hssf/record/TextRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * The text record is used to define text stored on a chart. @@ -30,10 +29,26 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class TextRecord - extends Record -{ +public final class TextRecord extends Record { public final static short sid = 0x1025; + + private static final BitField dataLabelPlacement = BitFieldFactory.getInstance(0x000F); + private static final BitField autoColor = BitFieldFactory.getInstance(0x0001); + private static final BitField showKey = BitFieldFactory.getInstance(0x0002); + private static final BitField showValue = BitFieldFactory.getInstance(0x0004); + private static final BitField vertical = BitFieldFactory.getInstance(0x0008); + private static final BitField autoGeneratedText = BitFieldFactory.getInstance(0x0010); + private static final BitField generated = BitFieldFactory.getInstance(0x0020); + private static final BitField autoLabelDeleted = BitFieldFactory.getInstance(0x0040); + private static final BitField autoBackground = BitFieldFactory.getInstance(0x0080); + private static final BitField rotation = BitFieldFactory.getInstance(0x0700); + + private static final BitField showCategoryLabelAsPercentage = BitFieldFactory.getInstance(0x0800); + private static final BitField showValueAsPercentage = BitFieldFactory.getInstance(0x1000); + private static final BitField showBubbleSizes = BitFieldFactory.getInstance(0x2000); + private static final BitField showLabel = BitFieldFactory.getInstance(0x4000); + + private byte field_1_horizontalAlignment; public final static byte HORIZONTAL_ALIGNMENT_LEFT = 1; public final static byte HORIZONTAL_ALIGNMENT_CENTER = 2; @@ -53,26 +68,12 @@ public class TextRecord private int field_7_width; private int field_8_height; private short field_9_options1; - private BitField autoColor = BitFieldFactory.getInstance(0x1); - private BitField showKey = BitFieldFactory.getInstance(0x2); - private BitField showValue = BitFieldFactory.getInstance(0x4); - private BitField vertical = BitFieldFactory.getInstance(0x8); - private BitField autoGeneratedText = BitFieldFactory.getInstance(0x10); - private BitField generated = BitFieldFactory.getInstance(0x20); - private BitField autoLabelDeleted = BitFieldFactory.getInstance(0x40); - private BitField autoBackground = BitFieldFactory.getInstance(0x80); - private BitField rotation = BitFieldFactory.getInstance(0x0700); public final static short ROTATION_NONE = 0; public final static short ROTATION_TOP_TO_BOTTOM = 1; public final static short ROTATION_ROTATED_90_DEGREES = 2; public final static short ROTATION_ROTATED_90_DEGREES_CLOCKWISE = 3; - private BitField showCategoryLabelAsPercentage = BitFieldFactory.getInstance(0x800); - private BitField showValueAsPercentage = BitFieldFactory.getInstance(0x1000); - private BitField showBubbleSizes = BitFieldFactory.getInstance(0x2000); - private BitField showLabel = BitFieldFactory.getInstance(0x4000); private short field_10_indexOfColorValue; private short field_11_options2; - private BitField dataLabelPlacement = BitFieldFactory.getInstance(0x000F); public final static short DATA_LABEL_PLACEMENT_CHART_DEPENDENT = 0; public final static short DATA_LABEL_PLACEMENT_OUTSIDE = 1; public final static short DATA_LABEL_PLACEMENT_INSIDE = 2; @@ -740,10 +741,4 @@ public class TextRecord { return dataLabelPlacement.getShortValue(field_11_options2); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/TickRecord.java b/src/java/org/apache/poi/hssf/record/TickRecord.java index 325dffc40..1b950e3ed 100644 --- a/src/java/org/apache/poi/hssf/record/TickRecord.java +++ b/src/java/org/apache/poi/hssf/record/TickRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * The Tick record defines how tick marks and label positioning/formatting @@ -30,10 +29,14 @@ import org.apache.poi.util.*; * @author Andrew C. Oliver(acoliver at apache.org) */ -public class TickRecord - extends Record -{ - public final static short sid = 0x101e; +public final class TickRecord extends Record { + public final static short sid = 0x101E; + + private static final BitField autoTextColor = BitFieldFactory.getInstance(0x1); + private static final BitField autoTextBackground = BitFieldFactory.getInstance(0x2); + private static final BitField rotation = BitFieldFactory.getInstance(0x1c); + private static final BitField autorotate = BitFieldFactory.getInstance(0x20); + private byte field_1_majorTickType; private byte field_2_minorTickType; private byte field_3_labelPosition; @@ -44,10 +47,6 @@ public class TickRecord private int field_8_zero3; private int field_9_zero4; private short field_10_options; - private BitField autoTextColor = BitFieldFactory.getInstance(0x1); - private BitField autoTextBackground = BitFieldFactory.getInstance(0x2); - private BitField rotation = BitFieldFactory.getInstance(0x1c); - private BitField autorotate = BitFieldFactory.getInstance(0x20); private short field_11_tickColor; private short field_12_zero5; @@ -442,10 +441,4 @@ public class TickRecord { return autorotate.isSet(field_10_options); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/ValueRangeRecord.java b/src/java/org/apache/poi/hssf/record/ValueRangeRecord.java index 44b26659e..6c94c5c54 100644 --- a/src/java/org/apache/poi/hssf/record/ValueRangeRecord.java +++ b/src/java/org/apache/poi/hssf/record/ValueRangeRecord.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,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; - - -import org.apache.poi.util.*; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * The value range record defines the range of the value axis. @@ -30,25 +29,25 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class ValueRangeRecord - extends Record -{ - public final static short sid = 0x101f; +public final class ValueRangeRecord extends Record { + public final static short sid = 0x101f; + + private static final BitField automaticMinimum = BitFieldFactory.getInstance(0x0001); + private static final BitField automaticMaximum = BitFieldFactory.getInstance(0x0002); + private static final BitField automaticMajor = BitFieldFactory.getInstance(0x0004); + private static final BitField automaticMinor = BitFieldFactory.getInstance(0x0008); + private static final BitField automaticCategoryCrossing = BitFieldFactory.getInstance(0x0010); + private static final BitField logarithmicScale = BitFieldFactory.getInstance(0x0020); + private static final BitField valuesInReverse = BitFieldFactory.getInstance(0x0040); + private static final BitField crossCategoryAxisAtMaximum = BitFieldFactory.getInstance(0x0080); + private static final BitField reserved = BitFieldFactory.getInstance(0x0100); + private double field_1_minimumAxisValue; private double field_2_maximumAxisValue; private double field_3_majorIncrement; private double field_4_minorIncrement; private double field_5_categoryAxisCross; private short field_6_options; - private BitField automaticMinimum = BitFieldFactory.getInstance(0x1); - private BitField automaticMaximum = BitFieldFactory.getInstance(0x2); - private BitField automaticMajor = BitFieldFactory.getInstance(0x4); - private BitField automaticMinor = BitFieldFactory.getInstance(0x8); - private BitField automaticCategoryCrossing = BitFieldFactory.getInstance(0x10); - private BitField logarithmicScale = BitFieldFactory.getInstance(0x20); - private BitField valuesInReverse = BitFieldFactory.getInstance(0x40); - private BitField crossCategoryAxisAtMaximum = BitFieldFactory.getInstance(0x80); - private BitField reserved = BitFieldFactory.getInstance(0x100); public ValueRangeRecord() @@ -432,10 +431,4 @@ public class ValueRangeRecord { return reserved.isSet(field_6_options); } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java b/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java index 6c715494f..fccb7ccda 100644 --- a/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java +++ b/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.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,46 +14,53 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; +import java.util.Iterator; + /** - * VerticalPageBreak record that stores page breaks at columns - *

- * This class is just used so that SID compares work properly in the RecordFactory + * VerticalPageBreak (0x001A) record that stores page breaks at columns

+ * * @see PageBreakRecord - * @author Danny Mui (dmui at apache dot org) + * @author Danny Mui (dmui at apache dot org) */ -public class VerticalPageBreakRecord extends PageBreakRecord { - - public static final short sid = PageBreakRecord.VERTICAL_SID; - +public final class VerticalPageBreakRecord extends PageBreakRecord { + + public static final short sid = 0x001A; + /** - * + * Creates an empty vertical page break record */ public VerticalPageBreakRecord() { - super(); + } /** - * @param sid - */ - public VerticalPageBreakRecord(short sid) { - super(sid); - } - - /** - * @param in the RecordInputstream to read the record from + * @param in the RecordInputstream to read the record from */ public VerticalPageBreakRecord(RecordInputStream in) { super(in); } - /* (non-Javadoc) - * @see org.apache.poi.hssf.record.Record#getSid() - */ + protected void validateSid(short id) { + if (id != getSid()) { + throw new RecordFormatException( + "NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id); + } + } + public short getSid() { return sid; } + public Object clone() { + PageBreakRecord result = new VerticalPageBreakRecord(); + Iterator iterator = getBreaksIterator(); + while (iterator.hasNext()) { + Break original = (Break) iterator.next(); + result.addBreak(original.main, original.subFrom, original.subTo); + } + return result; + } } diff --git a/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java b/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java index e2bb6d560..6e60ef41a 100644 --- a/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java +++ b/src/java/org/apache/poi/hssf/record/WindowTwoRecord.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; @@ -31,34 +29,27 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ - -public class WindowTwoRecord - extends Record -{ - public final static short sid = 0x23e; - private short field_1_options; +public final class WindowTwoRecord extends Record { + public final static short sid = 0x023E; // bitfields - private BitField displayFormulas = BitFieldFactory.getInstance(0x01); - private BitField displayGridlines = BitFieldFactory.getInstance(0x02); - private BitField displayRowColHeadings = BitFieldFactory.getInstance(0x04); - private BitField freezePanes = BitFieldFactory.getInstance(0x08); - private BitField displayZeros = BitFieldFactory.getInstance(0x10); - private BitField defaultHeader = - BitFieldFactory.getInstance(0x20); // if false use color in field 4 - - // if true use default foreground - // for headers - private BitField arabic = - BitFieldFactory.getInstance(0x40); // for our desert dwelling friends - private BitField displayGuts = BitFieldFactory.getInstance(0x80); - private BitField freezePanesNoSplit = BitFieldFactory.getInstance(0x100); - private BitField selected = BitFieldFactory.getInstance(0x200); - private BitField active = BitFieldFactory.getInstance(0x400); - private BitField savedInPageBreakPreview = BitFieldFactory.getInstance(0x800); - + private static final BitField displayFormulas = BitFieldFactory.getInstance(0x01); + private static final BitField displayGridlines = BitFieldFactory.getInstance(0x02); + private static final BitField displayRowColHeadings = BitFieldFactory.getInstance(0x04); + private static final BitField freezePanes = BitFieldFactory.getInstance(0x08); + private static final BitField displayZeros = BitFieldFactory.getInstance(0x10); + /** if false use color in field 4 if true use default foreground for headers */ + private static final BitField defaultHeader = BitFieldFactory.getInstance(0x20); + private static final BitField arabic = BitFieldFactory.getInstance(0x040); + private static final BitField displayGuts = BitFieldFactory.getInstance(0x080); + private static final BitField freezePanesNoSplit = BitFieldFactory.getInstance(0x100); + private static final BitField selected = BitFieldFactory.getInstance(0x200); + private static final BitField active = BitFieldFactory.getInstance(0x400); + private static final BitField savedInPageBreakPreview = BitFieldFactory.getInstance(0x800); // 4-7 reserved // end bitfields + + private short field_1_options; private short field_2_top_row; private short field_3_left_col; private int field_4_header_color; 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 cc74b98f6..9fd2412a9 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java @@ -14,20 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ + package org.apache.poi.hssf.record.aggregates; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.CFHeaderRecord; import org.apache.poi.hssf.record.CFRuleRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.ss.util.Region; import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; /** * CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord @@ -37,15 +37,12 @@ import org.apache.poi.util.POILogger; * @author Dmitriy Kumshayev * */ -public final class CFRecordsAggregate extends Record -{ +public final class CFRecordsAggregate extends Record { /** Excel allows up to 3 conditional formating rules */ private static final int MAX_CONDTIONAL_FORMAT_RULES = 3; public final static short sid = -2008; // not a real BIFF record - private static POILogger log = POILogFactory.getLogger(CFRecordsAggregate.class); - private final CFHeaderRecord header; /** List of CFRuleRecord objects */ @@ -79,9 +76,8 @@ public final class CFRecordsAggregate extends Record * @param offset - position of {@link CFHeaderRecord} object in the list of Record objects * @return CFRecordsAggregate object */ - public static CFRecordsAggregate createCFAggregate(List recs, int pOffset) - { - Record rec = ( Record ) recs.get(pOffset); + public static CFRecordsAggregate createCFAggregate(RecordStream rs) { + Record rec = rs.getNext(); if (rec.getSid() != CFHeaderRecord.sid) { throw new IllegalStateException("next record sid was " + rec.getSid() + " instead of " + CFHeaderRecord.sid + " as expected"); @@ -91,35 +87,10 @@ public final class CFRecordsAggregate extends Record int nRules = header.getNumberOfConditionalFormats(); CFRuleRecord[] rules = new CFRuleRecord[nRules]; - int offset = pOffset; - int countFound = 0; - while (countFound < rules.length) { - offset++; - if(offset>=recs.size()) { - break; - } - rec = (Record)recs.get(offset); - if(rec instanceof CFRuleRecord) { - rules[countFound] = (CFRuleRecord) rec; - countFound++; - } else { - break; - } - } - - if (countFound < nRules) - { // TODO -(MAR-2008) can this ever happen? write junit - - if (log.check(POILogger.DEBUG)) - { - log.log(POILogger.DEBUG, "Expected " + nRules + " Conditional Formats, " - + "but found " + countFound + " rules"); - } - header.setNumberOfConditionalFormats(nRules); - CFRuleRecord[] lessRules = new CFRuleRecord[countFound]; - System.arraycopy(rules, 0, lessRules, 0, countFound); - rules = lessRules; + for (int i = 0; i < rules.length; i++) { + rules[i] = (CFRuleRecord) rs.getNext(); } + return new CFRecordsAggregate(header, rules); } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java index 6df796c2a..b24d8c5b4 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java @@ -1,72 +1,52 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + package org.apache.poi.hssf.record.aggregates; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.ColumnInfoRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.RecordInputStream; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; /** * @author Glen Stampoultzis * @version $Id$ */ -public class ColumnInfoRecordsAggregate - extends Record -{ -// int size = 0; - List records = null; +public final class ColumnInfoRecordsAggregate extends RecordAggregate { + private final List records; - public ColumnInfoRecordsAggregate() - { - records = new ArrayList(); - } - - /** You never fill an aggregate */ - protected void fillFields(RecordInputStream in) - { - } - - /** Not required by an aggregate */ - protected void validateSid(short id) - { - } - - /** It's an aggregate... just made something up */ - public short getSid() - { - return -1012; - } - - public int getRecordSize() - { - int size = 0; - for ( Iterator iterator = records.iterator(); iterator.hasNext(); ) - size += ( (ColumnInfoRecord) iterator.next() ).getRecordSize(); - return size; - } - - public Iterator getIterator() - { - return records.iterator(); - } + /** + * Creates an empty aggregate + */ + public ColumnInfoRecordsAggregate() { + records = new ArrayList(); + } + public ColumnInfoRecordsAggregate(RecordStream rs) { + this(); + + while(rs.peekNextClass() == ColumnInfoRecord.class) { + records.add(rs.getNext()); + } + if (records.size() < 1) { + throw new RuntimeException("No column info records found"); + } + } /** * Performs a deep clone of the record @@ -105,25 +85,14 @@ public class ColumnInfoRecordsAggregate return records.size(); } - /** - * called by the class that is responsible for writing this sucker. - * Subclasses should implement this so that their data is passed back in a - * byte array. - * - * @param offset offset to begin writing at - * @param data byte array containing instance data - * @return number of bytes written - */ - public int serialize(int offset, byte [] data) - { - Iterator itr = records.iterator(); - int pos = offset; - - while (itr.hasNext()) - { - pos += (( Record ) itr.next()).serialize(pos, data); - } - return pos - offset; + public void visitContainedRecords(RecordVisitor rv) { + int nItems = records.size(); + if (nItems < 1) { + return; + } + for(int i=0; i

* Description: Defined a area in Extern Sheet.

@@ -38,14 +37,16 @@ import org.apache.poi.util.LittleEndian; public final class Area3DPtg extends OperandPtg implements AreaI { public final static byte sid = 0x3b; private final static int SIZE = 11; // 10 + 1 for Ptg + + private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000); + private static final BitField colRelative = BitFieldFactory.getInstance(0x4000); + private short field_1_index_extern_sheet; private int field_2_first_row; private int field_3_last_row; private int field_4_first_column; private int field_5_last_column; - private BitField rowRelative = BitFieldFactory.getInstance( 0x8000 ); - private BitField colRelative = BitFieldFactory.getInstance( 0x4000 ); /** Creates new AreaPtg */ public Area3DPtg() diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java index 52a5518e4..6b48036fe 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -36,6 +36,10 @@ import org.apache.poi.util.LittleEndian; */ public final class Ref3DPtg extends OperandPtg { public final static byte sid = 0x3a; + + private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000); + private static final BitField colRelative = BitFieldFactory.getInstance(0x4000); + private final static int SIZE = 7; // 6 + 1 for Ptg private short field_1_index_extern_sheet; /** The row index - zero based unsigned 16 bit value */ @@ -46,8 +50,6 @@ public final class Ref3DPtg extends OperandPtg { * - bit 15 - isColumnRelative */ private int field_3_column; - private BitField rowRelative = BitFieldFactory.getInstance(0x8000); - private BitField colRelative = BitFieldFactory.getInstance(0x4000); /** Creates new AreaPtg */ public Ref3DPtg() {} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index f110d71f9..9abcebcd7 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -48,6 +48,7 @@ import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.ObjRecord; import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.SubRecord; import org.apache.poi.hssf.record.TextObjectRecord; @@ -1154,7 +1155,7 @@ public class HSSFCell implements Cell HSSFComment comment = null; HashMap txshapes = new HashMap(); //map shapeId and TextObjectRecord for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) { - Record rec = ( Record ) it.next(); + RecordBase rec = (RecordBase) it.next(); if (rec instanceof NoteRecord){ NoteRecord note = (NoteRecord)rec; if (note.getRow() == row && note.getColumn() == column){ @@ -1196,7 +1197,7 @@ public class HSSFCell implements Cell */ public HSSFHyperlink getHyperlink(){ for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) { - Record rec = ( Record ) it.next(); + RecordBase rec = (RecordBase) it.next(); if (rec instanceof HyperlinkRecord){ HyperlinkRecord link = (HyperlinkRecord)rec; if(link.getFirstColumn() == record.getColumn() && link.getFirstRow() == record.getRow()){ diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index dcf68b9cf..7dd85e364 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -1464,43 +1464,19 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet } /** - * Retrieves all the horizontal page breaks - * @return all the horizontal page breaks, or null if there are no row page breaks + * @return row indexes of all the horizontal page breaks, never null */ public int[] getRowBreaks(){ //we can probably cache this information, but this should be a sparsely used function - int count = sheet.getNumRowBreaks(); - if (count > 0) { - int[] returnValue = new int[count]; - Iterator iterator = sheet.getRowBreaks(); - int i = 0; - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - returnValue[i++] = breakItem.main; - } - return returnValue; - } - return null; + return sheet.getRowBreaks(); } /** - * Retrieves all the vertical page breaks - * @return all the vertical page breaks, or null if there are no column page breaks + * @return column indexes of all the vertical page breaks, never null */ - public short[] getColumnBreaks(){ + public int[] getColumnBreaks(){ //we can probably cache this information, but this should be a sparsely used function - int count = sheet.getNumColumnBreaks(); - if (count > 0) { - short[] returnValue = new short[count]; - Iterator iterator = sheet.getColumnBreaks(); - int i = 0; - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - returnValue[i++] = breakItem.main; - } - return returnValue; - } - return null; + return sheet.getColumnBreaks(); } diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddressList.java b/src/java/org/apache/poi/ss/util/CellRangeAddressList.java index 8773c34ee..72b588248 100644 --- a/src/java/org/apache/poi/ss/util/CellRangeAddressList.java +++ b/src/java/org/apache/poi/ss/util/CellRangeAddressList.java @@ -99,7 +99,14 @@ public class CellRangeAddressList { } public int getSize() { - return 2 + CellRangeAddress.getEncodedSize(_list.size()); + return getEncodedSize(_list.size()); + } + /** + * @return the total size of for the specified number of ranges, + * including the initial 2 byte range count + */ + public static int getEncodedSize(int numberOfRanges) { + return 2 + CellRangeAddress.getEncodedSize(numberOfRanges); } public int serialize(int offset, byte[] data) { diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java index 055f8452d..b04b5d453 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java @@ -631,7 +631,7 @@ public interface Sheet extends Iterable { * Retrieves all the vertical page breaks * @return all the vertical page breaks, or null if there are no column page breaks */ - short[] getColumnBreaks(); + int[] getColumnBreaks(); /** * Sets a page break at the indicated column diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index a76711a7f..f619be8d2 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -312,15 +312,15 @@ public class XSSFSheet implements Sheet { return null; } - public short[] getColumnBreaks() { + public int[] getColumnBreaks() { CTBreak[] brkArray = getSheetTypeColumnBreaks().getBrkArray(); if (brkArray.length == 0) { return null; } - short[] breaks = new short[brkArray.length]; + int[] breaks = new int[brkArray.length]; for (int i = 0 ; i < brkArray.length ; i++) { CTBreak brk = brkArray[i]; - breaks[i] = (short) brk.getId(); + breaks[i] = (int)brk.getId(); } return breaks; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java index e3f5bb23e..ab7cc61ef 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.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.usermodel; @@ -56,7 +54,7 @@ import org.apache.poi.hssf.record.PlotAreaRecord; import org.apache.poi.hssf.record.PlotGrowthRecord; import org.apache.poi.hssf.record.PrintSetupRecord; import org.apache.poi.hssf.record.ProtectRecord; -import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.SeriesIndexRecord; import org.apache.poi.hssf.record.SeriesRecord; @@ -76,8 +74,7 @@ import org.apache.poi.hssf.record.formula.Area3DPtg; * * @author Glen Stampoultzis (glens at apache.org) */ -public class HSSFChart -{ +public final class HSSFChart { private ChartRecord chartRecord; private LegendRecord legendRecord; @@ -90,897 +87,897 @@ public class HSSFChart this.chartRecord = chartRecord; } - /** - * Creates a bar chart. API needs some work. :) - *

- * NOTE: Does not yet work... checking it in just so others - * can take a look. - */ - public void createBarChart( HSSFWorkbook workbook, HSSFSheet sheet ) - { - - List records = new ArrayList(); - records.add( createMSDrawingObjectRecord() ); - records.add( createOBJRecord() ); - records.add( createBOFRecord() ); - records.add( createHeaderRecord() ); - records.add( createFooterRecord() ); - records.add( createHCenterRecord() ); - records.add( createVCenterRecord() ); - records.add( createPrintSetupRecord() ); - // unknown 33 - records.add( createFontBasisRecord1() ); - records.add( createFontBasisRecord2() ); - records.add( createProtectRecord() ); - records.add( createUnitsRecord() ); - records.add( createChartRecord( 0, 0, 30434904, 19031616 ) ); - records.add( createBeginRecord() ); - records.add( createSCLRecord( (short) 1, (short) 1 ) ); - records.add( createPlotGrowthRecord( 65536, 65536 ) ); - records.add( createFrameRecord1() ); - records.add( createBeginRecord() ); - records.add( createLineFormatRecord(true) ); - records.add( createAreaFormatRecord1() ); - records.add( createEndRecord() ); - records.add( createSeriesRecord() ); - records.add( createBeginRecord() ); - records.add( createTitleLinkedDataRecord() ); - records.add( createValuesLinkedDataRecord() ); - records.add( createCategoriesLinkedDataRecord() ); - records.add( createDataFormatRecord() ); - // records.add(createBeginRecord()); - // unknown - // records.add(createEndRecord()); - records.add( createSeriesToChartGroupRecord() ); - records.add( createEndRecord() ); - records.add( createSheetPropsRecord() ); - records.add( createDefaultTextRecord( DefaultDataLabelTextPropertiesRecord.CATEGORY_DATA_TYPE_ALL_TEXT_CHARACTERISTIC ) ); - records.add( createAllTextRecord() ); - records.add( createBeginRecord() ); - // unknown - records.add( createFontIndexRecord( 5 ) ); - records.add( createDirectLinkRecord() ); - records.add( createEndRecord() ); - records.add( createDefaultTextRecord( (short) 3 ) ); // eek, undocumented text type - records.add( createUnknownTextRecord() ); - records.add( createBeginRecord() ); - records.add( createFontIndexRecord( (short) 6 ) ); - records.add( createDirectLinkRecord() ); - records.add( createEndRecord() ); - - records.add( createAxisUsedRecord( (short) 1 ) ); - createAxisRecords( records ); - - records.add( createEndRecord() ); - records.add( createDimensionsRecord() ); - records.add( createSeriesIndexRecord(2) ); - records.add( createSeriesIndexRecord(1) ); - records.add( createSeriesIndexRecord(3) ); - records.add( createEOFRecord() ); - - - - sheet.insertChartRecords( records ); - workbook.insertChartRecord(); - } - - /** - * Returns all the charts for the given sheet. - * - * NOTE: You won't be able to do very much with - * these charts yet, as this is very limited support - */ - public static HSSFChart[] getSheetCharts(HSSFSheet sheet) { - List charts = new ArrayList(); - HSSFChart lastChart = null; - - // Find records of interest - List records = sheet.getSheet().getRecords(); - for(Iterator it = records.iterator(); it.hasNext();) { - Record r = (Record)it.next(); - - if(r instanceof ChartRecord) { - lastChart = new HSSFChart((ChartRecord)r); - charts.add(lastChart); - } - if(r instanceof LegendRecord) { - lastChart.legendRecord = (LegendRecord)r; - } - if(r instanceof SeriesRecord) { - HSSFSeries series = lastChart.new HSSFSeries( (SeriesRecord)r ); - lastChart.series.add(series); - } - if(r instanceof ChartTitleFormatRecord) { - lastChart.chartTitleFormat = - (ChartTitleFormatRecord)r; - } - if(r instanceof SeriesTextRecord) { - // Applies to a series, unless we've seen - // a legend already - SeriesTextRecord str = (SeriesTextRecord)r; - if(lastChart.legendRecord == null && - lastChart.series.size() > 0) { - HSSFSeries series = (HSSFSeries) - lastChart.series.get(lastChart.series.size()-1); - series.seriesTitleText = str; - } else { - lastChart.chartTitleText = str; - } - } - } - - return (HSSFChart[]) - charts.toArray( new HSSFChart[charts.size()] ); - } - - /** Get the X offset of the chart */ - public int getChartX() { return chartRecord.getX(); } - /** Get the Y offset of the chart */ - public int getChartY() { return chartRecord.getY(); } - /** Get the width of the chart. {@link ChartRecord} */ - public int getChartWidth() { return chartRecord.getWidth(); } - /** Get the height of the chart. {@link ChartRecord} */ - public int getChartHeight() { return chartRecord.getHeight(); } - - /** Sets the X offset of the chart */ - public void setChartX(int x) { chartRecord.setX(x); } - /** Sets the Y offset of the chart */ - public void setChartY(int y) { chartRecord.setY(y); } - /** Sets the width of the chart. {@link ChartRecord} */ - public void setChartWidth(int width) { chartRecord.setWidth(width); } - /** Sets the height of the chart. {@link ChartRecord} */ - public void setChartHeight(int height) { chartRecord.setHeight(height); } - - /** - * Returns the series of the chart - */ - public HSSFSeries[] getSeries() { - return (HSSFSeries[]) - series.toArray(new HSSFSeries[series.size()]); - } - - /** - * Returns the chart's title, if there is one, - * or null if not - */ - public String getChartTitle() { - if(chartTitleText != null) { - return chartTitleText.getText(); - } - return null; - } - - /** - * Changes the chart's title, but only if there - * was one already. - * TODO - add in the records if not - */ - public void setChartTitle(String title) { - if(chartTitleText != null) { - chartTitleText.setText(title); - } else { - throw new IllegalStateException("No chart title found to change"); - } - } - - - private EOFRecord createEOFRecord() - { - return new EOFRecord(); - } - - private SeriesIndexRecord createSeriesIndexRecord( int index ) - { - SeriesIndexRecord r = new SeriesIndexRecord(); - r.setIndex((short)index); - return r; - } - - private DimensionsRecord createDimensionsRecord() - { - DimensionsRecord r = new DimensionsRecord(); - r.setFirstRow(0); - r.setLastRow(31); - r.setFirstCol((short)0); - r.setLastCol((short)1); - return r; - } - - private HCenterRecord createHCenterRecord() - { - HCenterRecord r = new HCenterRecord(); - r.setHCenter(false); - return r; - } - - private VCenterRecord createVCenterRecord() - { - VCenterRecord r = new VCenterRecord(); - r.setVCenter(false); - return r; - } - - private PrintSetupRecord createPrintSetupRecord() - { - PrintSetupRecord r = new PrintSetupRecord(); - r.setPaperSize((short)0); - r.setScale((short)18); - r.setPageStart((short)1); - r.setFitWidth((short)1); - r.setFitHeight((short)1); - r.setLeftToRight(false); - r.setLandscape(false); - r.setValidSettings(true); - r.setNoColor(false); - r.setDraft(false); - r.setNotes(false); - r.setNoOrientation(false); - r.setUsePage(false); - r.setHResolution((short)0); - r.setVResolution((short)0); - r.setHeaderMargin(0.5); - r.setFooterMargin(0.5); - r.setCopies((short)15); // what the ?? - return r; - } - - private FontBasisRecord createFontBasisRecord1() - { - FontBasisRecord r = new FontBasisRecord(); - r.setXBasis((short)9120); - r.setYBasis((short)5640); - r.setHeightBasis((short)200); - r.setScale((short)0); - r.setIndexToFontTable((short)5); - return r; - } - - private FontBasisRecord createFontBasisRecord2() - { - FontBasisRecord r = createFontBasisRecord1(); - r.setIndexToFontTable((short)6); - return r; - } - - private ProtectRecord createProtectRecord() - { - ProtectRecord r = new ProtectRecord(); - r.setProtect(false); - return r; - } - - private FooterRecord createFooterRecord() - { - FooterRecord r = new FooterRecord(); - r.setFooter(null); - return r; - } - - private HeaderRecord createHeaderRecord() - { - HeaderRecord r = new HeaderRecord(); - r.setHeader(null); - return r; - } - - private BOFRecord createBOFRecord() - { - BOFRecord r = new BOFRecord(); - r.setVersion((short)600); - r.setType((short)20); - r.setBuild((short)0x1CFE); - r.setBuildYear((short)1997); - r.setHistoryBitMask(0x40C9); - r.setRequiredVersion(106); - return r; - } - - private UnknownRecord createOBJRecord() - { - byte[] data = { - (byte) 0x15, (byte) 0x00, (byte) 0x12, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x11, (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xB8, (byte) 0x03, - (byte) 0x87, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - }; - - return new UnknownRecord( (short) 0x005D, data ); - } - - private UnknownRecord createMSDrawingObjectRecord() - { - // Since we haven't created this object yet we'll just put in the raw - // form for the moment. - - byte[] data = { - (byte)0x0F, (byte)0x00, (byte)0x02, (byte)0xF0, (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x08, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x0F, (byte)0x00, (byte)0x03, (byte)0xF0, (byte)0xA8, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x0F, (byte)0x00, (byte)0x04, (byte)0xF0, (byte)0x28, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, (byte)0xF0, (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x02, (byte)0x00, (byte)0x0A, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x0F, (byte)0x00, (byte)0x04, (byte)0xF0, (byte)0x70, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x92, (byte)0x0C, (byte)0x0A, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x02, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x93, (byte)0x00, (byte)0x0B, (byte)0xF0, (byte)0x36, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x7F, (byte)0x00, (byte)0x04, (byte)0x01, (byte)0x04, (byte)0x01, (byte)0xBF, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x81, (byte)0x01, (byte)0x4E, (byte)0x00, - (byte)0x00, (byte)0x08, (byte)0x83, (byte)0x01, (byte)0x4D, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0xBF, (byte)0x01, (byte)0x10, (byte)0x00, (byte)0x11, (byte)0x00, (byte)0xC0, (byte)0x01, - (byte)0x4D, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0xFF, (byte)0x01, (byte)0x08, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x3F, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, - (byte)0xBF, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0xF0, (byte)0x12, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x04, (byte)0x00, (byte)0xC0, (byte)0x02, (byte)0x0A, (byte)0x00, (byte)0xF4, (byte)0x00, (byte)0x0E, (byte)0x00, (byte)0x66, (byte)0x01, (byte)0x20, (byte)0x00, (byte)0xE9, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x11, (byte)0xF0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 - }; - - return new UnknownRecord((short)0x00EC, data); - } - - private void createAxisRecords( List records ) - { - records.add( createAxisParentRecord() ); - records.add( createBeginRecord() ); - records.add( createAxisRecord( AxisRecord.AXIS_TYPE_CATEGORY_OR_X_AXIS ) ); - records.add( createBeginRecord() ); - records.add( createCategorySeriesAxisRecord() ); - records.add( createAxisOptionsRecord() ); - records.add( createTickRecord1() ); - records.add( createEndRecord() ); - records.add( createAxisRecord( AxisRecord.AXIS_TYPE_VALUE_AXIS ) ); - records.add( createBeginRecord() ); - records.add( createValueRangeRecord() ); - records.add( createTickRecord2() ); - records.add( createAxisLineFormatRecord( AxisLineFormatRecord.AXIS_TYPE_MAJOR_GRID_LINE ) ); - records.add( createLineFormatRecord(false) ); - records.add( createEndRecord() ); - records.add( createPlotAreaRecord() ); - records.add( createFrameRecord2() ); - records.add( createBeginRecord() ); - records.add( createLineFormatRecord2() ); - records.add( createAreaFormatRecord2() ); - records.add( createEndRecord() ); - records.add( createChartFormatRecord() ); - records.add( createBeginRecord() ); - records.add( createBarRecord() ); - // unknown 1022 - records.add( createLegendRecord() ); - records.add( createBeginRecord() ); - // unknown 104f - records.add( createTextRecord() ); - records.add( createBeginRecord() ); - // unknown 104f - records.add( createLinkedDataRecord() ); - records.add( createEndRecord() ); - records.add( createEndRecord() ); - records.add( createEndRecord() ); - records.add( createEndRecord() ); - } - - private LinkedDataRecord createLinkedDataRecord() - { - LinkedDataRecord r = new LinkedDataRecord(); - r.setLinkType(LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT); - r.setReferenceType(LinkedDataRecord.REFERENCE_TYPE_DIRECT); - r.setCustomNumberFormat(false); - r.setIndexNumberFmtRecord((short)0); - r.setFormulaOfLink( new LinkedDataFormulaField() ); - return r; - } - - private TextRecord createTextRecord() - { - TextRecord r = new TextRecord(); - r.setHorizontalAlignment(TextRecord.HORIZONTAL_ALIGNMENT_CENTER); - r.setVerticalAlignment(TextRecord.VERTICAL_ALIGNMENT_CENTER); - r.setDisplayMode((short)1); - r.setRgbColor(0x00000000); - r.setX(-37); - r.setY(-60); - r.setWidth(0); - r.setHeight(0); - r.setAutoColor(true); - r.setShowKey(false); - r.setShowValue(false); - r.setVertical(false); - r.setAutoGeneratedText(true); - r.setGenerated(true); - r.setAutoLabelDeleted(false); - r.setAutoBackground(true); - r.setRotation((short)0); - r.setShowCategoryLabelAsPercentage(false); - r.setShowValueAsPercentage(false); - r.setShowBubbleSizes(false); - r.setShowLabel(false); - r.setIndexOfColorValue((short)77); - r.setDataLabelPlacement((short)0); - r.setTextRotation((short)0); - return r; - } - - private LegendRecord createLegendRecord() - { - LegendRecord r = new LegendRecord(); - r.setXAxisUpperLeft(3542); - r.setYAxisUpperLeft(1566); - r.setXSize(437); - r.setYSize(213); - r.setType(LegendRecord.TYPE_RIGHT); - r.setSpacing(LegendRecord.SPACING_MEDIUM); - r.setAutoPosition(true); - r.setAutoSeries(true); - r.setAutoXPositioning(true); - r.setAutoYPositioning(true); - r.setVertical(true); - r.setDataTable(false); - return r; - } - - private BarRecord createBarRecord() - { - BarRecord r = new BarRecord(); - r.setBarSpace((short)0); - r.setCategorySpace((short)150); - r.setHorizontal(false); - r.setStacked(false); - r.setDisplayAsPercentage(false); - r.setShadow(false); - return r; - } - - private ChartFormatRecord createChartFormatRecord() - { - ChartFormatRecord r = new ChartFormatRecord(); - r.setXPosition(0); - r.setYPosition(0); - r.setWidth(0); - r.setHeight(0); - r.setVaryDisplayPattern(false); - return r; - } - - private PlotAreaRecord createPlotAreaRecord() - { - PlotAreaRecord r = new PlotAreaRecord( ); - return r; - } - - private AxisLineFormatRecord createAxisLineFormatRecord( short format ) - { - AxisLineFormatRecord r = new AxisLineFormatRecord(); - r.setAxisType( format ); - return r; - } - - private ValueRangeRecord createValueRangeRecord() - { - ValueRangeRecord r = new ValueRangeRecord(); - r.setMinimumAxisValue( 0.0 ); - r.setMaximumAxisValue( 0.0 ); - r.setMajorIncrement( 0 ); - r.setMinorIncrement( 0 ); - r.setCategoryAxisCross( 0 ); - r.setAutomaticMinimum( true ); - r.setAutomaticMaximum( true ); - r.setAutomaticMajor( true ); - r.setAutomaticMinor( true ); - r.setAutomaticCategoryCrossing( true ); - r.setLogarithmicScale( false ); - r.setValuesInReverse( false ); - r.setCrossCategoryAxisAtMaximum( false ); - r.setReserved( true ); // what's this do?? - return r; - } - - private TickRecord createTickRecord1() - { - TickRecord r = new TickRecord(); - r.setMajorTickType( (byte) 2 ); - r.setMinorTickType( (byte) 0 ); - r.setLabelPosition( (byte) 3 ); - r.setBackground( (byte) 1 ); - r.setLabelColorRgb( 0 ); - r.setZero1( (short) 0 ); - r.setZero2( (short) 0 ); - r.setZero3( (short) 45 ); - r.setAutorotate( true ); - r.setAutoTextBackground( true ); - r.setRotation( (short) 0 ); - r.setAutorotate( true ); - r.setTickColor( (short) 77 ); - return r; - } - - private TickRecord createTickRecord2() - { - TickRecord r = createTickRecord1(); - r.setZero3((short)0); - return r; - } - - private AxisOptionsRecord createAxisOptionsRecord() - { - AxisOptionsRecord r = new AxisOptionsRecord(); - r.setMinimumCategory( (short) -28644 ); - r.setMaximumCategory( (short) -28715 ); - r.setMajorUnitValue( (short) 2 ); - r.setMajorUnit( (short) 0 ); - r.setMinorUnitValue( (short) 1 ); - r.setMinorUnit( (short) 0 ); - r.setBaseUnit( (short) 0 ); - r.setCrossingPoint( (short) -28644 ); - r.setDefaultMinimum( true ); - r.setDefaultMaximum( true ); - r.setDefaultMajor( true ); - r.setDefaultMinorUnit( true ); - r.setIsDate( true ); - r.setDefaultBase( true ); - r.setDefaultCross( true ); - r.setDefaultDateSettings( true ); - return r; - } - - private CategorySeriesAxisRecord createCategorySeriesAxisRecord() - { - CategorySeriesAxisRecord r = new CategorySeriesAxisRecord(); - r.setCrossingPoint( (short) 1 ); - r.setLabelFrequency( (short) 1 ); - r.setTickMarkFrequency( (short) 1 ); - r.setValueAxisCrossing( true ); - r.setCrossesFarRight( false ); - r.setReversed( false ); - return r; - } - - private AxisRecord createAxisRecord( short axisType ) - { - AxisRecord r = new AxisRecord(); - r.setAxisType( axisType ); - return r; - } - - private AxisParentRecord createAxisParentRecord() - { - AxisParentRecord r = new AxisParentRecord(); - r.setAxisType( AxisParentRecord.AXIS_TYPE_MAIN ); - r.setX( 479 ); - r.setY( 221 ); - r.setWidth( 2995 ); - r.setHeight( 2902 ); - return r; - } - - private AxisUsedRecord createAxisUsedRecord( short numAxis ) - { - AxisUsedRecord r = new AxisUsedRecord(); - r.setNumAxis( numAxis ); - return r; - } - - private LinkedDataRecord createDirectLinkRecord() - { - LinkedDataRecord r = new LinkedDataRecord(); - r.setLinkType( LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT ); - r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); - r.setCustomNumberFormat( false ); - r.setIndexNumberFmtRecord( (short) 0 ); - r.setFormulaOfLink( new LinkedDataFormulaField() ); - return r; - } - - private FontIndexRecord createFontIndexRecord( int index ) - { - FontIndexRecord r = new FontIndexRecord(); - r.setFontIndex( (short) index ); - return r; - } - - private TextRecord createAllTextRecord() - { - TextRecord r = new TextRecord(); - r.setHorizontalAlignment( TextRecord.HORIZONTAL_ALIGNMENT_CENTER ); - r.setVerticalAlignment( TextRecord.VERTICAL_ALIGNMENT_CENTER ); - r.setDisplayMode( TextRecord.DISPLAY_MODE_TRANSPARENT ); - r.setRgbColor( 0 ); - r.setX( -37 ); - r.setY( -60 ); - r.setWidth( 0 ); - r.setHeight( 0 ); - r.setAutoColor( true ); - r.setShowKey( false ); - r.setShowValue( true ); - r.setVertical( false ); - r.setAutoGeneratedText( true ); - r.setGenerated( true ); - r.setAutoLabelDeleted( false ); - r.setAutoBackground( true ); - r.setRotation( (short) 0 ); - r.setShowCategoryLabelAsPercentage( false ); - r.setShowValueAsPercentage( false ); - r.setShowBubbleSizes( false ); - r.setShowLabel( false ); - r.setIndexOfColorValue( (short) 77 ); - r.setDataLabelPlacement( (short) 0 ); - r.setTextRotation( (short) 0 ); - return r; - } - - private TextRecord createUnknownTextRecord() - { - TextRecord r = new TextRecord(); - r.setHorizontalAlignment( TextRecord.HORIZONTAL_ALIGNMENT_CENTER ); - r.setVerticalAlignment( TextRecord.VERTICAL_ALIGNMENT_CENTER ); - r.setDisplayMode( TextRecord.DISPLAY_MODE_TRANSPARENT ); - r.setRgbColor( 0 ); - r.setX( -37 ); - r.setY( -60 ); - r.setWidth( 0 ); - r.setHeight( 0 ); - r.setAutoColor( true ); - r.setShowKey( false ); - r.setShowValue( false ); - r.setVertical( false ); - r.setAutoGeneratedText( true ); - r.setGenerated( true ); - r.setAutoLabelDeleted( false ); - r.setAutoBackground( true ); - r.setRotation( (short) 0 ); - r.setShowCategoryLabelAsPercentage( false ); - r.setShowValueAsPercentage( false ); - r.setShowBubbleSizes( false ); - r.setShowLabel( false ); - r.setIndexOfColorValue( (short) 77 ); - r.setDataLabelPlacement( (short) 11088 ); - r.setTextRotation( (short) 0 ); - return r; - } - - private DefaultDataLabelTextPropertiesRecord createDefaultTextRecord( short categoryDataType ) - { - DefaultDataLabelTextPropertiesRecord r = new DefaultDataLabelTextPropertiesRecord(); - r.setCategoryDataType( categoryDataType ); - return r; - } - - private SheetPropertiesRecord createSheetPropsRecord() - { - SheetPropertiesRecord r = new SheetPropertiesRecord(); - r.setChartTypeManuallyFormatted( false ); - r.setPlotVisibleOnly( true ); - r.setDoNotSizeWithWindow( false ); - r.setDefaultPlotDimensions( true ); - r.setAutoPlotArea( false ); - return r; - } - - private SeriesToChartGroupRecord createSeriesToChartGroupRecord() - { - return new SeriesToChartGroupRecord(); - } - - private DataFormatRecord createDataFormatRecord() - { - DataFormatRecord r = new DataFormatRecord(); - r.setPointNumber( (short) -1 ); - r.setSeriesIndex( (short) 0 ); - r.setSeriesNumber( (short) 0 ); - r.setUseExcel4Colors( false ); - return r; - } - - private LinkedDataRecord createCategoriesLinkedDataRecord() - { - LinkedDataRecord r = new LinkedDataRecord(); - r.setLinkType( LinkedDataRecord.LINK_TYPE_CATEGORIES ); - r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); - r.setCustomNumberFormat( false ); - r.setIndexNumberFmtRecord( (short) 0 ); - LinkedDataFormulaField formula = new LinkedDataFormulaField(); - Stack tokens = new Stack(); - Area3DPtg p = new Area3DPtg(); - p.setExternSheetIndex( (short) 0 ); - p.setFirstColumn( (short) 1 ); - p.setLastColumn( (short) 1 ); - p.setFirstRow( (short) 0 ); - p.setLastRow( (short) 31 ); - tokens.add( p ); - formula.setFormulaTokens( tokens ); - r.setFormulaOfLink( formula ); - return r; - } - - private LinkedDataRecord createValuesLinkedDataRecord() - { - LinkedDataRecord r = new LinkedDataRecord(); - r.setLinkType( LinkedDataRecord.LINK_TYPE_VALUES ); - r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); - r.setCustomNumberFormat( false ); - r.setIndexNumberFmtRecord( (short) 0 ); - LinkedDataFormulaField formula = new LinkedDataFormulaField(); - Stack tokens = new Stack(); - Area3DPtg p = new Area3DPtg(); - p.setExternSheetIndex( (short) 0 ); - p.setFirstColumn( (short) 0 ); - p.setLastColumn( (short) 0 ); - p.setFirstRow( (short) 0 ); - p.setLastRow( (short) 31 ); - tokens.add( p ); - formula.setFormulaTokens( tokens ); - r.setFormulaOfLink( formula ); - return r; - } - - private LinkedDataRecord createTitleLinkedDataRecord() - { - LinkedDataRecord r = new LinkedDataRecord(); - r.setLinkType( LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT ); - r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); - r.setCustomNumberFormat( false ); - r.setIndexNumberFmtRecord( (short) 0 ); - r.setFormulaOfLink( new LinkedDataFormulaField() ); - return r; - } - - private SeriesRecord createSeriesRecord() - { - SeriesRecord r = new SeriesRecord(); - r.setCategoryDataType( SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC ); - r.setValuesDataType( SeriesRecord.VALUES_DATA_TYPE_NUMERIC ); - r.setNumCategories( (short) 32 ); - r.setNumValues( (short) 31 ); - r.setBubbleSeriesType( SeriesRecord.BUBBLE_SERIES_TYPE_NUMERIC ); - r.setNumBubbleValues( (short) 0 ); - return r; - } - - private EndRecord createEndRecord() - { - return new EndRecord(); - } - - private AreaFormatRecord createAreaFormatRecord1() - { - AreaFormatRecord r = new AreaFormatRecord(); - r.setForegroundColor( 16777215 ); // RGB Color - r.setBackgroundColor( 0 ); // RGB Color - r.setPattern( (short) 1 ); // TODO: Add Pattern constants to record - r.setAutomatic( true ); - r.setInvert( false ); - r.setForecolorIndex( (short) 78 ); - r.setBackcolorIndex( (short) 77 ); - return r; - } - - private AreaFormatRecord createAreaFormatRecord2() - { - AreaFormatRecord r = new AreaFormatRecord(); - r.setForegroundColor(0x00c0c0c0); - r.setBackgroundColor(0x00000000); - r.setPattern((short)1); - r.setAutomatic(false); - r.setInvert(false); - r.setForecolorIndex((short)22); - r.setBackcolorIndex((short)79); - return r; - } - - private LineFormatRecord createLineFormatRecord( boolean drawTicks ) - { - LineFormatRecord r = new LineFormatRecord(); - r.setLineColor( 0 ); - r.setLinePattern( LineFormatRecord.LINE_PATTERN_SOLID ); - r.setWeight( (short) -1 ); - r.setAuto( true ); - r.setDrawTicks( drawTicks ); - r.setColourPaletteIndex( (short) 77 ); // what colour is this? - return r; - } - - private LineFormatRecord createLineFormatRecord2() - { - LineFormatRecord r = new LineFormatRecord(); - r.setLineColor( 0x00808080 ); - r.setLinePattern( (short) 0 ); - r.setWeight( (short) 0 ); - r.setAuto( false ); - r.setDrawTicks( false ); - r.setUnknown( false ); - r.setColourPaletteIndex( (short) 23 ); - return r; - } - - private FrameRecord createFrameRecord1() - { - FrameRecord r = new FrameRecord(); - r.setBorderType( FrameRecord.BORDER_TYPE_REGULAR ); - r.setAutoSize( false ); - r.setAutoPosition( true ); - return r; - } - - private FrameRecord createFrameRecord2() - { - FrameRecord r = new FrameRecord(); - r.setBorderType( FrameRecord.BORDER_TYPE_REGULAR ); - r.setAutoSize( true ); - r.setAutoPosition( true ); - return r; - } - - private PlotGrowthRecord createPlotGrowthRecord( int horizScale, int vertScale ) - { - PlotGrowthRecord r = new PlotGrowthRecord(); - r.setHorizontalScale( horizScale ); - r.setVerticalScale( vertScale ); - return r; - } - - private SCLRecord createSCLRecord( short numerator, short denominator ) - { - SCLRecord r = new SCLRecord(); - r.setDenominator( denominator ); - r.setNumerator( numerator ); - return r; - } - - private BeginRecord createBeginRecord() - { - return new BeginRecord(); - } - - private ChartRecord createChartRecord( int x, int y, int width, int height ) - { - ChartRecord r = new ChartRecord(); - r.setX( x ); - r.setY( y ); - r.setWidth( width ); - r.setHeight( height ); - return r; - } - - private UnitsRecord createUnitsRecord() - { - UnitsRecord r = new UnitsRecord(); - r.setUnits( (short) 0 ); - return r; - } - - - /** - * A series in a chart - */ - public class HSSFSeries { - private SeriesRecord series; - private SeriesTextRecord seriesTitleText; - - private HSSFSeries(SeriesRecord series) { - this.series = series; - } - - public short getNumValues() { - return series.getNumValues(); - } - /** - * See {@link SeriesRecord} - */ - public short getValueType() { - return series.getValuesDataType(); - } - - /** - * Returns the series' title, if there is one, - * or null if not - */ - public String getSeriesTitle() { - if(seriesTitleText != null) { - return seriesTitleText.getText(); - } - return null; - } - - /** - * Changes the series' title, but only if there - * was one already. - * TODO - add in the records if not - */ - public void setSeriesTitle(String title) { - if(seriesTitleText != null) { - seriesTitleText.setText(title); - } else { - throw new IllegalStateException("No series title found to change"); - } - } - } + /** + * Creates a bar chart. API needs some work. :) + *

+ * NOTE: Does not yet work... checking it in just so others + * can take a look. + */ + public void createBarChart( HSSFWorkbook workbook, HSSFSheet sheet ) + { + + List records = new ArrayList(); + records.add( createMSDrawingObjectRecord() ); + records.add( createOBJRecord() ); + records.add( createBOFRecord() ); + records.add( createHeaderRecord() ); + records.add( createFooterRecord() ); + records.add( createHCenterRecord() ); + records.add( createVCenterRecord() ); + records.add( createPrintSetupRecord() ); + // unknown 33 + records.add( createFontBasisRecord1() ); + records.add( createFontBasisRecord2() ); + records.add( createProtectRecord() ); + records.add( createUnitsRecord() ); + records.add( createChartRecord( 0, 0, 30434904, 19031616 ) ); + records.add( createBeginRecord() ); + records.add( createSCLRecord( (short) 1, (short) 1 ) ); + records.add( createPlotGrowthRecord( 65536, 65536 ) ); + records.add( createFrameRecord1() ); + records.add( createBeginRecord() ); + records.add( createLineFormatRecord(true) ); + records.add( createAreaFormatRecord1() ); + records.add( createEndRecord() ); + records.add( createSeriesRecord() ); + records.add( createBeginRecord() ); + records.add( createTitleLinkedDataRecord() ); + records.add( createValuesLinkedDataRecord() ); + records.add( createCategoriesLinkedDataRecord() ); + records.add( createDataFormatRecord() ); + // records.add(createBeginRecord()); + // unknown + // records.add(createEndRecord()); + records.add( createSeriesToChartGroupRecord() ); + records.add( createEndRecord() ); + records.add( createSheetPropsRecord() ); + records.add( createDefaultTextRecord( DefaultDataLabelTextPropertiesRecord.CATEGORY_DATA_TYPE_ALL_TEXT_CHARACTERISTIC ) ); + records.add( createAllTextRecord() ); + records.add( createBeginRecord() ); + // unknown + records.add( createFontIndexRecord( 5 ) ); + records.add( createDirectLinkRecord() ); + records.add( createEndRecord() ); + records.add( createDefaultTextRecord( (short) 3 ) ); // eek, undocumented text type + records.add( createUnknownTextRecord() ); + records.add( createBeginRecord() ); + records.add( createFontIndexRecord( (short) 6 ) ); + records.add( createDirectLinkRecord() ); + records.add( createEndRecord() ); + + records.add( createAxisUsedRecord( (short) 1 ) ); + createAxisRecords( records ); + + records.add( createEndRecord() ); + records.add( createDimensionsRecord() ); + records.add( createSeriesIndexRecord(2) ); + records.add( createSeriesIndexRecord(1) ); + records.add( createSeriesIndexRecord(3) ); + records.add( createEOFRecord() ); + + + + sheet.insertChartRecords( records ); + workbook.insertChartRecord(); + } + + /** + * Returns all the charts for the given sheet. + * + * NOTE: You won't be able to do very much with + * these charts yet, as this is very limited support + */ + public static HSSFChart[] getSheetCharts(HSSFSheet sheet) { + List charts = new ArrayList(); + HSSFChart lastChart = null; + + // Find records of interest + List records = sheet.getSheet().getRecords(); + for(Iterator it = records.iterator(); it.hasNext();) { + RecordBase r = (RecordBase)it.next(); + + if(r instanceof ChartRecord) { + lastChart = new HSSFChart((ChartRecord)r); + charts.add(lastChart); + } + if(r instanceof LegendRecord) { + lastChart.legendRecord = (LegendRecord)r; + } + if(r instanceof SeriesRecord) { + HSSFSeries series = lastChart.new HSSFSeries( (SeriesRecord)r ); + lastChart.series.add(series); + } + if(r instanceof ChartTitleFormatRecord) { + lastChart.chartTitleFormat = + (ChartTitleFormatRecord)r; + } + if(r instanceof SeriesTextRecord) { + // Applies to a series, unless we've seen + // a legend already + SeriesTextRecord str = (SeriesTextRecord)r; + if(lastChart.legendRecord == null && + lastChart.series.size() > 0) { + HSSFSeries series = (HSSFSeries) + lastChart.series.get(lastChart.series.size()-1); + series.seriesTitleText = str; + } else { + lastChart.chartTitleText = str; + } + } + } + + return (HSSFChart[]) + charts.toArray( new HSSFChart[charts.size()] ); + } + + /** Get the X offset of the chart */ + public int getChartX() { return chartRecord.getX(); } + /** Get the Y offset of the chart */ + public int getChartY() { return chartRecord.getY(); } + /** Get the width of the chart. {@link ChartRecord} */ + public int getChartWidth() { return chartRecord.getWidth(); } + /** Get the height of the chart. {@link ChartRecord} */ + public int getChartHeight() { return chartRecord.getHeight(); } + + /** Sets the X offset of the chart */ + public void setChartX(int x) { chartRecord.setX(x); } + /** Sets the Y offset of the chart */ + public void setChartY(int y) { chartRecord.setY(y); } + /** Sets the width of the chart. {@link ChartRecord} */ + public void setChartWidth(int width) { chartRecord.setWidth(width); } + /** Sets the height of the chart. {@link ChartRecord} */ + public void setChartHeight(int height) { chartRecord.setHeight(height); } + + /** + * Returns the series of the chart + */ + public HSSFSeries[] getSeries() { + return (HSSFSeries[]) + series.toArray(new HSSFSeries[series.size()]); + } + + /** + * Returns the chart's title, if there is one, + * or null if not + */ + public String getChartTitle() { + if(chartTitleText != null) { + return chartTitleText.getText(); + } + return null; + } + + /** + * Changes the chart's title, but only if there + * was one already. + * TODO - add in the records if not + */ + public void setChartTitle(String title) { + if(chartTitleText != null) { + chartTitleText.setText(title); + } else { + throw new IllegalStateException("No chart title found to change"); + } + } + + + private EOFRecord createEOFRecord() + { + return new EOFRecord(); + } + + private SeriesIndexRecord createSeriesIndexRecord( int index ) + { + SeriesIndexRecord r = new SeriesIndexRecord(); + r.setIndex((short)index); + return r; + } + + private DimensionsRecord createDimensionsRecord() + { + DimensionsRecord r = new DimensionsRecord(); + r.setFirstRow(0); + r.setLastRow(31); + r.setFirstCol((short)0); + r.setLastCol((short)1); + return r; + } + + private HCenterRecord createHCenterRecord() + { + HCenterRecord r = new HCenterRecord(); + r.setHCenter(false); + return r; + } + + private VCenterRecord createVCenterRecord() + { + VCenterRecord r = new VCenterRecord(); + r.setVCenter(false); + return r; + } + + private PrintSetupRecord createPrintSetupRecord() + { + PrintSetupRecord r = new PrintSetupRecord(); + r.setPaperSize((short)0); + r.setScale((short)18); + r.setPageStart((short)1); + r.setFitWidth((short)1); + r.setFitHeight((short)1); + r.setLeftToRight(false); + r.setLandscape(false); + r.setValidSettings(true); + r.setNoColor(false); + r.setDraft(false); + r.setNotes(false); + r.setNoOrientation(false); + r.setUsePage(false); + r.setHResolution((short)0); + r.setVResolution((short)0); + r.setHeaderMargin(0.5); + r.setFooterMargin(0.5); + r.setCopies((short)15); // what the ?? + return r; + } + + private FontBasisRecord createFontBasisRecord1() + { + FontBasisRecord r = new FontBasisRecord(); + r.setXBasis((short)9120); + r.setYBasis((short)5640); + r.setHeightBasis((short)200); + r.setScale((short)0); + r.setIndexToFontTable((short)5); + return r; + } + + private FontBasisRecord createFontBasisRecord2() + { + FontBasisRecord r = createFontBasisRecord1(); + r.setIndexToFontTable((short)6); + return r; + } + + private ProtectRecord createProtectRecord() + { + ProtectRecord r = new ProtectRecord(); + r.setProtect(false); + return r; + } + + private FooterRecord createFooterRecord() + { + FooterRecord r = new FooterRecord(); + r.setFooter(null); + return r; + } + + private HeaderRecord createHeaderRecord() + { + HeaderRecord r = new HeaderRecord(); + r.setHeader(null); + return r; + } + + private BOFRecord createBOFRecord() + { + BOFRecord r = new BOFRecord(); + r.setVersion((short)600); + r.setType((short)20); + r.setBuild((short)0x1CFE); + r.setBuildYear((short)1997); + r.setHistoryBitMask(0x40C9); + r.setRequiredVersion(106); + return r; + } + + private UnknownRecord createOBJRecord() + { + byte[] data = { + (byte) 0x15, (byte) 0x00, (byte) 0x12, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x11, (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xB8, (byte) 0x03, + (byte) 0x87, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + }; + + return new UnknownRecord( (short) 0x005D, data ); + } + + private UnknownRecord createMSDrawingObjectRecord() + { + // Since we haven't created this object yet we'll just put in the raw + // form for the moment. + + byte[] data = { + (byte)0x0F, (byte)0x00, (byte)0x02, (byte)0xF0, (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x08, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x0F, (byte)0x00, (byte)0x03, (byte)0xF0, (byte)0xA8, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x0F, (byte)0x00, (byte)0x04, (byte)0xF0, (byte)0x28, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, (byte)0xF0, (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x02, (byte)0x00, (byte)0x0A, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x0F, (byte)0x00, (byte)0x04, (byte)0xF0, (byte)0x70, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x92, (byte)0x0C, (byte)0x0A, (byte)0xF0, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x02, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x93, (byte)0x00, (byte)0x0B, (byte)0xF0, (byte)0x36, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x7F, (byte)0x00, (byte)0x04, (byte)0x01, (byte)0x04, (byte)0x01, (byte)0xBF, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x81, (byte)0x01, (byte)0x4E, (byte)0x00, + (byte)0x00, (byte)0x08, (byte)0x83, (byte)0x01, (byte)0x4D, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0xBF, (byte)0x01, (byte)0x10, (byte)0x00, (byte)0x11, (byte)0x00, (byte)0xC0, (byte)0x01, + (byte)0x4D, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0xFF, (byte)0x01, (byte)0x08, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x3F, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, + (byte)0xBF, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0xF0, (byte)0x12, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x04, (byte)0x00, (byte)0xC0, (byte)0x02, (byte)0x0A, (byte)0x00, (byte)0xF4, (byte)0x00, (byte)0x0E, (byte)0x00, (byte)0x66, (byte)0x01, (byte)0x20, (byte)0x00, (byte)0xE9, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x11, (byte)0xF0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 + }; + + return new UnknownRecord((short)0x00EC, data); + } + + private void createAxisRecords( List records ) + { + records.add( createAxisParentRecord() ); + records.add( createBeginRecord() ); + records.add( createAxisRecord( AxisRecord.AXIS_TYPE_CATEGORY_OR_X_AXIS ) ); + records.add( createBeginRecord() ); + records.add( createCategorySeriesAxisRecord() ); + records.add( createAxisOptionsRecord() ); + records.add( createTickRecord1() ); + records.add( createEndRecord() ); + records.add( createAxisRecord( AxisRecord.AXIS_TYPE_VALUE_AXIS ) ); + records.add( createBeginRecord() ); + records.add( createValueRangeRecord() ); + records.add( createTickRecord2() ); + records.add( createAxisLineFormatRecord( AxisLineFormatRecord.AXIS_TYPE_MAJOR_GRID_LINE ) ); + records.add( createLineFormatRecord(false) ); + records.add( createEndRecord() ); + records.add( createPlotAreaRecord() ); + records.add( createFrameRecord2() ); + records.add( createBeginRecord() ); + records.add( createLineFormatRecord2() ); + records.add( createAreaFormatRecord2() ); + records.add( createEndRecord() ); + records.add( createChartFormatRecord() ); + records.add( createBeginRecord() ); + records.add( createBarRecord() ); + // unknown 1022 + records.add( createLegendRecord() ); + records.add( createBeginRecord() ); + // unknown 104f + records.add( createTextRecord() ); + records.add( createBeginRecord() ); + // unknown 104f + records.add( createLinkedDataRecord() ); + records.add( createEndRecord() ); + records.add( createEndRecord() ); + records.add( createEndRecord() ); + records.add( createEndRecord() ); + } + + private LinkedDataRecord createLinkedDataRecord() + { + LinkedDataRecord r = new LinkedDataRecord(); + r.setLinkType(LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT); + r.setReferenceType(LinkedDataRecord.REFERENCE_TYPE_DIRECT); + r.setCustomNumberFormat(false); + r.setIndexNumberFmtRecord((short)0); + r.setFormulaOfLink( new LinkedDataFormulaField() ); + return r; + } + + private TextRecord createTextRecord() + { + TextRecord r = new TextRecord(); + r.setHorizontalAlignment(TextRecord.HORIZONTAL_ALIGNMENT_CENTER); + r.setVerticalAlignment(TextRecord.VERTICAL_ALIGNMENT_CENTER); + r.setDisplayMode((short)1); + r.setRgbColor(0x00000000); + r.setX(-37); + r.setY(-60); + r.setWidth(0); + r.setHeight(0); + r.setAutoColor(true); + r.setShowKey(false); + r.setShowValue(false); + r.setVertical(false); + r.setAutoGeneratedText(true); + r.setGenerated(true); + r.setAutoLabelDeleted(false); + r.setAutoBackground(true); + r.setRotation((short)0); + r.setShowCategoryLabelAsPercentage(false); + r.setShowValueAsPercentage(false); + r.setShowBubbleSizes(false); + r.setShowLabel(false); + r.setIndexOfColorValue((short)77); + r.setDataLabelPlacement((short)0); + r.setTextRotation((short)0); + return r; + } + + private LegendRecord createLegendRecord() + { + LegendRecord r = new LegendRecord(); + r.setXAxisUpperLeft(3542); + r.setYAxisUpperLeft(1566); + r.setXSize(437); + r.setYSize(213); + r.setType(LegendRecord.TYPE_RIGHT); + r.setSpacing(LegendRecord.SPACING_MEDIUM); + r.setAutoPosition(true); + r.setAutoSeries(true); + r.setAutoXPositioning(true); + r.setAutoYPositioning(true); + r.setVertical(true); + r.setDataTable(false); + return r; + } + + private BarRecord createBarRecord() + { + BarRecord r = new BarRecord(); + r.setBarSpace((short)0); + r.setCategorySpace((short)150); + r.setHorizontal(false); + r.setStacked(false); + r.setDisplayAsPercentage(false); + r.setShadow(false); + return r; + } + + private ChartFormatRecord createChartFormatRecord() + { + ChartFormatRecord r = new ChartFormatRecord(); + r.setXPosition(0); + r.setYPosition(0); + r.setWidth(0); + r.setHeight(0); + r.setVaryDisplayPattern(false); + return r; + } + + private PlotAreaRecord createPlotAreaRecord() + { + PlotAreaRecord r = new PlotAreaRecord( ); + return r; + } + + private AxisLineFormatRecord createAxisLineFormatRecord( short format ) + { + AxisLineFormatRecord r = new AxisLineFormatRecord(); + r.setAxisType( format ); + return r; + } + + private ValueRangeRecord createValueRangeRecord() + { + ValueRangeRecord r = new ValueRangeRecord(); + r.setMinimumAxisValue( 0.0 ); + r.setMaximumAxisValue( 0.0 ); + r.setMajorIncrement( 0 ); + r.setMinorIncrement( 0 ); + r.setCategoryAxisCross( 0 ); + r.setAutomaticMinimum( true ); + r.setAutomaticMaximum( true ); + r.setAutomaticMajor( true ); + r.setAutomaticMinor( true ); + r.setAutomaticCategoryCrossing( true ); + r.setLogarithmicScale( false ); + r.setValuesInReverse( false ); + r.setCrossCategoryAxisAtMaximum( false ); + r.setReserved( true ); // what's this do?? + return r; + } + + private TickRecord createTickRecord1() + { + TickRecord r = new TickRecord(); + r.setMajorTickType( (byte) 2 ); + r.setMinorTickType( (byte) 0 ); + r.setLabelPosition( (byte) 3 ); + r.setBackground( (byte) 1 ); + r.setLabelColorRgb( 0 ); + r.setZero1( (short) 0 ); + r.setZero2( (short) 0 ); + r.setZero3( (short) 45 ); + r.setAutorotate( true ); + r.setAutoTextBackground( true ); + r.setRotation( (short) 0 ); + r.setAutorotate( true ); + r.setTickColor( (short) 77 ); + return r; + } + + private TickRecord createTickRecord2() + { + TickRecord r = createTickRecord1(); + r.setZero3((short)0); + return r; + } + + private AxisOptionsRecord createAxisOptionsRecord() + { + AxisOptionsRecord r = new AxisOptionsRecord(); + r.setMinimumCategory( (short) -28644 ); + r.setMaximumCategory( (short) -28715 ); + r.setMajorUnitValue( (short) 2 ); + r.setMajorUnit( (short) 0 ); + r.setMinorUnitValue( (short) 1 ); + r.setMinorUnit( (short) 0 ); + r.setBaseUnit( (short) 0 ); + r.setCrossingPoint( (short) -28644 ); + r.setDefaultMinimum( true ); + r.setDefaultMaximum( true ); + r.setDefaultMajor( true ); + r.setDefaultMinorUnit( true ); + r.setIsDate( true ); + r.setDefaultBase( true ); + r.setDefaultCross( true ); + r.setDefaultDateSettings( true ); + return r; + } + + private CategorySeriesAxisRecord createCategorySeriesAxisRecord() + { + CategorySeriesAxisRecord r = new CategorySeriesAxisRecord(); + r.setCrossingPoint( (short) 1 ); + r.setLabelFrequency( (short) 1 ); + r.setTickMarkFrequency( (short) 1 ); + r.setValueAxisCrossing( true ); + r.setCrossesFarRight( false ); + r.setReversed( false ); + return r; + } + + private AxisRecord createAxisRecord( short axisType ) + { + AxisRecord r = new AxisRecord(); + r.setAxisType( axisType ); + return r; + } + + private AxisParentRecord createAxisParentRecord() + { + AxisParentRecord r = new AxisParentRecord(); + r.setAxisType( AxisParentRecord.AXIS_TYPE_MAIN ); + r.setX( 479 ); + r.setY( 221 ); + r.setWidth( 2995 ); + r.setHeight( 2902 ); + return r; + } + + private AxisUsedRecord createAxisUsedRecord( short numAxis ) + { + AxisUsedRecord r = new AxisUsedRecord(); + r.setNumAxis( numAxis ); + return r; + } + + private LinkedDataRecord createDirectLinkRecord() + { + LinkedDataRecord r = new LinkedDataRecord(); + r.setLinkType( LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT ); + r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); + r.setCustomNumberFormat( false ); + r.setIndexNumberFmtRecord( (short) 0 ); + r.setFormulaOfLink( new LinkedDataFormulaField() ); + return r; + } + + private FontIndexRecord createFontIndexRecord( int index ) + { + FontIndexRecord r = new FontIndexRecord(); + r.setFontIndex( (short) index ); + return r; + } + + private TextRecord createAllTextRecord() + { + TextRecord r = new TextRecord(); + r.setHorizontalAlignment( TextRecord.HORIZONTAL_ALIGNMENT_CENTER ); + r.setVerticalAlignment( TextRecord.VERTICAL_ALIGNMENT_CENTER ); + r.setDisplayMode( TextRecord.DISPLAY_MODE_TRANSPARENT ); + r.setRgbColor( 0 ); + r.setX( -37 ); + r.setY( -60 ); + r.setWidth( 0 ); + r.setHeight( 0 ); + r.setAutoColor( true ); + r.setShowKey( false ); + r.setShowValue( true ); + r.setVertical( false ); + r.setAutoGeneratedText( true ); + r.setGenerated( true ); + r.setAutoLabelDeleted( false ); + r.setAutoBackground( true ); + r.setRotation( (short) 0 ); + r.setShowCategoryLabelAsPercentage( false ); + r.setShowValueAsPercentage( false ); + r.setShowBubbleSizes( false ); + r.setShowLabel( false ); + r.setIndexOfColorValue( (short) 77 ); + r.setDataLabelPlacement( (short) 0 ); + r.setTextRotation( (short) 0 ); + return r; + } + + private TextRecord createUnknownTextRecord() + { + TextRecord r = new TextRecord(); + r.setHorizontalAlignment( TextRecord.HORIZONTAL_ALIGNMENT_CENTER ); + r.setVerticalAlignment( TextRecord.VERTICAL_ALIGNMENT_CENTER ); + r.setDisplayMode( TextRecord.DISPLAY_MODE_TRANSPARENT ); + r.setRgbColor( 0 ); + r.setX( -37 ); + r.setY( -60 ); + r.setWidth( 0 ); + r.setHeight( 0 ); + r.setAutoColor( true ); + r.setShowKey( false ); + r.setShowValue( false ); + r.setVertical( false ); + r.setAutoGeneratedText( true ); + r.setGenerated( true ); + r.setAutoLabelDeleted( false ); + r.setAutoBackground( true ); + r.setRotation( (short) 0 ); + r.setShowCategoryLabelAsPercentage( false ); + r.setShowValueAsPercentage( false ); + r.setShowBubbleSizes( false ); + r.setShowLabel( false ); + r.setIndexOfColorValue( (short) 77 ); + r.setDataLabelPlacement( (short) 11088 ); + r.setTextRotation( (short) 0 ); + return r; + } + + private DefaultDataLabelTextPropertiesRecord createDefaultTextRecord( short categoryDataType ) + { + DefaultDataLabelTextPropertiesRecord r = new DefaultDataLabelTextPropertiesRecord(); + r.setCategoryDataType( categoryDataType ); + return r; + } + + private SheetPropertiesRecord createSheetPropsRecord() + { + SheetPropertiesRecord r = new SheetPropertiesRecord(); + r.setChartTypeManuallyFormatted( false ); + r.setPlotVisibleOnly( true ); + r.setDoNotSizeWithWindow( false ); + r.setDefaultPlotDimensions( true ); + r.setAutoPlotArea( false ); + return r; + } + + private SeriesToChartGroupRecord createSeriesToChartGroupRecord() + { + return new SeriesToChartGroupRecord(); + } + + private DataFormatRecord createDataFormatRecord() + { + DataFormatRecord r = new DataFormatRecord(); + r.setPointNumber( (short) -1 ); + r.setSeriesIndex( (short) 0 ); + r.setSeriesNumber( (short) 0 ); + r.setUseExcel4Colors( false ); + return r; + } + + private LinkedDataRecord createCategoriesLinkedDataRecord() + { + LinkedDataRecord r = new LinkedDataRecord(); + r.setLinkType( LinkedDataRecord.LINK_TYPE_CATEGORIES ); + r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); + r.setCustomNumberFormat( false ); + r.setIndexNumberFmtRecord( (short) 0 ); + LinkedDataFormulaField formula = new LinkedDataFormulaField(); + Stack tokens = new Stack(); + Area3DPtg p = new Area3DPtg(); + p.setExternSheetIndex( (short) 0 ); + p.setFirstColumn( (short) 1 ); + p.setLastColumn( (short) 1 ); + p.setFirstRow( (short) 0 ); + p.setLastRow( (short) 31 ); + tokens.add( p ); + formula.setFormulaTokens( tokens ); + r.setFormulaOfLink( formula ); + return r; + } + + private LinkedDataRecord createValuesLinkedDataRecord() + { + LinkedDataRecord r = new LinkedDataRecord(); + r.setLinkType( LinkedDataRecord.LINK_TYPE_VALUES ); + r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); + r.setCustomNumberFormat( false ); + r.setIndexNumberFmtRecord( (short) 0 ); + LinkedDataFormulaField formula = new LinkedDataFormulaField(); + Stack tokens = new Stack(); + Area3DPtg p = new Area3DPtg(); + p.setExternSheetIndex( (short) 0 ); + p.setFirstColumn( (short) 0 ); + p.setLastColumn( (short) 0 ); + p.setFirstRow( (short) 0 ); + p.setLastRow( (short) 31 ); + tokens.add( p ); + formula.setFormulaTokens( tokens ); + r.setFormulaOfLink( formula ); + return r; + } + + private LinkedDataRecord createTitleLinkedDataRecord() + { + LinkedDataRecord r = new LinkedDataRecord(); + r.setLinkType( LinkedDataRecord.LINK_TYPE_TITLE_OR_TEXT ); + r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); + r.setCustomNumberFormat( false ); + r.setIndexNumberFmtRecord( (short) 0 ); + r.setFormulaOfLink( new LinkedDataFormulaField() ); + return r; + } + + private SeriesRecord createSeriesRecord() + { + SeriesRecord r = new SeriesRecord(); + r.setCategoryDataType( SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC ); + r.setValuesDataType( SeriesRecord.VALUES_DATA_TYPE_NUMERIC ); + r.setNumCategories( (short) 32 ); + r.setNumValues( (short) 31 ); + r.setBubbleSeriesType( SeriesRecord.BUBBLE_SERIES_TYPE_NUMERIC ); + r.setNumBubbleValues( (short) 0 ); + return r; + } + + private EndRecord createEndRecord() + { + return new EndRecord(); + } + + private AreaFormatRecord createAreaFormatRecord1() + { + AreaFormatRecord r = new AreaFormatRecord(); + r.setForegroundColor( 16777215 ); // RGB Color + r.setBackgroundColor( 0 ); // RGB Color + r.setPattern( (short) 1 ); // TODO: Add Pattern constants to record + r.setAutomatic( true ); + r.setInvert( false ); + r.setForecolorIndex( (short) 78 ); + r.setBackcolorIndex( (short) 77 ); + return r; + } + + private AreaFormatRecord createAreaFormatRecord2() + { + AreaFormatRecord r = new AreaFormatRecord(); + r.setForegroundColor(0x00c0c0c0); + r.setBackgroundColor(0x00000000); + r.setPattern((short)1); + r.setAutomatic(false); + r.setInvert(false); + r.setForecolorIndex((short)22); + r.setBackcolorIndex((short)79); + return r; + } + + private LineFormatRecord createLineFormatRecord( boolean drawTicks ) + { + LineFormatRecord r = new LineFormatRecord(); + r.setLineColor( 0 ); + r.setLinePattern( LineFormatRecord.LINE_PATTERN_SOLID ); + r.setWeight( (short) -1 ); + r.setAuto( true ); + r.setDrawTicks( drawTicks ); + r.setColourPaletteIndex( (short) 77 ); // what colour is this? + return r; + } + + private LineFormatRecord createLineFormatRecord2() + { + LineFormatRecord r = new LineFormatRecord(); + r.setLineColor( 0x00808080 ); + r.setLinePattern( (short) 0 ); + r.setWeight( (short) 0 ); + r.setAuto( false ); + r.setDrawTicks( false ); + r.setUnknown( false ); + r.setColourPaletteIndex( (short) 23 ); + return r; + } + + private FrameRecord createFrameRecord1() + { + FrameRecord r = new FrameRecord(); + r.setBorderType( FrameRecord.BORDER_TYPE_REGULAR ); + r.setAutoSize( false ); + r.setAutoPosition( true ); + return r; + } + + private FrameRecord createFrameRecord2() + { + FrameRecord r = new FrameRecord(); + r.setBorderType( FrameRecord.BORDER_TYPE_REGULAR ); + r.setAutoSize( true ); + r.setAutoPosition( true ); + return r; + } + + private PlotGrowthRecord createPlotGrowthRecord( int horizScale, int vertScale ) + { + PlotGrowthRecord r = new PlotGrowthRecord(); + r.setHorizontalScale( horizScale ); + r.setVerticalScale( vertScale ); + return r; + } + + private SCLRecord createSCLRecord( short numerator, short denominator ) + { + SCLRecord r = new SCLRecord(); + r.setDenominator( denominator ); + r.setNumerator( numerator ); + return r; + } + + private BeginRecord createBeginRecord() + { + return new BeginRecord(); + } + + private ChartRecord createChartRecord( int x, int y, int width, int height ) + { + ChartRecord r = new ChartRecord(); + r.setX( x ); + r.setY( y ); + r.setWidth( width ); + r.setHeight( height ); + return r; + } + + private UnitsRecord createUnitsRecord() + { + UnitsRecord r = new UnitsRecord(); + r.setUnits( (short) 0 ); + return r; + } + + + /** + * A series in a chart + */ + public class HSSFSeries { + private SeriesRecord series; + private SeriesTextRecord seriesTitleText; + + /* package */ HSSFSeries(SeriesRecord series) { + this.series = series; + } + + public short getNumValues() { + return series.getNumValues(); + } + /** + * See {@link SeriesRecord} + */ + public short getValueType() { + return series.getValuesDataType(); + } + + /** + * Returns the series' title, if there is one, + * or null if not + */ + public String getSeriesTitle() { + if(seriesTitleText != null) { + return seriesTitleText.getText(); + } + return null; + } + + /** + * Changes the series' title, but only if there + * was one already. + * TODO - add in the records if not + */ + public void setSeriesTitle(String title) { + if(seriesTitleText != null) { + seriesTitleText.setText(title); + } else { + throw new IllegalStateException("No series title found to change"); + } + } + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java index d28b8a877..d244d3372 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java @@ -14,26 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ + package org.apache.poi.hssf.usermodel; -import java.io.File; -import java.io.FileInputStream; - -import org.apache.poi.hssf.record.SeriesRecord; - import junit.framework.TestCase; -public class TestHSSFChart extends TestCase { - private String dirName; +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.record.SeriesRecord; - protected void setUp() throws Exception { - dirName = System.getProperty("HSSF.testdata.path"); - } +public final class TestHSSFChart extends TestCase { public void testSingleChart() throws Exception { - HSSFWorkbook wb = new HSSFWorkbook( - new FileInputStream(new File(dirName, "WithChart.xls")) - ); + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithChart.xls"); HSSFSheet s1 = wb.getSheetAt(0); HSSFSheet s2 = wb.getSheetAt(1); @@ -62,9 +54,7 @@ public class TestHSSFChart extends TestCase { } public void testTwoCharts() throws Exception { - HSSFWorkbook wb = new HSSFWorkbook( - new FileInputStream(new File(dirName, "WithTwoCharts.xls")) - ); + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithTwoCharts.xls"); HSSFSheet s1 = wb.getSheetAt(0); HSSFSheet s2 = wb.getSheetAt(1); @@ -96,9 +86,7 @@ public class TestHSSFChart extends TestCase { } public void testThreeCharts() throws Exception { - HSSFWorkbook wb = new HSSFWorkbook( - new FileInputStream(new File(dirName, "WithThreeCharts.xls")) - ); + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithThreeCharts.xls"); HSSFSheet s1 = wb.getSheetAt(0); HSSFSheet s2 = wb.getSheetAt(1); diff --git a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java index 0913ab725..cb028edfa 100644 --- a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java +++ b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java @@ -32,7 +32,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; */ public final class TestExcelExtractor extends TestCase { - private static final ExcelExtractor createExtractor(String sampleFileName) { + private static ExcelExtractor createExtractor(String sampleFileName) { InputStream is = HSSFTestDataSamples.openSampleFileStream(sampleFileName); @@ -192,18 +192,16 @@ public final class TestExcelExtractor extends TestCase { * Embded in a non-excel file */ public void testWithEmbeded() throws Exception { + // TODO - encapsulate sys prop 'POIFS.testdata.path' similar to HSSFTestDataSamples String pdirname = System.getProperty("POIFS.testdata.path"); String filename = pdirname + "/word_with_embeded.doc"; POIFSFileSystem fs = new POIFSFileSystem( new FileInputStream(filename) ); - DirectoryNode objPool = (DirectoryNode) - fs.getRoot().getEntry("ObjectPool"); - DirectoryNode dirA = (DirectoryNode) - objPool.getEntry("_1269427460"); - DirectoryNode dirB = (DirectoryNode) - objPool.getEntry("_1269427461"); + DirectoryNode objPool = (DirectoryNode) fs.getRoot().getEntry("ObjectPool"); + DirectoryNode dirA = (DirectoryNode) objPool.getEntry("_1269427460"); + DirectoryNode dirB = (DirectoryNode) objPool.getEntry("_1269427461"); HSSFWorkbook wbA = new HSSFWorkbook(dirA, fs, true); HSSFWorkbook wbB = new HSSFWorkbook(dirB, fs, true); @@ -224,16 +222,15 @@ public final class TestExcelExtractor extends TestCase { * Excel embeded in excel */ public void testWithEmbededInOwn() throws Exception { + // TODO - encapsulate sys prop 'POIFS.testdata.path' similar to HSSFTestDataSamples String pdirname = System.getProperty("POIFS.testdata.path"); String filename = pdirname + "/excel_with_embeded.xls"; POIFSFileSystem fs = new POIFSFileSystem( new FileInputStream(filename) ); - DirectoryNode dirA = (DirectoryNode) - fs.getRoot().getEntry("MBD0000A3B5"); - DirectoryNode dirB = (DirectoryNode) - fs.getRoot().getEntry("MBD0000A3B4"); + DirectoryNode dirA = (DirectoryNode) fs.getRoot().getEntry("MBD0000A3B5"); + DirectoryNode dirB = (DirectoryNode) fs.getRoot().getEntry("MBD0000A3B4"); HSSFWorkbook wbA = new HSSFWorkbook(dirA, fs, true); HSSFWorkbook wbB = new HSSFWorkbook(dirB, fs, true); @@ -260,15 +257,15 @@ public final class TestExcelExtractor extends TestCase { * Test that we get text from headers and footers */ public void test45538() throws Exception { - String[] files = new String[] { + String[] files = { "45538_classic_Footer.xls", "45538_form_Footer.xls", "45538_classic_Header.xls", "45538_form_Header.xls" }; for(int i=0; i=0); + assertTrue("Unable to find expected word in text\n" + text, text.indexOf("test phrase") >= 0); } } } diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index 4589ee5b1..22defb942 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -17,20 +17,31 @@ package org.apache.poi.hssf.model; +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.hssf.eventmodel.ERFListener; import org.apache.poi.hssf.eventmodel.EventRecordFactory; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.ColumnInfoRecord; +import org.apache.poi.hssf.record.DimensionsRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.MergeCellsRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RowRecord; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.record.UncalcedRecord; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; - -import java.io.ByteArrayInputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import org.apache.poi.hssf.util.CellRangeAddress; /** * Unit test for the Sheet class. @@ -55,10 +66,24 @@ public final class TestSheet extends TestCase { assertTrue( sheet.records.get(pos++) instanceof EOFRecord ); } + private static final class MergedCellListener implements ERFListener { + + private int _count; + public MergedCellListener() { + _count = 0; + } + public boolean processRecord(Record rec) { + _count++; + return true; + } + public int getCount() { + return _count; + } + } + public void testAddMergedRegion() { Sheet sheet = Sheet.createSheet(); int regionsToAdd = 4096; - int startRecords = sheet.getRecords().size(); //simple test that adds a load of regions for (int n = 0; n < regionsToAdd; n++) @@ -71,11 +96,18 @@ public final class TestSheet extends TestCase { assertTrue(sheet.getNumMergedRegions() == regionsToAdd); //test that the regions were spread out over the appropriate number of records - int recordsAdded = sheet.getRecords().size() - startRecords; + byte[] sheetData = new byte[sheet.getSize()]; + sheet.serialize(0, sheetData); + MergedCellListener mcListener = new MergedCellListener(); + EventRecordFactory erf = new EventRecordFactory(mcListener, new short[] { MergeCellsRecord.sid, }); +// POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(sheetData)); + erf.processRecords(new ByteArrayInputStream(sheetData)); + int recordsAdded = mcListener.getCount(); int recordsExpected = regionsToAdd/1027; if ((regionsToAdd % 1027) != 0) recordsExpected++; - assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected); + assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected); // Check we can't add one with invalid date try { sheet.addMergedRegion(10, (short)10, 9, (short)12); @@ -97,22 +129,23 @@ public final class TestSheet extends TestCase { Sheet sheet = Sheet.createSheet(); int regionsToAdd = 4096; - for (int n = 0; n < regionsToAdd; n++) - sheet.addMergedRegion(0, (short) 0, 1, (short) 1); + for (int n = 0; n < regionsToAdd; n++) { + sheet.addMergedRegion(n, 0, n, 1); + } - int records = sheet.getRecords().size(); + int nSheetRecords = sheet.getRecords().size(); //remove a third from the beginning for (int n = 0; n < regionsToAdd/3; n++) { sheet.removeMergedRegion(0); //assert they have been deleted - assertTrue("Num of regions should be " + (regionsToAdd - n - 1) + " not " + sheet.getNumMergedRegions(), sheet.getNumMergedRegions() == regionsToAdd - n - 1); + assertEquals("Num of regions", regionsToAdd - n - 1, sheet.getNumMergedRegions()); } - - //assert any record removing was done - int recordsRemoved = (regionsToAdd/3)/1027; //doesn't work for particular values of regionsToAdd - assertTrue("Expected " + recordsRemoved + " record to be removed from the starting " + records + ". Currently there are " + sheet.getRecords().size() + " records", records - sheet.getRecords().size() == recordsRemoved); + + // merge records are removed from within the MergedCellsTable, + // so the sheet record count should not change + assertEquals("Sheet Records", nSheetRecords, sheet.getRecords().size()); } /** @@ -125,8 +158,11 @@ public final class TestSheet extends TestCase { public void testMovingMergedRegion() { List records = new ArrayList(); - MergeCellsRecord merged = new MergeCellsRecord(); - merged.addArea(0, (short)0, 1, (short)2); + CellRangeAddress[] cras = { + new CellRangeAddress(0, 1, 0, 2), + }; + MergeCellsRecord merged = new MergeCellsRecord(cras, 0, cras.length); + records.add(new DimensionsRecord()); records.add(new RowRecord(0)); records.add(new RowRecord(1)); records.add(new RowRecord(2)); @@ -155,6 +191,7 @@ public final class TestSheet extends TestCase { public void testRowAggregation() { List records = new ArrayList(); + records.add(new DimensionsRecord()); records.add(new RowRecord(0)); records.add(new RowRecord(1)); records.add(new StringRecord()); @@ -196,10 +233,9 @@ public final class TestSheet extends TestCase { boolean is0 = false; boolean is11 = false; - Iterator iterator = sheet.getRowBreaks(); - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = breakItem.main; + int[] rowBreaks = sheet.getRowBreaks(); + for (int i = 0; i < rowBreaks.length; i++) { + int main = rowBreaks[i]; if (main != 0 && main != 10 && main != 11) fail("Invalid page break"); if (main == 0) is0 = true; if (main == 10) is10= true; @@ -253,10 +289,9 @@ public final class TestSheet extends TestCase { boolean is1 = false; boolean is15 = false; - Iterator iterator = sheet.getColumnBreaks(); - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = breakItem.main; + int[] colBreaks = sheet.getColumnBreaks(); + for (int i = 0; i < colBreaks.length; i++) { + int main = colBreaks[i]; if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break"); if (main == 0) is0 = true; if (main == 1) is1 = true; @@ -297,9 +332,8 @@ public final class TestSheet extends TestCase { xfindex = sheet.getXFIndexForColAt((short) 1); assertEquals(DEFAULT_IDX, xfindex); - // TODO change return type to ColumnInfoRecord - ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo(); - sheet.columns.insertColumn(nci); + ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo(); + sheet._columnInfos.insertColumn(nci); // single column ColumnInfoRecord nci.setFirstColumn((short) 2); @@ -361,6 +395,7 @@ public final class TestSheet extends TestCase { List records = new ArrayList(); records.add(new BOFRecord()); records.add(new UncalcedRecord()); + records.add(new DimensionsRecord()); records.add(new EOFRecord()); Sheet sheet = Sheet.createSheet(records, 0, 0); @@ -369,7 +404,7 @@ public final class TestSheet extends TestCase { if (serializedSize != estimatedSize) { throw new AssertionFailedError("Identified bug 45066 b"); } - assertEquals(50, serializedSize); + assertEquals(68, serializedSize); } /** @@ -393,7 +428,7 @@ public final class TestSheet extends TestCase { int dbCellRecordPos = getDbCellRecordPos(sheet); - if (dbCellRecordPos == 264) { + if (dbCellRecordPos == 252) { // The overt symptom of the bug // DBCELL record pos is calculated wrong if VRA comes before RRA throw new AssertionFailedError("Identified bug 45145"); @@ -405,7 +440,7 @@ public final class TestSheet extends TestCase { assertEquals(RowRecordsAggregate.class, recs.get(rraIx).getClass()); assertEquals(ValueRecordsAggregate.class, recs.get(rraIx+1).getClass()); - assertEquals(254, dbCellRecordPos); + assertEquals(242, dbCellRecordPos); } /** diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java index f86c2941a..0962b9148 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java @@ -29,8 +29,7 @@ public final class TestSheetAdditional extends TestCase { public void testGetCellWidth() { Sheet sheet = Sheet.createSheet(); - // TODO change return type to ColumnInfoRecord - ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo(); + ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo(); // Prepare test model nci.setFirstColumn((short)5); @@ -38,7 +37,7 @@ public final class TestSheetAdditional extends TestCase { nci.setColumnWidth((short)100); - sheet.columns.insertColumn(nci); + sheet._columnInfos.insertColumn(nci); assertEquals((short)100,sheet.getColumnWidth((short)5)); assertEquals((short)100,sheet.getColumnWidth((short)6)); @@ -58,6 +57,3 @@ public final class TestSheetAdditional extends TestCase { } } - - - diff --git a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java index 9df7e3b26..c0a8f9fe7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java @@ -33,8 +33,8 @@ public final class TestMergeCellsRecord extends TestCase { * @throws Exception */ public void testCloneReferences() throws Exception { - MergeCellsRecord merge = new MergeCellsRecord(); - merge.addArea(0, (short)0, 1, (short)2); + CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), }; + MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length); MergeCellsRecord clone = (MergeCellsRecord)merge.clone(); assertNotSame("Merged and cloned objects are the same", merge, clone); @@ -47,7 +47,6 @@ public final class TestMergeCellsRecord extends TestCase { assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn()); assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn()); - merge.removeAreaAt(0); - assertNotNull("Clone's item not removed", clone.getAreaAt(0)); + assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0)); } } diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java index efe352b24..844430fb7 100644 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java @@ -24,6 +24,7 @@ import java.util.List; import junit.framework.TestCase; +import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.CFHeaderRecord; import org.apache.poi.hssf.record.CFRuleRecord; import org.apache.poi.hssf.record.RecordFactory; @@ -59,7 +60,7 @@ public final class TestCFRecordsAggregate extends TestCase recs.add(rule2); recs.add(rule3); CFRecordsAggregate record; - record = CFRecordsAggregate.createCFAggregate(recs, 0); + record = CFRecordsAggregate.createCFAggregate(new RecordStream(recs, 0)); // Serialize byte [] serializedRecord = record.serialize(); @@ -81,7 +82,7 @@ public final class TestCFRecordsAggregate extends TestCase assertEquals(2, cellRanges.length); assertEquals(3, header.getNumberOfConditionalFormats()); - record = CFRecordsAggregate.createCFAggregate(recs, 0); + record = CFRecordsAggregate.createCFAggregate(new RecordStream(recs, 0)); record = record.cloneCFAggregate(); diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java index 20fded35e..298829061 100644 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java @@ -19,42 +19,39 @@ package org.apache.poi.hssf.record.aggregates; import junit.framework.TestCase; import org.apache.poi.hssf.record.ColumnInfoRecord; +import org.apache.poi.hssf.record.RecordBase; /** * @author Glen Stampoultzis */ -public final class TestColumnInfoRecordsAggregate extends TestCase -{ - ColumnInfoRecordsAggregate columnInfoRecordsAggregate; +public final class TestColumnInfoRecordsAggregate extends TestCase { - public void testGetRecordSize() throws Exception - { - columnInfoRecordsAggregate = new ColumnInfoRecordsAggregate(); - columnInfoRecordsAggregate.insertColumn( createColumn( (short)1, (short)3 )); - columnInfoRecordsAggregate.insertColumn( createColumn( (short)4, (short)7 )); - columnInfoRecordsAggregate.insertColumn( createColumn( (short)8, (short)8 )); -// columnInfoRecordsAggregate.setColumn( (short)2, new Short( (short)200 ), new Integer( 1 ), new Boolean( true ), null); - columnInfoRecordsAggregate.groupColumnRange( (short)2, (short)5, true ); - assertEquals(6, columnInfoRecordsAggregate.getNumColumns()); + public void testGetRecordSize() { + ColumnInfoRecordsAggregate agg = new ColumnInfoRecordsAggregate(); + agg.insertColumn(createColumn(1, 3)); + agg.insertColumn(createColumn(4, 7)); + agg.insertColumn(createColumn(8, 8)); + agg.groupColumnRange((short) 2, (short) 5, true); + assertEquals(6, agg.getNumColumns()); - assertEquals(columnInfoRecordsAggregate.getRecordSize(), columnInfoRecordsAggregate.serialize().length); + confirmSerializedSize(agg); - columnInfoRecordsAggregate = new ColumnInfoRecordsAggregate(); - columnInfoRecordsAggregate.groupColumnRange( (short)3, (short)6, true ); + agg = new ColumnInfoRecordsAggregate(); + agg.groupColumnRange((short) 3, (short) 6, true); + confirmSerializedSize(agg); + } - assertEquals(columnInfoRecordsAggregate.getRecordSize(), serializedSize()); - } + private static void confirmSerializedSize(RecordBase cirAgg) { + int estimatedSize = cirAgg.getRecordSize(); + byte[] buf = new byte[estimatedSize]; + int serializedSize = cirAgg.serialize(0, buf); + assertEquals(estimatedSize, serializedSize); + } - private int serializedSize() - { - return columnInfoRecordsAggregate.serialize(0, new byte[columnInfoRecordsAggregate.getRecordSize()]); - } - - private ColumnInfoRecord createColumn( short firstCol, short lastCol ) - { - ColumnInfoRecord columnInfoRecord = new ColumnInfoRecord( ); - columnInfoRecord.setFirstColumn(firstCol); - columnInfoRecord.setLastColumn(lastCol); - return columnInfoRecord; - } + private static ColumnInfoRecord createColumn(int firstCol, int lastCol) { + ColumnInfoRecord columnInfoRecord = new ColumnInfoRecord(); + columnInfoRecord.setFirstColumn((short) firstCol); + columnInfoRecord.setLastColumn((short) lastCol); + return columnInfoRecord; + } } \ No newline at end of file diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 541fb893a..646321d3d 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -660,7 +660,7 @@ public final class TestBugs extends TestCase { HSSFSheet sheet = wb.getSheetAt( 0 ); int[] breaks = sheet.getRowBreaks(); - assertNull(breaks); + assertEquals(0, breaks.length); //add 3 row breaks for (int j = 1; j <= 3; j++) {