/**
* Title: Multiple Blank cell record(0x00BE) <P/>
* Description: Represents a set of columns in a row with no value but with styling.
- * In this release we have read-only support for this record type.
- * The RecordFactory converts this to a set of BlankRecord objects.<P/>
+ * <p/>
* REFERENCE: PG 329 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P/>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @see BlankRecord
*/
public final class MulBlankRecord extends StandardRecord {
- public final static short sid = 0x00BE;
-
- private int field_1_row;
- private short field_2_first_col;
- private short[] field_3_xfs;
- private short field_4_last_col;
-
- public MulBlankRecord(int row, int firstCol, short[] xfs) {
- field_1_row = row;
- field_2_first_col = (short)firstCol;
- field_3_xfs = xfs;
- field_4_last_col = (short) (firstCol + xfs.length - 1);
- }
-
- /**
- * get the row number of the cells this represents
- *
- * @return row number
- */
- public int getRow()
- {
- return field_1_row;
- }
-
- /**
- * starting column (first cell this holds in the row)
- * @return first column number
- */
- public short getFirstColumn()
- {
- return field_2_first_col;
- }
-
- /**
- * ending column (last cell this holds in the row)
- * @return first column number
- */
- public short getLastColumn()
- {
- return field_4_last_col;
- }
-
- /**
- * get the number of columns this contains (last-first +1)
- * @return number of columns (last - first +1)
- */
- public int getNumColumns()
- {
- return field_4_last_col - field_2_first_col + 1;
- }
-
- /**
- * returns the xf index for column (coffset = column - field_2_first_col)
- * @param coffset the column (coffset = column - field_2_first_col)
- * @return the XF index for the column
- */
- public short getXFAt(int coffset)
- {
- return field_3_xfs[ coffset ];
- }
-
- /**
- * @param in the RecordInputstream to read the record from
- */
- public MulBlankRecord(RecordInputStream in) {
- field_1_row = in.readUShort();
- field_2_first_col = in.readShort();
- field_3_xfs = parseXFs(in);
- field_4_last_col = in.readShort();
- }
-
- private static short [] parseXFs(RecordInputStream in)
- {
- short[] retval = new short[ (in.remaining() - 2) / 2 ];
-
- for (int idx = 0; idx < retval.length;idx++)
- {
- retval[idx] = in.readShort();
- }
- return retval;
- }
-
- public String toString() {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("[MULBLANK]\n");
- buffer.append("row = ").append(Integer.toHexString(getRow())).append("\n");
- buffer.append("firstcol = ").append(Integer.toHexString(getFirstColumn())).append("\n");
- buffer.append(" lastcol = ").append(Integer.toHexString(getLastColumn())).append("\n");
- for (int k = 0; k < getNumColumns(); k++) {
- buffer.append("xf").append(k).append(" = ").append(
- Integer.toHexString(getXFAt(k))).append("\n");
- }
- buffer.append("[/MULBLANK]\n");
- return buffer.toString();
- }
-
- public short getSid()
- {
- return sid;
- }
-
- public void serialize(LittleEndianOutput out) {
- out.writeShort(field_1_row);
- out.writeShort(field_2_first_col);
- int nItems = field_3_xfs.length;
- for (int i = 0; i < nItems; i++) {
- out.writeShort(field_3_xfs[i]);
- }
- out.writeShort(field_4_last_col);
- }
-
- protected int getDataSize() {
- // 3 short fields + array of shorts
- return 6 + field_3_xfs.length * 2;
- }
+ public final static short sid = 0x00BE;
+
+ private final int _row;
+ private final int _firstCol;
+ private final short[] _xfs;
+ private final int _lastCol;
+
+ public MulBlankRecord(int row, int firstCol, short[] xfs) {
+ _row = row;
+ _firstCol = firstCol;
+ _xfs = xfs;
+ _lastCol = firstCol + xfs.length - 1;
+ }
+
+ /**
+ * @return the row number of the cells this represents
+ */
+ public int getRow() {
+ return _row;
+ }
+
+ /**
+ * @return starting column (first cell this holds in the row). Zero based
+ */
+ public int getFirstColumn() {
+ return _firstCol;
+ }
+
+ /**
+ * get the number of columns this contains (last-first +1)
+ * @return number of columns (last - first +1)
+ */
+ public int getNumColumns() {
+ return _lastCol - _firstCol + 1;
+ }
+
+ /**
+ * returns the xf index for column (coffset = column - field_2_first_col)
+ * @param coffset the column (coffset = column - field_2_first_col)
+ * @return the XF index for the column
+ */
+ public short getXFAt(int coffset) {
+ return _xfs[coffset];
+ }
+
+ /**
+ * @param in the RecordInputstream to read the record from
+ */
+ public MulBlankRecord(RecordInputStream in) {
+ _row = in.readUShort();
+ _firstCol = in.readShort();
+ _xfs = parseXFs(in);
+ _lastCol = in.readShort();
+ }
+
+ private static short [] parseXFs(RecordInputStream in) {
+ short[] retval = new short[(in.remaining() - 2) / 2];
+
+ for (int idx = 0; idx < retval.length;idx++) {
+ retval[idx] = in.readShort();
+ }
+ return retval;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[MULBLANK]\n");
+ buffer.append("row = ").append(Integer.toHexString(getRow())).append("\n");
+ buffer.append("firstcol = ").append(Integer.toHexString(getFirstColumn())).append("\n");
+ buffer.append(" lastcol = ").append(Integer.toHexString(_lastCol)).append("\n");
+ for (int k = 0; k < getNumColumns(); k++) {
+ buffer.append("xf").append(k).append(" = ").append(
+ Integer.toHexString(getXFAt(k))).append("\n");
+ }
+ buffer.append("[/MULBLANK]\n");
+ return buffer.toString();
+ }
+
+ public short getSid() {
+ return sid;
+ }
+
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(_row);
+ out.writeShort(_firstCol);
+ int nItems = _xfs.length;
+ for (int i = 0; i < nItems; i++) {
+ out.writeShort(_xfs[i]);
+ }
+ out.writeShort(_lastCol);
+ }
+
+ protected int getDataSize() {
+ // 3 short fields + array of shorts
+ return 6 + _xfs.length * 2;
+ }
+
+ @Override
+ public Object clone() {
+ // immutable - so OK to return this
+ return this;
+ }
}
package org.apache.poi.hssf.model;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import junit.framework.AssertionFailedError;
import org.apache.poi.hssf.record.GutsRecord;
import org.apache.poi.hssf.record.IndexRecord;
import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.MulBlankRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
assertEquals(colIx, dims.getFirstCol());
assertEquals(colIx, dims.getLastCol());
}
-
+
/**
- * Prior to the fix for bug 46547, shifting formulas would have the side-effect
+ * Prior to the fix for bug 46547, shifting formulas would have the side-effect
* of creating a {@link ConditionalFormattingTable}. There was no impairment to
- * functionality since empty record aggregates are equivalent to missing record
+ * functionality since empty record aggregates are equivalent to missing record
* aggregates. However, since this unnecessary creation helped expose bug 46547b,
* and since there is a slight performance hit the fix was made to avoid it.
*/
List<RecordBase> sheetRecs = sheet.getRecords();
assertEquals(22, sheetRecs.size());
-
+
FormulaShifter shifter = FormulaShifter.createForRowShift(0, 0, 0, 1);
sheet.updateFormulasAfterCellShift(shifter, 0);
if (sheetRecs.size() == 23 && sheetRecs.get(21) instanceof ConditionalFormattingTable) {
throw new AssertionFailedError("Identified bug 46547a");
}
assertEquals(22, sheetRecs.size());
-
+
}
/**
* Bug 46547 happened when attempting to add conditional formatting to a sheet
}
assertNotNull(cft);
}
+
+ public void testCloneMulBlank_bug46776() {
+ Record[] recs = {
+ Sheet.createBOF(),
+ new DimensionsRecord(),
+ new RowRecord(1),
+ new MulBlankRecord(1, 3, new short[] { 0x0F, 0x0F, 0x0F, } ),
+ new RowRecord(2),
+ createWindow2Record(),
+ EOFRecord.instance,
+ };
+
+ Sheet sheet = createSheet(Arrays.asList(recs));
+
+ Sheet sheet2;
+ try {
+ sheet2 = sheet.cloneSheet();
+ } catch (RuntimeException e) {
+ if (e.getMessage().equals("The class org.apache.poi.hssf.record.MulBlankRecord needs to define a clone method")) {
+ throw new AssertionFailedError("Identified bug 46776");
+ }
+ throw e;
+ }
+
+ RecordCollector rc = new RecordCollector();
+ sheet2.visitContainedRecords(rc, 0);
+ Record[] clonedRecs = rc.getRecords();
+ assertEquals(recs.length+2, clonedRecs.length); // +2 for INDEX and DBCELL
+ }
}