/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache POI" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache POI", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.apache.poi.hssf.model; import java.util.List; import java.util.ArrayList; import java.util.Iterator; import org.apache.poi.hssf .record.*; // normally I don't do this, buy we literally mean ALL import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.util.*; import org.apache.poi.hssf.record .aggregates.*; // normally I don't do this, buy we literally mean ALL /** * Low level model implementation of a Sheet (one workbook contains many sheets) * This file contains the low level binary records starting at the sheets BOF and * ending with the sheets EOF. Use HSSFSheet for a high level representation. *

* The structures of the highlevel API use references to this to perform most of their * operations. Its probably unwise to use these low level structures directly unless you * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf * before even attempting to use this. *

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Glen Stampoultzis (glens at apache.org) * @author Shawn Laubach (slaubach at apache dot org) Gridlines, Headers, Footers, and PrintSetup * @author Jason Height (jheight at chariot dot net dot au) Clone support * @author Brian Sanders (kestrel at burdell dot org) Active Cell support * * @see org.apache.poi.hssf.model.Workbook * @see org.apache.poi.hssf.usermodel.HSSFSheet * @version 1.0-pre */ public class Sheet implements Model { public static final short LeftMargin = 0; public static final short RightMargin = 1; public static final short TopMargin = 2; public static final short BottomMargin = 3; protected ArrayList records = null; int preoffset = 0; // offset of the sheet in a new file int loc = 0; protected boolean containsLabels = false; protected int dimsloc = 0; protected DimensionsRecord dims; protected DefaultColWidthRecord defaultcolwidth = null; protected DefaultRowHeightRecord defaultrowheight = null; protected GridsetRecord gridset = null; 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 ArrayList mergedRecords = new ArrayList(); protected ArrayList mergedLocs = new ArrayList(); protected int numMergedRegions = 0; protected SelectionRecord selection = null; private static POILogger log = POILogFactory.getLogger(Sheet.class); private ArrayList columnSizes = null; // holds column info protected ValueRecordsAggregate cells = null; protected RowRecordsAggregate rows = null; private Iterator valueRecIterator = null; private Iterator rowRecIterator = null; protected int eofLoc = 0; protected ProtectRecord protect = null; public static final byte PANE_LOWER_RIGHT = (byte)0; public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_LOWER_LEFT = (byte)2; public static final byte PANE_UPPER_LEFT = (byte)3; /** * Creates new Sheet with no intialization --useless at this point * @see #createSheet(List,int,int) */ public Sheet() { } /** * read support (offset used as starting point for search) for low level * API. Pass in an array of Record objects, the sheet number (0 based) and * a record offset (should be the location of the sheets BOF record). A Sheet * object is constructed and passed back with all of its initialization set * to the passed in records and references to those records held. This function * is normally called via Workbook. * * @param recs array containing those records in the sheet in sequence (normally obtained from RecordFactory) * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release) * @param offset of the sheet's BOF record * * @return Sheet object with all values set to those read from the file * * @see org.apache.poi.hssf.model.Workbook * @see org.apache.poi.hssf.record.Record */ public static Sheet createSheet(List recs, int sheetnum, int offset) { log.logFormatted(log.DEBUG, "Sheet createSheet (existing file) with %", new Integer(recs.size())); 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.getSid() == LabelRecord.sid) { log.log(log.DEBUG, "Hit label record."); retval.containsLabels = true; } else if (rec.getSid() == BOFRecord.sid) { bofEofNestingLevel++; log.log(log.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel); } else if (rec.getSid() == EOFRecord.sid) { --bofEofNestingLevel; log.log(log.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel); if (bofEofNestingLevel == 0) { records.add(rec); retval.eofLoc = k; break; } } else if (rec.getSid() == DimensionsRecord.sid) { retval.dims = ( DimensionsRecord ) rec; retval.dimsloc = records.size(); } else if (rec.getSid() == MergeCellsRecord.sid) { retval.mergedRecords.add(rec); retval.merged = ( MergeCellsRecord ) rec; retval.mergedLocs.add(new Integer(k - offset)); retval.numMergedRegions += retval.merged.getNumAreas(); } else if (rec.getSid() == ColumnInfoRecord.sid) { if (retval.columnSizes == null) { retval.columnSizes = new ArrayList(); } retval.columnSizes.add(rec); } 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 ) { retval.cells = new ValueRecordsAggregate(); rec = retval.cells; retval.cells.construct( k, recs ); isfirstcell = false; } else { rec = null; } } else if ( rec.getSid() == StringRecord.sid ) { rec = null; } else if ( rec.getSid() == RowRecord.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); } else if ( rec.getSid() == PrintGridlinesRecord.sid ) { retval.printGridlines = (PrintGridlinesRecord) rec; } else if ( rec.getSid() == HeaderRecord.sid && bofEofNestingLevel == 1) { retval.header = (HeaderRecord) rec; } else if ( rec.getSid() == FooterRecord.sid && bofEofNestingLevel == 1) { retval.footer = (FooterRecord) rec; } else if ( rec.getSid() == PrintSetupRecord.sid && bofEofNestingLevel == 1) { retval.printSetup = (PrintSetupRecord) rec; } else if ( rec.getSid() == LeftMarginRecord.sid) { retval.getMargins()[LeftMargin] = (LeftMarginRecord) rec; } else if ( rec.getSid() == RightMarginRecord.sid) { retval.getMargins()[RightMargin] = (RightMarginRecord) rec; } else if ( rec.getSid() == TopMarginRecord.sid) { retval.getMargins()[TopMargin] = (TopMarginRecord) rec; } else if ( rec.getSid() == BottomMarginRecord.sid) { retval.getMargins()[BottomMargin] = (BottomMarginRecord) rec; } else if ( rec.getSid() == SelectionRecord.sid ) { retval.selection = (SelectionRecord) rec; } else if ( rec.getSid() == WindowTwoRecord.sid ) { retval.windowTwo = (WindowTwoRecord) rec; } else if ( rec.getSid() == ProtectRecord.sid ) { retval.protect = (ProtectRecord) rec; } if (rec != null) { records.add(rec); } } retval.records = records; if (retval.rows == null) { retval.rows = new RowRecordsAggregate(); } if (retval.cells == null) { retval.cells = new ValueRecordsAggregate(); } log.log(log.DEBUG, "sheet createSheet (existing file) exited"); return retval; } /** * 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 * can be added to a sheet. The Record object does not implement cloneable. * When adding a new record, implement a public clone method if and only if the record * belongs to a sheet. */ public Sheet cloneSheet() { 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); 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; } } int removePos = ((Integer) mergedLocs.get(pos)).intValue(); records.remove(removePos); mergedLocs.remove(pos); } } public MergeCellsRecord.MergedRegion 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); } public int getNumMergedRegions() { return numMergedRegions; } /** * This is basically a kludge to deal with the now obsolete Label records. If * you have to read in a sheet that contains Label records, be aware that the rest * of the API doesn't deal with them, the low level structure only provides read-only * semi-immutable structures (the sets are there for interface conformance with NO * impelmentation). In short, you need to call this function passing it a reference * to the Workbook object. All labels will be converted to LabelSST records and their * contained strings will be written to the Shared String tabel (SSTRecord) within * the Workbook. * * @param wb sheet's matching low level Workbook structure containing the SSTRecord. * @see org.apache.poi.hssf.record.LabelRecord * @see org.apache.poi.hssf.record.LabelSSTRecord * @see org.apache.poi.hssf.record.SSTRecord */ public void convertLabelRecords(Workbook wb) { log.log(log.DEBUG, "convertLabelRecords called"); if (containsLabels) { for (int k = 0; k < records.size(); k++) { Record rec = ( Record ) records.get(k); if (rec.getSid() == LabelRecord.sid) { LabelRecord oldrec = ( LabelRecord ) rec; records.remove(k); LabelSSTRecord newrec = new LabelSSTRecord(); int stringid = wb.addSSTString(oldrec.getValue()); newrec.setRow(oldrec.getRow()); newrec.setColumn(oldrec.getColumn()); newrec.setXFIndex(oldrec.getXFIndex()); newrec.setSSTIndex(stringid); records.add(k, newrec); } } } log.log(log.DEBUG, "convertLabelRecords exit"); } /** * Returns the number of low level binary records in this sheet. This adjusts things for the so called * AgregateRecords. * * @see org.apache.poi.hssf.record.Record */ public int getNumRecords() { checkCells(); checkRows(); log.log(log.DEBUG, "Sheet.getNumRecords"); log.logFormatted(log.DEBUG, "returning % + % + % - 2 = %", new int[] { records.size(), cells.getPhysicalNumberOfCells(), rows.getPhysicalNumberOfRows(), records.size() + cells.getPhysicalNumberOfCells() + rows.getPhysicalNumberOfRows() - 2 }); return records.size() + cells.getPhysicalNumberOfCells() + rows.getPhysicalNumberOfRows() - 2; } /** * Per an earlier reported bug in working with Andy Khan's excel read library. This * sets the values in the sheet's DimensionsRecord object to be correct. Excel doesn't * really care, but we want to play nice with other libraries. * * @see org.apache.poi.hssf.record.DimensionsRecord */ //public void setDimensions(short firstrow, short firstcol, short lastrow, public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol) { log.log(log.DEBUG, "Sheet.setDimensions"); log.log(log.DEBUG, (new StringBuffer("firstrow")).append(firstrow) .append("firstcol").append(firstcol).append("lastrow") .append(lastrow).append("lastcol").append(lastcol) .toString()); dims.setFirstCol(firstcol); dims.setFirstRow(firstrow); dims.setLastCol(lastcol); dims.setLastRow(lastrow); log.log(log.DEBUG, "Sheet.setDimensions exiting"); } /** * set the locator for where we should look for the next value record. The * algorythm will actually start here and find the correct location so you * can set this to 0 and watch performance go down the tubes but it will work. * After a value is set this is automatically advanced. Its also set by the * create method. So you probably shouldn't mess with this unless you have * a compelling reason why or the help for the method you're calling says so. * Check the other methods for whether they care about * the loc pointer. Many of the "modify" and "remove" methods re-initialize this * to "dimsloc" which is the location of the Dimensions Record and presumably the * start of the value section (at or around 19 dec). * * @param loc the record number to start at * */ public void setLoc(int loc) { valueRecIterator = null; log.log(log.DEBUG, "sheet.setLoc(): " + loc); this.loc = loc; } /** * Returns the location pointer to the first record to look for when adding rows/values * */ public int getLoc() { log.log(log.DEBUG, "sheet.getLoc():" + loc); return loc; } /** * Set the preoffset when using DBCELL records (currently unused) - this is * the position of this sheet within the whole file. * * @param offset the offset of the sheet's BOF within the file. */ public void setPreOffset(int offset) { this.preoffset = offset; } /** * get the preoffset when using DBCELL records (currently unused) - this is * the position of this sheet within the whole file. * * @return offset the offset of the sheet's BOF within the file. */ public int getPreOffset() { return preoffset; } /** * Serializes all records in the sheet into one big byte array. Use this to write * the sheet out. * * @return byte[] array containing the binary representation of the records in this sheet * */ public byte [] serialize() { log.log(log.DEBUG, "Sheet.serialize"); // addDBCellRecords(); byte[] retval = null; // ArrayList bytes = new ArrayList(4096); int arraysize = getSize(); int pos = 0; // for (int k = 0; k < records.size(); k++) // { // bytes.add((( Record ) records.get(k)).serialize()); // // } // for (int k = 0; k < bytes.size(); k++) // { // arraysize += (( byte [] ) bytes.get(k)).length; // log.debug((new StringBuffer("arraysize=")).append(arraysize) // .toString()); // } retval = new byte[ arraysize ]; for (int k = 0; k < records.size(); k++) { // byte[] rec = (( byte [] ) bytes.get(k)); // System.arraycopy(rec, 0, retval, pos, rec.length); pos += (( Record ) records.get(k)).serialize(pos, retval); // rec.length; } log.log(log.DEBUG, "Sheet.serialize returning " + retval); return retval; } /** * Serializes all records in the sheet into one big byte array. Use this to write * the sheet out. * * @param offset to begin write at * @param data array containing the binary representation of the records in this sheet * */ public int serialize(int offset, byte [] data) { log.log(log.DEBUG, "Sheet.serialize using offsets"); // addDBCellRecords(); // ArrayList bytes = new ArrayList(4096); // int arraysize = getSize(); // 0; int pos = 0; // for (int k = 0; k < records.size(); k++) // { // bytes.add((( Record ) records.get(k)).serialize()); // // } // for (int k = 0; k < bytes.size(); k++) // { // arraysize += (( byte [] ) bytes.get(k)).length; // log.debug((new StringBuffer("arraysize=")).append(arraysize) // .toString()); // } for (int k = 0; k < records.size(); k++) { // byte[] rec = (( byte [] ) bytes.get(k)); // System.arraycopy(rec, 0, data, offset + pos, rec.length); Record record = (( Record ) records.get(k)); //uncomment to test record sizes // byte[] data2 = new byte[record.getRecordSize()]; // record.serialize(0, data2 ); // rec.length; // if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4 // && record instanceof RowRecordsAggregate == false && record instanceof ValueRecordsAggregate == false) // throw new RuntimeException("Blah!!!"); pos += record.serialize(pos + offset, data ); // rec.length; } log.log(log.DEBUG, "Sheet.serialize returning "); return pos; } /** * Create a row record. (does not add it to the records contained in this sheet) * * @param row number * @return RowRecord created for the passed in row number * @see org.apache.poi.hssf.record.RowRecord */ public RowRecord createRow(int row) { log.log(log.DEBUG, "create row number " + row); RowRecord rowrec = new RowRecord(); //rowrec.setRowNumber(( short ) row); rowrec.setRowNumber(row); rowrec.setHeight(( short ) 0xff); rowrec.setOptimize(( short ) 0x0); rowrec.setOptionFlags(( short ) 0x0); rowrec.setXFIndex(( short ) 0x0); return rowrec; } /** * Create a LABELSST Record (does not add it to the records contained in this sheet) * * @param row the row the LabelSST is a member of * @param col the column the LabelSST defines * @param index the index of the string within the SST (use workbook addSSTString method) * @return LabelSSTRecord newly created containing your SST Index, row,col. * @see org.apache.poi.hssf.record.SSTRecord */ //public LabelSSTRecord createLabelSST(short row, short col, int index) public LabelSSTRecord createLabelSST(int row, short col, int index) { log.logFormatted(log.DEBUG, "create labelsst row,col,index %,%,%", new int[] { row, col, index }); LabelSSTRecord rec = new LabelSSTRecord(); rec.setRow(row); rec.setColumn(col); rec.setSSTIndex(index); rec.setXFIndex(( short ) 0x0f); return rec; } /** * Create a NUMBER Record (does not add it to the records contained in this sheet) * * @param row the row the NumberRecord is a member of * @param col the column the NumberRecord defines * @param value for the number record * * @return NumberRecord for that row, col containing that value as added to the sheet */ //public NumberRecord createNumber(short row, short col, double value) public NumberRecord createNumber(int row, short col, double value) { log.logFormatted(log.DEBUG, "create number row,col,value %,%,%", new double[] { row, col, value }); NumberRecord rec = new NumberRecord(); //rec.setRow(( short ) row); rec.setRow(row); rec.setColumn(col); rec.setValue(value); rec.setXFIndex(( short ) 0x0f); return rec; } /** * create a BLANK record (does not add it to the records contained in this sheet) * * @param row - the row the BlankRecord is a member of * @param col - the column the BlankRecord is a member of */ //public BlankRecord createBlank(short row, short col) public BlankRecord createBlank(int row, short col) { //log.logFormatted(log.DEBUG, "create blank row,col %,%", new short[] log.logFormatted(log.DEBUG, "create blank row,col %,%", new int[] { row, col }); BlankRecord rec = new BlankRecord(); //rec.setRow(( short ) row); rec.setRow(row); rec.setColumn(col); rec.setXFIndex(( short ) 0x0f); return rec; } /** * Attempts to parse the formula into PTGs and create a formula record * DOES NOT WORK YET * * @param row - the row for the formula record * @param col - the column of the formula record * @param formula - a String representing the formula. To be parsed to PTGs * @return bogus/useless formula record */ //public FormulaRecord createFormula(short row, short col, String formula) public FormulaRecord createFormula(int row, short col, String formula) { log.logFormatted(log.DEBUG, "create formula row,col,formula %,%,%", //new short[] new int[] { row, col }, formula); FormulaRecord rec = new FormulaRecord(); rec.setRow(row); rec.setColumn(col); rec.setOptions(( short ) 2); rec.setValue(0); rec.setXFIndex(( short ) 0x0f); FormulaParser fp = new FormulaParser(formula,null); //fix - do we need this method? fp.parse(); Ptg[] ptg = fp.getRPNPtg(); int size = 0; for (int k = 0; k < ptg.length; k++) { size += ptg[ k ].getSize(); rec.pushExpressionToken(ptg[ k ]); } rec.setExpressionLength(( short ) size); return rec; } /** * Adds a value record to the sheet's contained binary records * (i.e. LabelSSTRecord or NumberRecord). *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. * * @param row the row to add the cell value to * @param col the cell value record itself. */ //public void addValueRecord(short row, CellValueRecordInterface col) public void addValueRecord(int row, CellValueRecordInterface col) { checkCells(); log.logFormatted(log.DEBUG, "add value record row,loc %,%", new int[] { row, loc }); DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); if (col.getColumn() > d.getLastCol()) { d.setLastCol(( short ) (col.getColumn() + 1)); } if (col.getColumn() < d.getFirstCol()) { d.setFirstCol(col.getColumn()); } cells.insertCell(col); /* * for (int k = loc; k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * if (rec.getSid() == RowRecord.sid) * { * RowRecord rowrec = ( RowRecord ) rec; * * if (rowrec.getRowNumber() == col.getRow()) * { * records.add(k + 1, col); * loc = k; * if (rowrec.getLastCol() <= col.getColumn()) * { * rowrec.setLastCol((( short ) (col.getColumn() + 1))); * } * break; * } * } * } */ } /** * remove a value record from the records array. * * This method is not loc sensitive, it resets loc to = dimsloc so no worries. * * @param row - the row of the value record you wish to remove * @param col - a record supporting the CellValueRecordInterface. * @see org.apache.poi.hssf.record.CellValueRecordInterface */ //public void removeValueRecord(short row, CellValueRecordInterface col) public void removeValueRecord(int row, CellValueRecordInterface col) { checkCells(); log.logFormatted(log.DEBUG, "remove value record row,dimsloc %,%", new int[] { row, dimsloc }); loc = dimsloc; cells.removeCell(col); /* * for (int k = loc; k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * // checkDimsLoc(rec,k); * if (rec.isValue()) * { * CellValueRecordInterface cell = * ( CellValueRecordInterface ) rec; * * if ((cell.getRow() == col.getRow()) * && (cell.getColumn() == col.getColumn())) * { * records.remove(k); * break; * } * } * } */ } /** * replace a value record from the records array. * * This method is not loc sensitive, it resets loc to = dimsloc so no worries. * * @param newval - a record supporting the CellValueRecordInterface. this will replace * the cell value with the same row and column. If there isn't one, one will * be added. */ public void replaceValueRecord(CellValueRecordInterface newval) { checkCells(); setLoc(dimsloc); log.log(log.DEBUG, "replaceValueRecord "); cells.insertCell(newval); /* * CellValueRecordInterface oldval = getNextValueRecord(); * * while (oldval != null) * { * if (oldval.isEqual(newval)) * { * records.set(( short ) (getLoc() - 1), newval); * return; * } * oldval = getNextValueRecord(); * } * addValueRecord(newval.getRow(), newval); * setLoc(dimsloc); */ } /** * Adds a row record to the sheet * *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. * * @param row the row record to be added * @see #setLoc(int) */ public void addRow(RowRecord row) { checkRows(); log.log(log.DEBUG, "addRow "); DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); if (row.getRowNumber() > d.getLastRow()) { d.setLastRow(row.getRowNumber() + 1); } if (row.getRowNumber() < d.getFirstRow()) { d.setFirstRow(row.getRowNumber()); } //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()); if (existingRow != null) rows.removeRow(existingRow); rows.insertRow(row); /* * for (int k = loc; k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * if (rec.getSid() == IndexRecord.sid) * { * index = ( IndexRecord ) rec; * } * if (rec.getSid() == RowRecord.sid) * { * RowRecord rowrec = ( RowRecord ) rec; * * if (rowrec.getRowNumber() > row.getRowNumber()) * { * records.add(k, row); * loc = k; * break; * } * } * if (rec.getSid() == WindowTwoRecord.sid) * { * records.add(k, row); * loc = k; * break; * } * } * if (index != null) * { * if (index.getLastRowAdd1() <= row.getRowNumber()) * { * index.setLastRowAdd1(row.getRowNumber() + 1); * } * } */ log.log(log.DEBUG, "exit addRow"); } /** * Removes a row record * * This method is not loc sensitive, it resets loc to = dimsloc so no worries. * * @param row the row record to remove */ public void removeRow(RowRecord row) { checkRows(); // IndexRecord index = null; setLoc(getDimsLoc()); rows.removeRow(row); /* * for (int k = loc; k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * // checkDimsLoc(rec,k); * if (rec.getSid() == RowRecord.sid) * { * RowRecord rowrec = ( RowRecord ) rec; * * if (rowrec.getRowNumber() == row.getRowNumber()) * { * records.remove(k); * break; * } * } * if (rec.getSid() == WindowTwoRecord.sid) * { * break; * } * } */ } /** * get the NEXT value record (from LOC). The first record that is a value record * (starting at LOC) will be returned. * *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. For this method, set loc to dimsloc to start with, * subsequent calls will return values in (physical) sequence or NULL when you get to the end. * * @return CellValueRecordInterface representing the next value record or NULL if there are no more * @see #setLoc(int) */ public CellValueRecordInterface getNextValueRecord() { log.log(log.DEBUG, "getNextValue loc= " + loc); if (valueRecIterator == null) { valueRecIterator = cells.getIterator(); } if (!valueRecIterator.hasNext()) { return null; } return ( CellValueRecordInterface ) valueRecIterator.next(); /* * if (this.getLoc() < records.size()) * { * for (int k = getLoc(); k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * this.setLoc(k + 1); * if (rec instanceof CellValueRecordInterface) * { * return ( CellValueRecordInterface ) rec; * } * } * } * return null; */ } /** * get the NEXT RowRecord or CellValueRecord(from LOC). The first record that * is a Row record or CellValueRecord(starting at LOC) will be returned. *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. For this method, set loc to dimsloc to start with. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. * * @return RowRecord representing the next row record or CellValueRecordInterface * representing the next cellvalue or NULL if there are no more * @see #setLoc(int) * */ /* public Record getNextRowOrValue() { log.debug((new StringBuffer("getNextRow loc= ")).append(loc) .toString()); if (this.getLoc() < records.size()) { for (int k = this.getLoc(); k < records.size(); k++) { Record rec = ( Record ) records.get(k); this.setLoc(k + 1); if (rec.getSid() == RowRecord.sid) { return rec; } else if (rec.isValue()) { return rec; } } } return null; } */ /** * get the NEXT RowRecord (from LOC). The first record that is a Row record * (starting at LOC) will be returned. *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. For this method, set loc to dimsloc to start with. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. * * @return RowRecord representing the next row record or NULL if there are no more * @see #setLoc(int) * */ public RowRecord getNextRow() { log.log(log.DEBUG, "getNextRow loc= " + loc); if (rowRecIterator == null) { rowRecIterator = rows.getIterator(); } if (!rowRecIterator.hasNext()) { return null; } return ( RowRecord ) rowRecIterator.next(); /* if (this.getLoc() < records.size()) { for (int k = this.getLoc(); k < records.size(); k++) { Record rec = ( Record ) records.get(k); this.setLoc(k + 1); if (rec.getSid() == RowRecord.sid) { return ( RowRecord ) rec; } } }*/ } /** * get the NEXT (from LOC) RowRecord where rownumber matches the given rownum. * The first record that is a Row record (starting at LOC) that has the * same rownum as the given rownum will be returned. *

* This method is "loc" sensitive. Meaning you need to set LOC to where you * want it to start searching. If you don't know do this: setLoc(getDimsLoc). * When adding several rows you can just start at the last one by leaving loc * at what this sets it to. For this method, set loc to dimsloc to start with. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. * * @param rownum which row to return (careful with LOC) * @return RowRecord representing the next row record or NULL if there are no more * @see #setLoc(int) * */ //public RowRecord getRow(short rownum) public RowRecord getRow(int rownum) { log.log(log.DEBUG, "getNextRow loc= " + loc); return rows.getRow(rownum); /* * if (this.getLoc() < records.size()) * { * for (int k = this.getLoc(); k < records.size(); k++) * { * Record rec = ( Record ) records.get(k); * * this.setLoc(k + 1); * if (rec.getSid() == RowRecord.sid) * { * if ((( RowRecord ) rec).getRowNumber() == rownum) * { * return ( RowRecord ) rec; * } * } * } * } */ // return null; } /** * Not currently used method to calculate and add dbcell records * */ public void addDBCellRecords() { int offset = 0; int recnum = 0; int rownum = 0; //int lastrow = 0; //long lastrowoffset = 0; IndexRecord index = null; // ArrayList rowOffsets = new ArrayList(); IntList rowOffsets = new IntList(); for (recnum = 0; recnum < records.size(); recnum++) { Record rec = ( Record ) records.get(recnum); if (rec.getSid() == IndexRecord.sid) { index = ( IndexRecord ) rec; } if (rec.getSid() != RowRecord.sid) { offset += rec.serialize().length; } else { break; } } // First Row Record for (; recnum < records.size(); recnum++) { Record rec = ( Record ) records.get(recnum); if (rec.getSid() == RowRecord.sid) { rownum++; rowOffsets.add(offset); if ((rownum % 32) == 0) { // if this is the last rec in a dbcell block // find the next row or last value record for (int rn = recnum; rn < records.size(); rn++) { rec = ( Record ) records.get(rn); if ((!rec.isInValueSection()) || (rec.getSid() == RowRecord.sid)) { // here is the next row or last value record records.add(rn, createDBCell(offset, rowOffsets, index)); recnum = rn; break; } } } else { } } if (!rec.isInValueSection()) { records.add(recnum, createDBCell(offset, rowOffsets, index)); break; } offset += rec.serialize().length; } } /** not currently used */ private DBCellRecord createDBCell(int offset, IntList rowoffsets, IndexRecord index) { DBCellRecord rec = new DBCellRecord(); rec.setRowOffset(offset - rowoffsets.get(0)); // test hack rec.addCellOffset(( short ) 0x0); // end test hack addDbCellToIndex(offset, index); return rec; } /** not currently used */ private void addDbCellToIndex(int offset, IndexRecord index) { int numdbcells = index.getNumDbcells() + 1; index.addDbcell(offset + preoffset); // stupid but whenever we add an offset that causes everything to be shifted down 4 for (int k = 0; k < numdbcells; k++) { int dbval = index.getDbcellAt(k); index.setDbcell(k, dbval + 4); } } /** * creates the BOF record * @see org.apache.poi.hssf.record.BOFRecord * @see org.apache.poi.hssf.record.Record * @return record containing a BOFRecord */ protected Record createBOF() { BOFRecord retval = new BOFRecord(); retval.setVersion(( short ) 0x600); retval.setType(( short ) 0x010); // retval.setBuild((short)0x10d3); retval.setBuild(( short ) 0x0dbb); retval.setBuildYear(( short ) 1996); retval.setHistoryBitMask(0xc1); retval.setRequiredVersion(0x6); return retval; } /** * creates the Index record - not currently used * @see org.apache.poi.hssf.record.IndexRecord * @see org.apache.poi.hssf.record.Record * @return record containing a IndexRecord */ protected Record createIndex() { IndexRecord retval = new IndexRecord(); retval.setFirstRow(0); // must be set explicitly retval.setLastRowAdd1(0); return retval; } /** * creates the CalcMode record and sets it to 1 (automatic formula caculation) * @see org.apache.poi.hssf.record.CalcModeRecord * @see org.apache.poi.hssf.record.Record * @return record containing a CalcModeRecord */ protected Record createCalcMode() { CalcModeRecord retval = new CalcModeRecord(); retval.setCalcMode(( short ) 1); return retval; } /** * creates the CalcCount record and sets it to 0x64 (default number of iterations) * @see org.apache.poi.hssf.record.CalcCountRecord * @see org.apache.poi.hssf.record.Record * @return record containing a CalcCountRecord */ protected Record createCalcCount() { CalcCountRecord retval = new CalcCountRecord(); retval.setIterations(( short ) 0x64); // default 64 iterations return retval; } /** * creates the RefMode record and sets it to A1 Mode (default reference mode) * @see org.apache.poi.hssf.record.RefModeRecord * @see org.apache.poi.hssf.record.Record * @return record containing a RefModeRecord */ protected Record createRefMode() { RefModeRecord retval = new RefModeRecord(); retval.setMode(retval.USE_A1_MODE); return retval; } /** * creates the Iteration record and sets it to false (don't iteratively calculate formulas) * @see org.apache.poi.hssf.record.IterationRecord * @see org.apache.poi.hssf.record.Record * @return record containing a IterationRecord */ protected Record createIteration() { IterationRecord retval = new IterationRecord(); retval.setIteration(false); return retval; } /** * creates the Delta record and sets it to 0.0010 (default accuracy) * @see org.apache.poi.hssf.record.DeltaRecord * @see org.apache.poi.hssf.record.Record * @return record containing a DeltaRecord */ protected Record createDelta() { DeltaRecord retval = new DeltaRecord(); retval.setMaxChange(0.0010); return retval; } /** * creates the SaveRecalc record and sets it to true (recalculate before saving) * @see org.apache.poi.hssf.record.SaveRecalcRecord * @see org.apache.poi.hssf.record.Record * @return record containing a SaveRecalcRecord */ protected Record createSaveRecalc() { SaveRecalcRecord retval = new SaveRecalcRecord(); retval.setRecalc(true); return retval; } /** * creates the PrintHeaders record and sets it to false (we don't create headers yet so why print them) * @see org.apache.poi.hssf.record.PrintHeadersRecord * @see org.apache.poi.hssf.record.Record * @return record containing a PrintHeadersRecord */ protected Record createPrintHeaders() { PrintHeadersRecord retval = new PrintHeadersRecord(); retval.setPrintHeaders(false); return retval; } /** * creates the PrintGridlines record and sets it to false (that makes for ugly sheets). As far as I can * tell this does the same thing as the GridsetRecord * * @see org.apache.poi.hssf.record.PrintGridlinesRecord * @see org.apache.poi.hssf.record.Record * @return record containing a PrintGridlinesRecord */ protected Record createPrintGridlines() { PrintGridlinesRecord retval = new PrintGridlinesRecord(); retval.setPrintGridlines(false); return retval; } /** * creates the Gridset record and sets it to true (user has mucked with the gridlines) * @see org.apache.poi.hssf.record.GridsetRecord * @see org.apache.poi.hssf.record.Record * @return record containing a GridsetRecord */ protected Record createGridset() { GridsetRecord retval = new GridsetRecord(); retval.setGridset(true); return retval; } /** * creates the Guts record and sets leftrow/topcol guttter and rowlevelmax/collevelmax to 0 * @see org.apache.poi.hssf.record.GutsRecord * @see org.apache.poi.hssf.record.Record * @return record containing a GutsRecordRecord */ protected Record createGuts() { GutsRecord retval = new GutsRecord(); retval.setLeftRowGutter(( short ) 0); retval.setTopColGutter(( short ) 0); retval.setRowLevelMax(( short ) 0); retval.setColLevelMax(( short ) 0); return retval; } /** * creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff * @see org.apache.poi.hssf.record.DefaultRowHeightRecord * @see org.apache.poi.hssf.record.Record * @return record containing a DefaultRowHeightRecord */ protected Record createDefaultRowHeight() { DefaultRowHeightRecord retval = new DefaultRowHeightRecord(); retval.setOptionFlags(( short ) 0); retval.setRowHeight(( short ) 0xff); return retval; } /** * creates the WSBoolRecord and sets its values to defaults * @see org.apache.poi.hssf.record.WSBoolRecord * @see org.apache.poi.hssf.record.Record * @return record containing a WSBoolRecord */ protected Record createWSBool() { WSBoolRecord retval = new WSBoolRecord(); retval.setWSBool1(( byte ) 0x4); retval.setWSBool2(( byte ) 0xffffffc1); return retval; } /** * creates the Header Record and sets it to nothing/0 length * @see org.apache.poi.hssf.record.HeaderRecord * @see org.apache.poi.hssf.record.Record * @return record containing a HeaderRecord */ protected Record createHeader() { HeaderRecord retval = new HeaderRecord(); retval.setHeaderLength(( byte ) 0); retval.setHeader(null); return retval; } /** * creates the Footer Record and sets it to nothing/0 length * @see org.apache.poi.hssf.record.FooterRecord * @see org.apache.poi.hssf.record.Record * @return record containing a FooterRecord */ protected Record createFooter() { FooterRecord retval = new FooterRecord(); retval.setFooterLength(( byte ) 0); retval.setFooter(null); return retval; } /** * creates the HCenter Record and sets it to false (don't horizontally center) * @see org.apache.poi.hssf.record.HCenterRecord * @see org.apache.poi.hssf.record.Record * @return record containing a HCenterRecord */ protected Record createHCenter() { HCenterRecord retval = new HCenterRecord(); retval.setHCenter(false); return retval; } /** * creates the VCenter Record and sets it to false (don't horizontally center) * @see org.apache.poi.hssf.record.VCenterRecord * @see org.apache.poi.hssf.record.Record * @return record containing a VCenterRecord */ protected Record createVCenter() { VCenterRecord retval = new VCenterRecord(); retval.setVCenter(false); return retval; } /** * creates the PrintSetup Record and sets it to defaults and marks it invalid * @see org.apache.poi.hssf.record.PrintSetupRecord * @see org.apache.poi.hssf.record.Record * @return record containing a PrintSetupRecord */ protected Record createPrintSetup() { PrintSetupRecord retval = new PrintSetupRecord(); retval.setPaperSize(( short ) 1); retval.setScale(( short ) 100); retval.setPageStart(( short ) 1); retval.setFitWidth(( short ) 1); retval.setFitHeight(( short ) 1); retval.setOptions(( short ) 2); retval.setHResolution(( short ) 300); retval.setVResolution(( short ) 300); retval.setHeaderMargin( 0.5); retval.setFooterMargin( 0.5); retval.setCopies(( short ) 0); return retval; } /** * creates the DefaultColWidth Record and sets it to 8 * @see org.apache.poi.hssf.record.DefaultColWidthRecord * @see org.apache.poi.hssf.record.Record * @return record containing a DefaultColWidthRecord */ protected Record createDefaultColWidth() { DefaultColWidthRecord retval = new DefaultColWidthRecord(); retval.setColWidth(( short ) 8); return retval; } /** * creates the ColumnInfo Record and sets it to a default column/width * @see org.apache.poi.hssf.record.ColumnInfoRecord * @return record containing a ColumnInfoRecord */ protected Record createColInfo() { ColumnInfoRecord retval = new ColumnInfoRecord(); retval.setColumnWidth(( short ) 0x8); retval.setOptions(( short ) 6); retval.setXFIndex(( short ) 0x0f); return retval; } /** * get the default column width for the sheet (if the columns do not define their own width) * @return default column width */ public short getDefaultColumnWidth() { return defaultcolwidth.getColWidth(); } /** * get whether gridlines are printed. * @return true if printed */ public boolean isGridsPrinted() { return !gridset.getGridset(); } /** * set whether gridlines printed or not. * @param value True if gridlines printed. */ public void setGridsPrinted(boolean value) { gridset.setGridset(!value); } /** * set the default column width for the sheet (if the columns do not define their own width) * @param dcw default column width */ public void setDefaultColumnWidth(short dcw) { defaultcolwidth.setColWidth(dcw); } /** * set the default row height for the sheet (if the rows do not define their own height) */ public void setDefaultRowHeight(short dch) { defaultrowheight.setRowHeight(dch); } /** * get the default row height for the sheet (if the rows do not define their own height) * @return default row height */ public short getDefaultRowHeight() { return defaultrowheight.getRowHeight(); } /** * get the width of a given column in units of 1/20th of a point width (twips?) * @param column 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/20th of a point (twips?) */ public short getColumnWidth(short column) { short retval = 0; ColumnInfoRecord ci = null; int k = 0; if (columnSizes != null) { for (k = 0; k < columnSizes.size(); k++) { ci = ( ColumnInfoRecord ) columnSizes.get(k); if ((ci.getFirstColumn() <= column) && (column <= ci.getLastColumn())) { break; } ci = null; } } if (ci != null) { retval = ci.getColumnWidth(); } else { retval = defaultcolwidth.getColWidth(); } return retval; } /** * set the width for a given column in 1/20th of a character width units * @param column - the column number * @param width (in units of 1/20th of a character width) */ public void setColumnWidth(short column, short width) { ColumnInfoRecord ci = null; int k = 0; if (columnSizes == null) { columnSizes = new ArrayList(); } //int cioffset = getDimsLoc() - columnSizes.size(); for (k = 0; k < columnSizes.size(); k++) { ci = ( ColumnInfoRecord ) columnSizes.get(k); if ((ci.getFirstColumn() <= column) && (column <= ci.getLastColumn())) { break; } ci = null; } if (ci != null) { if (ci.getColumnWidth() == width) { // do nothing...the cell's width is equal to what we're setting it to. } else if ((ci.getFirstColumn() == column) && (ci.getLastColumn() == column)) { // if its only for this cell then ci.setColumnWidth(width); // who cares, just change the width } else if ((ci.getFirstColumn() == column) || (ci.getLastColumn() == column)) { // okay so the width is different but the first or last column == the column we'return setting // we'll just divide the info and create a new one if (ci.getFirstColumn() == column) { ci.setFirstColumn(( short ) (column + 1)); } else { ci.setLastColumn(( short ) (column - 1)); } ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); nci.setFirstColumn(column); nci.setLastColumn(column); nci.setOptions(ci.getOptions()); nci.setXFIndex(ci.getXFIndex()); nci.setColumnWidth(width); columnSizes.add(k, nci); records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); dimsloc++; } else{ //split to 3 records short lastcolumn = ci.getLastColumn(); ci.setLastColumn(( short ) (column - 1)); ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); nci.setFirstColumn(column); nci.setLastColumn(column); nci.setOptions(ci.getOptions()); nci.setXFIndex(ci.getXFIndex()); nci.setColumnWidth(width); columnSizes.add(k, nci); records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); dimsloc++; nci = ( ColumnInfoRecord ) createColInfo(); nci.setFirstColumn((short)(column+1)); nci.setLastColumn(lastcolumn); nci.setOptions(ci.getOptions()); nci.setXFIndex(ci.getXFIndex()); nci.setColumnWidth(ci.getColumnWidth()); columnSizes.add(k, nci); records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); dimsloc++; } } else { // okay so there ISN'T a column info record that cover's this column so lets create one! ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); nci.setFirstColumn(column); nci.setLastColumn(column); nci.setColumnWidth(width); columnSizes.add(k, nci); records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); dimsloc++; } } /** * creates the Dimensions Record and sets it to bogus values (you should set this yourself * or let the high level API do it for you) * @see org.apache.poi.hssf.record.DimensionsRecord * @see org.apache.poi.hssf.record.Record * @return record containing a DimensionsRecord */ protected Record createDimensions() { DimensionsRecord retval = new DimensionsRecord(); retval.setFirstCol(( short ) 0); retval.setLastRow(1); // one more than it is retval.setFirstRow(0); retval.setLastCol(( short ) 1); // one more than it is return retval; } /** * creates the WindowTwo Record and sets it to:

* options = 0x6b6

* toprow = 0

* leftcol = 0

* headercolor = 0x40

* pagebreakzoom = 0x0

* normalzoom = 0x0

* @see org.apache.poi.hssf.record.WindowTwoRecord * @see org.apache.poi.hssf.record.Record * @return record containing a WindowTwoRecord */ protected WindowTwoRecord createWindowTwo() { WindowTwoRecord retval = new WindowTwoRecord(); retval.setOptions(( short ) 0x6b6); retval.setTopRow(( short ) 0); retval.setLeftCol(( short ) 0); retval.setHeaderColor(0x40); retval.setPageBreakZoom(( short ) 0); retval.setNormalZoom(( short ) 0); return retval; } /** * Creates the Selection record and sets it to nothing selected * * @see org.apache.poi.hssf.record.SelectionRecord * @see org.apache.poi.hssf.record.Record * @return record containing a SelectionRecord */ protected Record createSelection() { SelectionRecord retval = new SelectionRecord(); retval.setPane(( byte ) 0x3); retval.setActiveCellCol(( short ) 0x0); retval.setActiveCellRow(( short ) 0x0); retval.setNumRefs(( short ) 0x0); return retval; } /** * Returns the active row * * @see org.apache.poi.hssf.record.SelectionRecord * @return row the active row index */ public int getActiveCellRow() { if (selection == null) { return 0; } return selection.getActiveCellRow(); } /** * Sets the active row * * @param row the row index * @see org.apache.poi.hssf.record.SelectionRecord */ public void setActiveCellRow(int row) { //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway if (selection != null) { selection.setActiveCellRow(row); } } /** * Returns the active column * * @see org.apache.poi.hssf.record.SelectionRecord * @return row the active column index */ public short getActiveCellCol() { if (selection == null) { return (short) 0; } return selection.getActiveCellCol(); } /** * Sets the active column * * @param col the column index * @see org.apache.poi.hssf.record.SelectionRecord */ public void setActiveCellCol(short col) { //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway if (selection != null) { selection.setActiveCellCol(col); } } protected Record createMergedCells() { MergeCellsRecord retval = new MergeCellsRecord(); retval.setNumAreas(( short ) 0); return retval; } /** * creates the EOF record * @see org.apache.poi.hssf.record.EOFRecord * @see org.apache.poi.hssf.record.Record * @return record containing a EOFRecord */ protected Record createEOF() { return new EOFRecord(); } /** * get the location of the DimensionsRecord (which is the last record before the value section) * @return location in the array of records of the DimensionsRecord */ public int getDimsLoc() { log.log(log.DEBUG, "getDimsLoc dimsloc= " + dimsloc); return dimsloc; } /** * in the event the record is a dimensions record, resets both the loc index and dimsloc index */ public void checkDimsLoc(Record rec, int recloc) { if (rec.getSid() == DimensionsRecord.sid) { loc = recloc; dimsloc = recloc; } } public int getSize() { int retval = 0; for (int k = 0; k < records.size(); k++) { retval += (( Record ) records.get(k)).getRecordSize(); } return retval; } public List getRecords() { return records; } /** * Gets the gridset record for this sheet. */ public GridsetRecord getGridsetRecord() { return gridset; } /** * Returns the first occurance of a record matching a particular sid. */ public Record findFirstRecordBySid(short sid) { for (Iterator iterator = records.iterator(); iterator.hasNext(); ) { Record record = ( Record ) iterator.next(); if (record.getSid() == sid) { return record; } } return null; } /** * Sets the SCL record or creates it in the correct place if it does not * already exist. * * @param sclRecord The record to set. */ public void setSCLRecord(SCLRecord sclRecord) { int oldRecordLoc = findFirstRecordLocBySid(SCLRecord.sid); if (oldRecordLoc == -1) { // Insert it after the window record int windowRecordLoc = findFirstRecordLocBySid(WindowTwoRecord.sid); records.add(windowRecordLoc+1, sclRecord); } else { records.set(oldRecordLoc, sclRecord); } } /** * Finds the first occurance of a record matching a particular sid and * returns it's position. * @param sid the sid to search for * @return the record position of the matching record or -1 if no match * is made. */ public int findFirstRecordLocBySid( short sid ) { int index = 0; for (Iterator iterator = records.iterator(); iterator.hasNext(); ) { Record record = ( Record ) iterator.next(); if (record.getSid() == sid) { return index; } index++; } return -1; } /** * Returns the HeaderRecord. * @return HeaderRecord for the sheet. */ public HeaderRecord getHeader () { return header; } /** * Sets the HeaderRecord. * @param newHeader The new HeaderRecord for the sheet. */ public void setHeader (HeaderRecord newHeader) { header = newHeader; } /** * Returns the FooterRecord. * @return FooterRecord for the sheet. */ public FooterRecord getFooter () { return footer; } /** * Sets the FooterRecord. * @param newFooter The new FooterRecord for the sheet. */ public void setFooter (FooterRecord newFooter) { footer = newFooter; } /** * Returns the PrintSetupRecord. * @return PrintSetupRecord for the sheet. */ public PrintSetupRecord getPrintSetup () { return printSetup; } /** * Sets the PrintSetupRecord. * @param newPrintSetup The new PrintSetupRecord for the sheet. */ public void setPrintSetup (PrintSetupRecord newPrintSetup) { printSetup = newPrintSetup; } /** * Returns the PrintGridlinesRecord. * @return PrintGridlinesRecord for the sheet. */ public PrintGridlinesRecord getPrintGridlines () { return printGridlines; } /** * Sets the PrintGridlinesRecord. * @param newPrintGridlines The new PrintGridlinesRecord for the sheet. */ public void setPrintGridlines (PrintGridlinesRecord newPrintGridlines) { printGridlines = newPrintGridlines; } /** * Sets whether the sheet is selected * @param sel True to select the sheet, false otherwise. */ public void setSelected(boolean sel) { windowTwo.setSelected(sel); } /** * Gets the size of the margin in inches. * @param margin which margin to get * @return the size of the margin */ public double getMargin(short margin) { if (getMargins()[margin] != null) return margins[margin].getMargin(); else { switch ( margin ) { case LeftMargin: return .75; case RightMargin: return .75; case TopMargin: return 1.0; case BottomMargin: return 1.0; default : throw new RuntimeException( "Unknown margin constant: " + margin ); } } } /** * Sets the size of the margin in inches. * @param margin which margin to get * @param size the size of the margin */ public void setMargin(short margin, double size) { Margin m = getMargins()[margin]; if (m == null) { switch ( margin ) { case LeftMargin: m = new LeftMarginRecord(); records.add( getDimsLoc() + 1, m ); break; case RightMargin: m = new RightMarginRecord(); records.add( getDimsLoc() + 1, m ); break; case TopMargin: m = new TopMarginRecord(); records.add( getDimsLoc() + 1, m ); break; case BottomMargin: m = new BottomMarginRecord(); records.add( getDimsLoc() + 1, m ); break; default : throw new RuntimeException( "Unknown margin constant: " + margin ); } margins[margin] = m; } m.setMargin( size ); } public int getEofLoc() { return eofLoc; } /** * Creates a split (freezepane). * @param colSplit Horizonatal position of split. * @param rowSplit Vertical position of split. * @param topRow Top row visible in bottom pane * @param leftmostColumn Left column visible in right pane. */ public void createFreezePane(int colSplit, int rowSplit, int topRow, int leftmostColumn ) { int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); PaneRecord pane = new PaneRecord(); pane.setX((short)colSplit); pane.setY((short)rowSplit); pane.setTopRow((short) topRow); pane.setLeftColumn((short) leftmostColumn); if (rowSplit == 0) { pane.setTopRow((short)0); pane.setActivePane((short)1); } else if (colSplit == 0) { pane.setLeftColumn((short)64); pane.setActivePane((short)2); } else { pane.setActivePane((short)0); } records.add(loc+1, pane); windowTwo.setFreezePanes(true); windowTwo.setFreezePanesNoSplit(true); SelectionRecord sel = (SelectionRecord) findFirstRecordBySid(SelectionRecord.sid); // SelectionRecord sel2 = (SelectionRecord) sel.clone(); // SelectionRecord sel3 = (SelectionRecord) sel.clone(); // SelectionRecord sel4 = (SelectionRecord) sel.clone(); // sel.setPane(PANE_LOWER_RIGHT); // 0 // sel3.setPane(PANE_UPPER_RIGHT); // 1 sel.setPane((byte)pane.getActivePane()); // 2 // sel2.setPane(PANE_UPPER_LEFT); // 3 // sel4.setActiveCellCol((short)Math.max(sel3.getActiveCellCol(), colSplit)); // sel3.setActiveCellRow((short)Math.max(sel4.getActiveCellRow(), rowSplit)); int selLoc = findFirstRecordLocBySid(SelectionRecord.sid); // sel.setActiveCellCol((short)15); // sel.setActiveCellRow((short)15); // sel2.setActiveCellCol((short)0); // sel2.setActiveCellRow((short)0); // records.add(selLoc+1,sel2); // records.add(selLoc+2,sel3); // records.add(selLoc+3,sel4); } /** * Creates a split pane. * @param xSplitPos Horizonatal position of split (in 1/20th of a point). * @param ySplitPos Vertical position of split (in 1/20th of a point). * @param topRow Top row visible in bottom pane * @param leftmostColumn Left column visible in right pane. * @param activePane Active pane. One of: PANE_LOWER_RIGHT, * PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT * @see #PANE_LOWER_LEFT * @see #PANE_LOWER_RIGHT * @see #PANE_UPPER_LEFT * @see #PANE_UPPER_RIGHT */ public void createSplitPane(int xSplitPos, int ySplitPos, int topRow, int leftmostColumn, int activePane ) { int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); PaneRecord r = new PaneRecord(); r.setX((short)xSplitPos); r.setY((short)ySplitPos); r.setTopRow((short) topRow); r.setLeftColumn((short) leftmostColumn); r.setActivePane((short) activePane); records.add(loc+1, r); windowTwo.setFreezePanes(false); windowTwo.setFreezePanesNoSplit(false); SelectionRecord sel = (SelectionRecord) findFirstRecordBySid(SelectionRecord.sid); // SelectionRecord sel2 = (SelectionRecord) sel.clone(); // SelectionRecord sel3 = (SelectionRecord) sel.clone(); // SelectionRecord sel4 = (SelectionRecord) sel.clone(); sel.setPane(PANE_LOWER_RIGHT); // 0 // sel3.setPane(PANE_UPPER_RIGHT); // 1 // sel4.setPane(PANE_LOWER_LEFT); // 2 // sel2.setPane(PANE_UPPER_LEFT); // 3 // sel4.setActiveCellCol((short)Math.max(sel3.getActiveCellCol(), colSplit)); // sel3.setActiveCellRow((short)Math.max(sel4.getActiveCellRow(), rowSplit)); int selLoc = findFirstRecordLocBySid(SelectionRecord.sid); // sel.setActiveCellCol((short)15); // sel.setActiveCellRow((short)15); // sel2.setActiveCellCol((short)0); // sel2.setActiveCellRow((short)0); // records.add(selLoc+1,sel2); // records.add(selLoc+2,sel3); // records.add(selLoc+3,sel4); } public SelectionRecord getSelection() { return selection; } public void setSelection( SelectionRecord selection ) { this.selection = selection; } /** * creates a Protect record with protect set to false. * @see org.apache.poi.hssf.record.ProtectRecord * @see org.apache.poi.hssf.record.Record * @return a ProtectRecord */ protected Record createProtect() { log.log(log.DEBUG, "create protect record with protection disabled"); ProtectRecord retval = new ProtectRecord(); retval.setProtect(false); // by default even when we support encryption we won't return retval; } public ProtectRecord getProtect() { return protect; } /** * Sets whether the gridlines are shown in a viewer. * @param show whether to show gridlines or not */ public void setDisplayGridlines(boolean show) { windowTwo.setDisplayGridlines(show); } /** * Returns if gridlines are displayed. * @return whether gridlines are displayed */ public boolean isDisplayGridlines() { return windowTwo.getDisplayGridlines(); } /** * Sets whether the formulas are shown in a viewer. * @param show whether to show formulas or not */ public void setDisplayFormulas(boolean show) { windowTwo.setDisplayFormulas(show); } /** * Returns if formulas are displayed. * @return whether formulas are displayed */ public boolean isDisplayFormulas() { return windowTwo.getDisplayFormulas(); } /** * Sets whether the RowColHeadings are shown in a viewer. * @param show whether to show RowColHeadings or not */ public void setDisplayRowColHeadings(boolean show) { windowTwo.setDisplayRowColHeadings(show); } /** * Returns if RowColHeadings are displayed. * @return whether RowColHeadings are displayed */ public boolean isDisplayRowColHeadings() { return windowTwo.getDisplayRowColHeadings(); } /** * Returns the array of margins. If not created, will create. * * @return the array of marings. */ protected Margin[] getMargins() { if (margins == null) margins = new Margin[4]; return margins; } }