From: Josh Micich Date: Tue, 22 Dec 2009 00:51:29 +0000 (+0000) Subject: Renamed model.Workbook to InternalWorkbook to alleviate name clash. X-Git-Tag: REL_3_7_BETA1~196 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1fd52310cd92e6c426950d8045aafe3fb0d0ea6a;p=poi.git Renamed model.Workbook to InternalWorkbook to alleviate name clash. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893050 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java index c7a1471a7d..c8c2491f3c 100644 --- a/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java +++ b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java @@ -20,7 +20,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.EOFRecord; import org.apache.poi.hssf.record.ExternSheetRecord; @@ -30,39 +30,31 @@ import org.apache.poi.hssf.record.SupBookRecord; import org.apache.poi.hssf.usermodel.HSSFWorkbook; /** - * When working with the EventUserModel, if you want to + * When working with the EventUserModel, if you want to * process formulas, you need an instance of - * {@link Workbook} to pass to a {@link HSSFWorkbook}, - * to finally give to {@link HSSFFormulaParser}, + * {@link InternalWorkbook} to pass to a {@link HSSFWorkbook}, + * to finally give to {@link HSSFFormulaParser}, * and this will build you stub ones. * Since you're working with the EventUserModel, you - * wouldn't want to get a full {@link Workbook} and + * wouldn't want to get a full {@link InternalWorkbook} and * {@link HSSFWorkbook}, as they would eat too much memory. * Instead, you should collect a few key records as they * go past, then call this once you have them to build a - * stub {@link Workbook}, and from that a stub + * stub {@link InternalWorkbook}, and from that a stub * {@link HSSFWorkbook}, to use with the {@link HSSFFormulaParser}. - * + * * The records you should collect are: * * {@link ExternSheetRecord} * * {@link BoundSheetRecord} - * You should probably also collect {@link SSTRecord}, + * You should probably also collect {@link SSTRecord}, * but it's not required to pass this in. - * + * * To help, this class includes a HSSFListener wrapper * that will do the collecting for you. */ public class EventWorkbookBuilder { - /** - * Wraps up your stub {@link Workbook} as a stub - * {@link HSSFWorkbook}, ready for passing to - * {@link HSSFFormulaParser} - * @param workbook A stub {@link Workbook} - */ - public static HSSFWorkbook createStubHSSFWorkbook(Workbook workbook) { - return new StubHSSFWorkbook(workbook); - } - + + /** * Creates a stub Workbook from the supplied records, * suitable for use with the {@link HSSFFormulaParser} @@ -71,10 +63,10 @@ public class EventWorkbookBuilder { * @param sst The SSTRecord in your file. * @return A stub Workbook suitable for use with {@link HSSFFormulaParser} */ - public static Workbook createStubWorkbook(ExternSheetRecord[] externs, + public static InternalWorkbook createStubWorkbook(ExternSheetRecord[] externs, BoundSheetRecord[] bounds, SSTRecord sst) { List wbRecords = new ArrayList(); - + // Core Workbook records go first if(bounds != null) { for(int i=0; i + * This file contains the low level binary records starting at the workbook's BOF and + * ending with the workbook's EOF. Use HSSFWorkbook 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 Luc Girardin (luc dot girardin at macrofocus dot com) + * @author Sergei Kozello (sergeikozello at mail.ru) + * @author Shawn Laubach (slaubach at apache dot org) (Data Formats) + * @author Andrew C. Oliver (acoliver at apache dot org) + * @author Brian Sanders (bsanders at risklabs dot com) - custom palette + * @author Dan Sherman (dsherman at isisph.com) + * @author Glen Stampoultzis (glens at apache.org) + * @see org.apache.poi.hssf.usermodel.HSSFWorkbook + */ +@Internal +public final class InternalWorkbook { + /** + * Excel silently truncates long sheet names to 31 chars. + * This constant is used to ensure uniqueness in the first 31 chars + */ + private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31; + + + private static final POILogger log = POILogFactory.getLogger(InternalWorkbook.class); + private static final int DEBUG = POILogger.DEBUG; + + /** + * constant used to set the "codepage" wherever "codepage" is set in records + * (which is duplicated in more than one record) + */ + private final static short CODEPAGE = 0x04B0; + + /** + * this contains the Worksheet record objects + */ + private final WorkbookRecordList records; + + /** + * this contains a reference to the SSTRecord so that new stings can be added + * to it. + */ + protected SSTRecord sst; + + + private LinkTable linkTable; // optionally occurs if there are references in the document. (4.10.3) + + /** + * holds the "boundsheet" records (aka bundlesheet) so that they can have their + * reference to their "BOF" marker + */ + private final List boundsheets; + private final List formats; + private final List hyperlinks; + + /** the number of extended format records */ + private int numxfs; + /** the number of font records */ + private int numfonts; + /** holds the max format id */ + private int maxformatid; + /** whether 1904 date windowing is being used */ + private boolean uses1904datewindowing; + private DrawingManager2 drawingManager; + private List escherBSERecords; + private WindowOneRecord windowOne; + private FileSharingRecord fileShare; + private WriteAccessRecord writeAccess; + private WriteProtectRecord writeProtect; + + private InternalWorkbook() { + records = new WorkbookRecordList(); + + boundsheets = new ArrayList(); + formats = new ArrayList(); + hyperlinks = new ArrayList(); + numxfs = 0; + numfonts = 0; + maxformatid = -1; + uses1904datewindowing = false; + escherBSERecords = new ArrayList(); + } + + /** + * read support for low level + * API. Pass in an array of Record objects, A Workbook + * object is constructed and passed back with all of its initialization set + * to the passed in records and references to those records held. Unlike Sheet + * workbook does not use an offset (its assumed to be 0) since its first in a file. + * If you need an offset then construct a new array with a 0 offset or write your + * own ;-p. + * + * @param recs an array of Record objects + * @return Workbook object + */ + public static InternalWorkbook createWorkbook(List recs) { + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "Workbook (readfile) created with reclen=", + Integer.valueOf(recs.size())); + InternalWorkbook retval = new InternalWorkbook(); + List records = new ArrayList(recs.size() / 3); + retval.records.setRecords(records); + + int k; + for (k = 0; k < recs.size(); k++) { + Record rec = recs.get(k); + + if (rec.getSid() == EOFRecord.sid) { + records.add(rec); + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found workbook eof record at " + k); + break; + } + switch (rec.getSid()) { + + case BoundSheetRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found boundsheet record at " + k); + retval.boundsheets.add((BoundSheetRecord) rec); + retval.records.setBspos( k ); + break; + + case SSTRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found sst record at " + k); + retval.sst = ( SSTRecord ) rec; + break; + + case FontRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found font record at " + k); + retval.records.setFontpos( k ); + retval.numfonts++; + break; + + case ExtendedFormatRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found XF record at " + k); + retval.records.setXfpos( k ); + retval.numxfs++; + break; + + case TabIdRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found tabid record at " + k); + retval.records.setTabpos( k ); + break; + + case ProtectRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found protect record at " + k); + retval.records.setProtpos( k ); + break; + + case BackupRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found backup record at " + k); + retval.records.setBackuppos( k ); + break; + case ExternSheetRecord.sid : + throw new RuntimeException("Extern sheet is part of LinkTable"); + case NameRecord.sid : + case SupBookRecord.sid : + // LinkTable can start with either of these + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found SupBook record at " + k); + retval.linkTable = new LinkTable(recs, k, retval.records); + k+=retval.linkTable.getRecordCount() - 1; + continue; + case FormatRecord.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found format record at " + k); + retval.formats.add((FormatRecord) rec); + retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); + break; + case DateWindow1904Record.sid : + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found datewindow1904 record at " + k); + retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1; + break; + case PaletteRecord.sid: + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found palette record at " + k); + retval.records.setPalettepos( k ); + break; + case WindowOneRecord.sid: + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found WindowOneRecord at " + k); + retval.windowOne = (WindowOneRecord) rec; + break; + case WriteAccessRecord.sid: + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found WriteAccess at " + k); + retval.writeAccess = (WriteAccessRecord) rec; + break; + case WriteProtectRecord.sid: + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found WriteProtect at " + k); + retval.writeProtect = (WriteProtectRecord) rec; + break; + case FileSharingRecord.sid: + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "found FileSharing at " + k); + retval.fileShare = (FileSharingRecord) rec; + default : + } + records.add(rec); + } + //What if we dont have any ranges and supbooks + // if (retval.records.supbookpos == 0) { + // retval.records.supbookpos = retval.records.bspos + 1; + // retval.records.namepos = retval.records.supbookpos + 1; + // } + + // Look for other interesting values that + // follow the EOFRecord + for ( ; k < recs.size(); k++) { + Record rec = recs.get(k); + switch (rec.getSid()) { + case HyperlinkRecord.sid: + retval.hyperlinks.add((HyperlinkRecord)rec); + break; + } + } + + if (retval.windowOne == null) { + retval.windowOne = createWindowOne(); + } + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "exit create workbook from existing file function"); + return retval; + } + + /** + * Creates an empty workbook object with three blank sheets and all the empty + * fields. Use this to create a workbook from scratch. + */ + public static InternalWorkbook createWorkbook() + { + if (log.check( POILogger.DEBUG )) + log.log( DEBUG, "creating new workbook from scratch" ); + InternalWorkbook retval = new InternalWorkbook(); + List records = new ArrayList( 30 ); + retval.records.setRecords(records); + List formats = retval.formats; + + records.add(retval.createBOF()); + records.add(retval.createInterfaceHdr()); + records.add(retval.createMMS()); + records.add(retval.createInterfaceEnd()); + records.add(retval.createWriteAccess()); + records.add(retval.createCodepage()); + records.add(retval.createDSF()); + records.add(retval.createTabId()); + retval.records.setTabpos(records.size() - 1); + records.add(retval.createFnGroupCount()); + records.add(createWindowProtect()); + records.add(createProtect()); + retval.records.setProtpos(records.size() - 1); + records.add(createPassword()); + records.add(createProtectionRev4()); + records.add(retval.createPasswordRev4()); + retval.windowOne = createWindowOne(); + records.add(retval.windowOne); + records.add(retval.createBackup()); + retval.records.setBackuppos(records.size() - 1); + records.add(retval.createHideObj()); + records.add(retval.createDateWindow1904()); + records.add(retval.createPrecision()); + records.add(createRefreshAll()); + records.add(retval.createBookBool()); + records.add(retval.createFont()); + records.add(retval.createFont()); + records.add(retval.createFont()); + records.add(retval.createFont()); + retval.records.setFontpos( records.size() - 1 ); // last font record position + retval.numfonts = 4; + + // set up format records + for (int i = 0; i <= 7; i++) { + FormatRecord rec = createFormat(i); + retval.maxformatid = retval.maxformatid >= rec.getIndexCode() ? retval.maxformatid : rec.getIndexCode(); + formats.add(rec); + records.add(rec); + } + + for (int k = 0; k < 21; k++) { + records.add(retval.createExtendedFormat(k)); + retval.numxfs++; + } + retval.records.setXfpos( records.size() - 1 ); + for (int k = 0; k < 6; k++) { + records.add(retval.createStyle(k)); + } + records.add(retval.createUseSelFS()); + + int nBoundSheets = 1; // now just do 1 + for (int k = 0; k < nBoundSheets; k++) { + BoundSheetRecord bsr = createBoundSheet(k); + + records.add(bsr); + retval.boundsheets.add(bsr); + retval.records.setBspos(records.size() - 1); + } + records.add( retval.createCountry() ); + for ( int k = 0; k < nBoundSheets; k++ ) { + retval.getOrCreateLinkTable().checkExternSheet(k); + } + retval.sst = new SSTRecord(); + records.add(retval.sst); + records.add(retval.createExtendedSST()); + + records.add(EOFRecord.instance); + if (log.check( POILogger.DEBUG )) + log.log( DEBUG, "exit create new workbook from scratch" ); + return retval; + } + + + /**Retrieves the Builtin NameRecord that matches the name and index + * There shouldn't be too many names to make the sequential search too slow + * @param name byte representation of the builtin name to match + * @param sheetNumber 1-based sheet number + * @return null if no builtin NameRecord matches + */ + public NameRecord getSpecificBuiltinRecord(byte name, int sheetNumber) + { + return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetNumber); + } + + /** + * Removes the specified Builtin NameRecord that matches the name and index + * @param name byte representation of the builtin to match + * @param sheetIndex zero-based sheet reference + */ + public void removeBuiltinRecord(byte name, int sheetIndex) { + linkTable.removeBuiltinRecord(name, sheetIndex); + // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}? + } + + public int getNumRecords() { + return records.size(); + } + + /** + * gets the font record at the given index in the font table. Remember + * "There is No Four" (someone at M$ must have gone to Rocky Horror one too + * many times) + * + * @param idx the index to look at (0 or greater but NOT 4) + * @return FontRecord located at the given index + */ + + public FontRecord getFontRecordAt(int idx) { + int index = idx; + + if (index > 4) { + index -= 1; // adjust for "There is no 4" + } + if (index > (numfonts - 1)) { + throw new ArrayIndexOutOfBoundsException( + "There are only " + numfonts + + " font records, you asked for " + idx); + } + FontRecord retval = + ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + index); + + return retval; + } + + /** + * Retrieves the index of the given font + */ + public int getFontIndex(FontRecord font) { + for(int i=0; i<=numfonts; i++) { + FontRecord thisFont = + ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i); + if(thisFont == font) { + // There is no 4! + if(i > 3) { + return (i+1); + } + return i; + } + } + throw new IllegalArgumentException("Could not find that font!"); + } + + /** + * creates a new font record and adds it to the "font table". This causes the + * boundsheets to move down one, extended formats to move down (so this function moves + * those pointers as well) + * + * @return FontRecord that was just created + */ + + public FontRecord createNewFont() { + FontRecord rec = createFont(); + + records.add(records.getFontpos()+1, rec); + records.setFontpos( records.getFontpos() + 1 ); + numfonts++; + return rec; + } + + /** + * Removes the given font record from the + * file's list. This will make all + * subsequent font indicies drop by one, + * so you'll need to update those yourself! + */ + public void removeFontRecord(FontRecord rec) { + records.remove(rec); // this updates FontPos for us + numfonts--; + } + + /** + * gets the number of font records + * + * @return number of font records in the "font table" + */ + + public int getNumberOfFontRecords() { + return numfonts; + } + + /** + * Sets the BOF for a given sheet + * + * @param sheetIndex the number of the sheet to set the positing of the bof for + * @param pos the actual bof position + */ + + public void setSheetBof(int sheetIndex, int pos) { + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "setting bof for sheetnum =", Integer.valueOf(sheetIndex), + " at pos=", Integer.valueOf(pos)); + checkSheets(sheetIndex); + getBoundSheetRec(sheetIndex) + .setPositionOfBof(pos); + } + + private BoundSheetRecord getBoundSheetRec(int sheetIndex) { + return boundsheets.get(sheetIndex); + } + + /** + * Returns the position of the backup record. + */ + + public BackupRecord getBackupRecord() { + return ( BackupRecord ) records.get(records.getBackuppos()); + } + + + /** + * sets the name for a given sheet. If the boundsheet record doesn't exist and + * its only one more than we have, go ahead and create it. If it's > 1 more than + * we have, except + * + * @param sheetnum the sheet number (0 based) + * @param sheetname the name for the sheet + */ + public void setSheetName(int sheetnum, String sheetname) { + checkSheets(sheetnum); + BoundSheetRecord sheet = boundsheets.get(sheetnum); + sheet.setSheetname(sheetname); + } + + /** + * Determines whether a workbook contains the provided sheet name. For the purpose of + * comparison, long names are truncated to 31 chars. + * + * @param name the name to test (case insensitive match) + * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check. + * @return true if the sheet contains the name, false otherwise. + */ + public boolean doesContainsSheetName(String name, int excludeSheetIdx) { + String aName = name; + if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) { + aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN); + } + for (int i = 0; i < boundsheets.size(); i++) { + BoundSheetRecord boundSheetRecord = getBoundSheetRec(i); + if (excludeSheetIdx == i) { + continue; + } + String bName = boundSheetRecord.getSheetname(); + if (bName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) { + bName = bName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN); + } + if (aName.equalsIgnoreCase(bName)) { + return true; + } + } + return false; + } + + /** + * sets the order of appearance for a given sheet. + * + * @param sheetname the name of the sheet to reorder + * @param pos the position that we want to insert the sheet into (0 based) + */ + + public void setSheetOrder(String sheetname, int pos ) { + int sheetNumber = getSheetIndex(sheetname); + //remove the sheet that needs to be reordered and place it in the spot we want + boundsheets.add(pos, boundsheets.remove(sheetNumber)); + } + + /** + * gets the name for a given sheet. + * + * @param sheetIndex the sheet number (0 based) + * @return sheetname the name for the sheet + */ + public String getSheetName(int sheetIndex) { + return getBoundSheetRec(sheetIndex).getSheetname(); + } + + /** + * Gets the hidden flag for a given sheet. + * Note that a sheet could instead be + * set to be very hidden, which is different + * ({@link #isSheetVeryHidden(int)}) + * + * @param sheetnum the sheet number (0 based) + * @return True if sheet is hidden + */ + public boolean isSheetHidden(int sheetnum) { + return getBoundSheetRec(sheetnum).isHidden(); + } + + /** + * Gets the very hidden flag for a given sheet. + * This is different from the normal + * hidden flag + * ({@link #isSheetHidden(int)}) + * + * @param sheetnum the sheet number (0 based) + * @return True if sheet is very hidden + */ + public boolean isSheetVeryHidden(int sheetnum) { + return getBoundSheetRec(sheetnum).isVeryHidden(); + } + + /** + * Hide or unhide a sheet + * + * @param sheetnum The sheet number + * @param hidden True to mark the sheet as hidden, false otherwise + */ + public void setSheetHidden(int sheetnum, boolean hidden) { + getBoundSheetRec(sheetnum).setHidden(hidden); + } + + /** + * Hide or unhide a sheet. + * 0 = not hidden + * 1 = hidden + * 2 = very hidden. + * + * @param sheetnum The sheet number + * @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden + */ + public void setSheetHidden(int sheetnum, int hidden) { + BoundSheetRecord bsr = getBoundSheetRec(sheetnum); + boolean h = false; + boolean vh = false; + if(hidden == 0) { + } else if(hidden == 1) { + h = true; + } else if(hidden == 2) { + vh = true; + } else { + throw new IllegalArgumentException("Invalid hidden flag " + hidden + " given, must be 0, 1 or 2"); + } + bsr.setHidden(h); + bsr.setVeryHidden(vh); + } + + + /** + * get the sheet's index + * @param name sheet name + * @return sheet index or -1 if it was not found. + */ + public int getSheetIndex(String name) { + int retval = -1; + + for (int k = 0; k < boundsheets.size(); k++) { + String sheet = getSheetName(k); + + if (sheet.equalsIgnoreCase(name)) { + retval = k; + break; + } + } + return retval; + } + + /** + * if we're trying to address one more sheet than we have, go ahead and add it! if we're + * trying to address >1 more than we have throw an exception! + */ + private void checkSheets(int sheetnum) { + if ((boundsheets.size()) <= sheetnum) { // if we're short one add another.. + if ((boundsheets.size() + 1) <= sheetnum) { + throw new RuntimeException("Sheet number out of bounds!"); + } + BoundSheetRecord bsr = createBoundSheet(sheetnum); + + records.add(records.getBspos()+1, bsr); + records.setBspos( records.getBspos() + 1 ); + boundsheets.add(bsr); + getOrCreateLinkTable().checkExternSheet(sheetnum); + fixTabIdRecord(); + } + } + + /** + * @param sheetIndex zero based sheet index + */ + public void removeSheet(int sheetIndex) { + if (boundsheets.size() > sheetIndex) { + records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetIndex); + boundsheets.remove(sheetIndex); + fixTabIdRecord(); + } + + // Within NameRecords, it's ok to have the formula + // part point at deleted sheets. It's also ok to + // have the ExternSheetNumber point at deleted + // sheets. + // However, the sheet index must be adjusted, or + // excel will break. (Sheet index is either 0 for + // global, or 1 based index to sheet) + int sheetNum1Based = sheetIndex + 1; + for(int i=0; i sheetNum1Based) { + // Bump down by one, so still points + // at the same sheet + nr.setSheetNumber(nr.getSheetNumber()-1); + } + } + } + + /** + * make the tabid record look like the current situation. + * + */ + private void fixTabIdRecord() { + TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos()); + short[] tia = new short[ boundsheets.size() ]; + + for (short k = 0; k < tia.length; k++) { + tia[ k ] = k; + } + tir.setTabIdArray(tia); + } + + /** + * returns the number of boundsheet objects contained in this workbook. + * + * @return number of BoundSheet records + */ + + public int getNumSheets() { + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "getNumSheets=", Integer.valueOf(boundsheets.size())); + return boundsheets.size(); + } + + /** + * get the number of ExtendedFormat records contained in this workbook. + * + * @return int count of ExtendedFormat records + */ + + public int getNumExFormats() { + if (log.check( POILogger.DEBUG )) + log.log(DEBUG, "getXF=", Integer.valueOf(numxfs)); + return numxfs; + } + + /** + * gets the ExtendedFormatRecord at the given 0-based index + * + * @param index of the Extended format record (0-based) + * @return ExtendedFormatRecord at the given index + */ + + public ExtendedFormatRecord getExFormatAt(int index) { + int xfptr = records.getXfpos() - (numxfs - 1); + + xfptr += index; + ExtendedFormatRecord retval = + ( ExtendedFormatRecord ) records.get(xfptr); + + return retval; + } + + /** + * Removes the given ExtendedFormatRecord record from the + * file's list. This will make all + * subsequent font indicies drop by one, + * so you'll need to update those yourself! + */ + public void removeExFormatRecord(ExtendedFormatRecord rec) { + records.remove(rec); // this updates XfPos for us + numxfs--; + } + + + /** + * creates a new Cell-type Extneded Format Record and adds it to the end of + * ExtendedFormatRecords collection + * + * @return ExtendedFormatRecord that was created + */ + + public ExtendedFormatRecord createCellXF() { + ExtendedFormatRecord xf = createExtendedFormat(); + + records.add(records.getXfpos()+1, xf); + records.setXfpos( records.getXfpos() + 1 ); + numxfs++; + return xf; + } + + /** + * Returns the StyleRecord for the given + * xfIndex, or null if that ExtendedFormat doesn't + * have a Style set. + */ + public StyleRecord getStyleRecord(int xfIndex) { + // Style records always follow after + // the ExtendedFormat records + for(int i=records.getXfpos(); i + * horizontal hold - 0x168

+ * vertical hold - 0x10e

+ * width - 0x3a5c

+ * height - 0x23be

+ * options - 0x38

+ * selected tab - 0

+ * displayed tab - 0

+ * num selected tab- 0

+ * tab width ratio - 0x258

+ */ + private static WindowOneRecord createWindowOne() { + WindowOneRecord retval = new WindowOneRecord(); + + retval.setHorizontalHold(( short ) 0x168); + retval.setVerticalHold(( short ) 0x10e); + retval.setWidth(( short ) 0x3a5c); + retval.setHeight(( short ) 0x23be); + retval.setOptions(( short ) 0x38); + retval.setActiveSheetIndex( 0x0); + retval.setFirstVisibleTab(0x0); + retval.setNumSelectedTabs(( short ) 1); + retval.setTabWidthRatio(( short ) 0x258); + return retval; + } + + /** + * creates the Backup record with backup set to 0. (loose the data, who cares) + */ + private static BackupRecord createBackup() { + BackupRecord retval = new BackupRecord(); + + retval.setBackup(( short ) 0); // by default DONT save backups of files...just loose data + return retval; + } + + /** + * creates the HideObj record with hide object set to 0. (don't hide) + */ + private static HideObjRecord createHideObj() { + HideObjRecord retval = new HideObjRecord(); + retval.setHideObj(( short ) 0); // by default set hide object off + return retval; + } + + /** + * creates the DateWindow1904 record with windowing set to 0. (don't window) + */ + private static DateWindow1904Record createDateWindow1904() { + DateWindow1904Record retval = new DateWindow1904Record(); + + retval.setWindowing(( short ) 0); // don't EVER use 1904 date windowing...tick tock.. + return retval; + } + + /** + * creates the Precision record with precision set to true. (full precision) + */ + private static PrecisionRecord createPrecision() { + PrecisionRecord retval = new PrecisionRecord(); + retval.setFullPrecision(true); // always use real numbers in calculations! + return retval; + } + + /** + * @return a new RefreshAll record with refreshAll set to false. (do not refresh all calcs) + */ + private static RefreshAllRecord createRefreshAll() { + return new RefreshAllRecord(false); + } + + /** + * creates the BookBool record with saveLinkValues set to 0. (don't save link values) + */ + private static BookBoolRecord createBookBool() { + BookBoolRecord retval = new BookBoolRecord(); + retval.setSaveLinkValues(( short ) 0); + return retval; + } + + /** + * creates a Font record with the following magic values:

+ * fontheight = 0xc8

+ * attributes = 0x0

+ * color palette index = 0x7fff

+ * bold weight = 0x190

+ * Font Name Length = 5

+ * Font Name = Arial

+ */ + private static FontRecord createFont() { + FontRecord retval = new FontRecord(); + + retval.setFontHeight(( short ) 0xc8); + retval.setAttributes(( short ) 0x0); + retval.setColorPaletteIndex(( short ) 0x7fff); + retval.setBoldWeight(( short ) 0x190); + retval.setFontName("Arial"); + return retval; + } + + /** + * Creates a FormatRecord object + * @param id the number of the format record to create (meaning its position in + * a file as M$ Excel would create it.) + */ + private static FormatRecord createFormat(int id) { + // we'll need multiple editions for + // the different formats + + switch (id) { + case 0: return new FormatRecord(5, "\"$\"#,##0_);\\(\"$\"#,##0\\)"); + case 1: return new FormatRecord(6, "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)"); + case 2: return new FormatRecord(7, "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)"); + case 3: return new FormatRecord(8, "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)"); + case 4: return new FormatRecord(0x2a, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"); + case 5: return new FormatRecord(0x29, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"); + case 6: return new FormatRecord(0x2c, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"); + case 7: return new FormatRecord(0x2b, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"); + } + throw new IllegalArgumentException("Unexpected id " + id); + } + + /** + * Creates an ExtendedFormatRecord object + * @param id the number of the extended format record to create (meaning its position in + * a file as MS Excel would create it.) + */ + private static ExtendedFormatRecord createExtendedFormat(int id) { // we'll need multiple editions + ExtendedFormatRecord retval = new ExtendedFormatRecord(); + + switch (id) { + + case 0 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 1 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 2 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 3 : + retval.setFontIndex(( short ) 2); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 4 : + retval.setFontIndex(( short ) 2); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 5 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 6 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 7 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 8 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 9 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 10 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 11 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 12 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 13 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 14 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff400); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + // cell records + case 15 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x0); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + // style + case 16 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0x2b); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 17 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0x29); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 18 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0x2c); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 19 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0x2a); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 20 : + retval.setFontIndex(( short ) 1); + retval.setFormatIndex(( short ) 0x9); + retval.setCellOptions(( short ) 0xfffffff5); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0xfffff800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + // unused from this point down + case 21 : + retval.setFontIndex(( short ) 5); + retval.setFormatIndex(( short ) 0x0); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x800); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 22 : + retval.setFontIndex(( short ) 6); + retval.setFormatIndex(( short ) 0x0); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x5c00); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 23 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0x31); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x5c00); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 24 : + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0x8); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x5c00); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + + case 25 : + retval.setFontIndex(( short ) 6); + retval.setFormatIndex(( short ) 0x8); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0x5c00); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + break; + } + return retval; + } + + /** + * creates an default cell type ExtendedFormatRecord object. + * @return ExtendedFormatRecord with intial defaults (cell-type) + */ + private static ExtendedFormatRecord createExtendedFormat() { + ExtendedFormatRecord retval = new ExtendedFormatRecord(); + + retval.setFontIndex(( short ) 0); + retval.setFormatIndex(( short ) 0x0); + retval.setCellOptions(( short ) 0x1); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) 0); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); + retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index); + retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index); + retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index); + retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index); + return retval; + } + + /** + * Creates a StyleRecord object + * @param id the number of the style record to create (meaning its position in + * a file as MS Excel would create it. + */ + private static StyleRecord createStyle(int id) { // we'll need multiple editions + StyleRecord retval = new StyleRecord(); + + switch (id) { + + case 0 : + retval.setXFIndex(0x010); + retval.setBuiltinStyle(3); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + + case 1 : + retval.setXFIndex(0x011); + retval.setBuiltinStyle(6); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + + case 2 : + retval.setXFIndex(0x012); + retval.setBuiltinStyle(4); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + + case 3 : + retval.setXFIndex(0x013); + retval.setBuiltinStyle(7); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + + case 4 : + retval.setXFIndex(0x000); + retval.setBuiltinStyle(0); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + + case 5 : + retval.setXFIndex(0x014); + retval.setBuiltinStyle(5); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + break; + } + return retval; + } + + /** + * Creates a palette record initialized to the default palette + */ + private static PaletteRecord createPalette() { + return new PaletteRecord(); + } + + /** + * @return a new UseSelFS object with the use natural language flag set to 0 (false) + */ + private static UseSelFSRecord createUseSelFS() { + return new UseSelFSRecord(false); + } + + /** + * create a "bound sheet" or "bundlesheet" (depending who you ask) record + * Always sets the sheet's bof to 0. You'll need to set that yourself. + * @param id either sheet 0,1 or 2. + * @return record containing a BoundSheetRecord + * @see org.apache.poi.hssf.record.BoundSheetRecord + * @see org.apache.poi.hssf.record.Record + */ + private static BoundSheetRecord createBoundSheet(int id) { + return new BoundSheetRecord("Sheet" + (id+1)); + } + + /** + * Creates the Country record with the default country set to 1 + * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise + */ + private static CountryRecord createCountry() { + CountryRecord retval = new CountryRecord(); + + retval.setDefaultCountry(( short ) 1); + + // from Russia with love ;) + if ( Locale.getDefault().toString().equals( "ru_RU" ) ) { + retval.setCurrentCountry(( short ) 7); + } + else { + retval.setCurrentCountry(( short ) 1); + } + + return retval; + } + + /** + * Creates the ExtendedSST record with numstrings per bucket set to 0x8. HSSF + * doesn't yet know what to do with this thing, but we create it with nothing in + * it hardly just to make Excel happy and our sheets look like Excel's + */ + private static ExtSSTRecord createExtendedSST() { + ExtSSTRecord retval = new ExtSSTRecord(); + retval.setNumStringsPerBucket(( short ) 0x8); + return retval; + } + + /** + * lazy initialization + * Note - creating the link table causes creation of 1 EXTERNALBOOK and 1 EXTERNALSHEET record + */ + private LinkTable getOrCreateLinkTable() { + if(linkTable == null) { + linkTable = new LinkTable((short) getNumSheets(), records); + } + return linkTable; + } + + /** finds the sheet name by his extern sheet index + * @param externSheetIndex extern sheet index + * @return sheet name. + */ + public String findSheetNameFromExternSheet(int externSheetIndex){ + + int indexToSheet = linkTable.getIndexToInternalSheet(externSheetIndex); + if (indexToSheet < 0) { + // TODO - what does '-1' mean here? + //error check, bail out gracefully! + return ""; + } + if (indexToSheet >= boundsheets.size()) { + // Not sure if this can ever happen (See bug 45798) + return ""; // Seems to be what excel would do in this case + } + return getSheetName(indexToSheet); + } + public ExternalSheet getExternalSheet(int externSheetIndex) { + String[] extNames = linkTable.getExternalBookAndSheetName(externSheetIndex); + if (extNames == null) { + return null; + } + return new ExternalSheet(extNames[0], extNames[1]); + } + + /** + * Finds the sheet index for a particular external sheet number. + * @param externSheetNumber The external sheet number to convert + * @return The index to the sheet found. + */ + public int getSheetIndexFromExternSheetIndex(int externSheetNumber) + { + return linkTable.getSheetIndexFromExternSheetIndex(externSheetNumber); + } + + /** returns the extern sheet number for specific sheet number , + * if this sheet doesn't exist in extern sheet , add it + * @param sheetNumber sheet number + * @return index to extern sheet + */ + public short checkExternSheet(int sheetNumber){ + return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber); + } + + public int getExternalSheetIndex(String workbookName, String sheetName) { + return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName); + } + + + /** gets the total number of names + * @return number of names + */ + public int getNumNames(){ + if(linkTable == null) { + return 0; + } + return linkTable.getNumNames(); + } + + /** gets the name record + * @param index name index + * @return name record + */ + public NameRecord getNameRecord(int index){ + return linkTable.getNameRecord(index); + } + + /** creates new name + * @return new name record + */ + public NameRecord createName(){ + return addName(new NameRecord()); + } + + + /** creates new name + * @return new name record + */ + public NameRecord addName(NameRecord name) + { + + LinkTable linkTable = getOrCreateLinkTable(); + if(linkTable.nameAlreadyExists(name)) { + throw new IllegalArgumentException( + "You are trying to assign a duplicated name record: " + + name.getNameText()); + } + linkTable.addName(name); + + return name; + } + + /** + * Generates a NameRecord to represent a built-in region + * @return a new NameRecord + */ + public NameRecord createBuiltInName(byte builtInName, int sheetNumber) { + if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) { + throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid "); + } + + NameRecord name = new NameRecord(builtInName, sheetNumber); + + while(linkTable.nameAlreadyExists(name)) { + throw new RuntimeException("Builtin (" + builtInName + + ") already exists for sheet (" + sheetNumber + ")"); + } + addName(name); + return name; + } + + + /** removes the name + * @param nameIndex name index + */ + public void removeName(int nameIndex){ + + if (linkTable.getNumNames() > nameIndex) { + int idx = findFirstRecordLocBySid(NameRecord.sid); + records.remove(idx + nameIndex); + linkTable.removeName(nameIndex); + } + } + + /** + * Returns a format index that matches the passed in format. It does not tie into HSSFDataFormat. + * @param format the format string + * @param createIfNotFound creates a new format if format not found + * @return the format id of a format that matches or -1 if none found and createIfNotFound + */ + public short getFormat(String format, boolean createIfNotFound) { + Iterator iterator; + for (iterator = formats.iterator(); iterator.hasNext();) { + FormatRecord r = (FormatRecord)iterator.next(); + if (r.getFormatString().equals(format)) { + return (short)r.getIndexCode(); + } + } + + if (createIfNotFound) { + return (short)createFormat(format); + } + + return -1; + } + + /** + * Returns the list of FormatRecords in the workbook. + * @return ArrayList of FormatRecords in the notebook + */ + public List getFormats() { + return formats; + } + + /** + * Creates a FormatRecord, inserts it, and returns the index code. + * @param formatString the format string + * @return the index code of the format record. + * @see org.apache.poi.hssf.record.FormatRecord + * @see org.apache.poi.hssf.record.Record + */ + public int createFormat(String formatString) { + + maxformatid = maxformatid >= 0xa4 ? maxformatid + 1 : 0xa4; //Starting value from M$ empircal study. + FormatRecord rec = new FormatRecord(maxformatid, formatString); + + int pos = 0; + while ( pos < records.size() && records.get( pos ).getSid() != FormatRecord.sid ) + pos++; + pos += formats.size(); + formats.add( rec ); + records.add( pos, rec ); + return maxformatid; + } + + + + /** + * 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; + } + + /** + * Returns the index of a record matching a particular sid. + * @param sid The sid of the record to match + * @return The index of -1 if no match 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 next occurance of a record matching a particular sid. + */ + public Record findNextRecordBySid(short sid, int pos) { + int matches = 0; + for (Iterator iterator = records.iterator(); iterator.hasNext(); ) { + Record record = ( Record ) iterator.next(); + + if (record.getSid() == sid) { + if (matches++ == pos) + return record; + } + } + return null; + } + + public List getHyperlinks() + { + return hyperlinks; + } + + public List getRecords() { + return records.getRecords(); + } + + /** + * Whether date windowing is based on 1/2/1904 or 1/1/1900. + * Some versions of Excel (Mac) can save workbooks using 1904 date windowing. + * + * @return true if using 1904 date windowing + */ + public boolean isUsing1904DateWindowing() { + return uses1904datewindowing; + } + + /** + * Returns the custom palette in use for this workbook; if a custom palette record + * does not exist, then it is created. + */ + public PaletteRecord getCustomPalette() + { + PaletteRecord palette; + int palettePos = records.getPalettepos(); + if (palettePos != -1) { + Record rec = records.get(palettePos); + if (rec instanceof PaletteRecord) { + palette = (PaletteRecord) rec; + } else throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'"); + } + else + { + palette = createPalette(); + //Add the palette record after the bof which is always the first record + records.add(1, palette); + records.setPalettepos(1); + } + return palette; + } + + /** + * Finds the primary drawing group, if one already exists + */ + public void findDrawingGroup() { + // Need to find a DrawingGroupRecord that + // contains a EscherDggRecord + for(Iterator rit = records.iterator(); rit.hasNext();) { + Record r = rit.next(); + + if(r instanceof DrawingGroupRecord) { + DrawingGroupRecord dg = (DrawingGroupRecord)r; + dg.processChildRecords(); + + EscherContainerRecord cr = + dg.getEscherContainer(); + if(cr == null) { + continue; + } + + EscherDggRecord dgg = null; + for(Iterator it = cr.getChildIterator(); it.hasNext();) { + Object er = it.next(); + if(er instanceof EscherDggRecord) { + dgg = (EscherDggRecord)er; + } + } + + if(dgg != null) { + drawingManager = new DrawingManager2(dgg); + return; + } + } + } + + // Look for the DrawingGroup record + int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); + + // If there is one, does it have a EscherDggRecord? + if(dgLoc != -1) { + DrawingGroupRecord dg = (DrawingGroupRecord)records.get(dgLoc); + EscherDggRecord dgg = null; + for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) { + Object er = it.next(); + if(er instanceof EscherDggRecord) { + dgg = (EscherDggRecord)er; + } + } + + if(dgg != null) { + drawingManager = new DrawingManager2(dgg); + } + } + } + + /** + * Creates a primary drawing group record. If it already + * exists then it's modified. + */ + public void createDrawingGroup() { + if (drawingManager == null) { + EscherContainerRecord dggContainer = new EscherContainerRecord(); + EscherDggRecord dgg = new EscherDggRecord(); + EscherOptRecord opt = new EscherOptRecord(); + EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord(); + + dggContainer.setRecordId((short) 0xF000); + dggContainer.setOptions((short) 0x000F); + dgg.setRecordId(EscherDggRecord.RECORD_ID); + dgg.setOptions((short)0x0000); + dgg.setShapeIdMax(1024); + dgg.setNumShapesSaved(0); + dgg.setDrawingsSaved(0); + dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} ); + drawingManager = new DrawingManager2(dgg); + EscherContainerRecord bstoreContainer = null; + if (escherBSERecords.size() > 0) + { + bstoreContainer = new EscherContainerRecord(); + bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); + bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) ); + for ( Iterator iterator = escherBSERecords.iterator(); iterator.hasNext(); ) + { + EscherRecord escherRecord = (EscherRecord) iterator.next(); + bstoreContainer.addChildRecord( escherRecord ); + } + } + opt.setRecordId((short) 0xF00B); + opt.setOptions((short) 0x0033); + opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) ); + opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 0x08000041) ); + opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) ); + splitMenuColors.setRecordId((short) 0xF11E); + splitMenuColors.setOptions((short) 0x0040); + splitMenuColors.setColor1(0x0800000D); + splitMenuColors.setColor2(0x0800000C); + splitMenuColors.setColor3(0x08000017); + splitMenuColors.setColor4(0x100000F7); + + dggContainer.addChildRecord(dgg); + if (bstoreContainer != null) + dggContainer.addChildRecord( bstoreContainer ); + dggContainer.addChildRecord(opt); + dggContainer.addChildRecord(splitMenuColors); + + int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); + if (dgLoc == -1) { + DrawingGroupRecord drawingGroup = new DrawingGroupRecord(); + drawingGroup.addEscherRecord(dggContainer); + int loc = findFirstRecordLocBySid(CountryRecord.sid); + + getRecords().add(loc+1, drawingGroup); + } else { + DrawingGroupRecord drawingGroup = new DrawingGroupRecord(); + drawingGroup.addEscherRecord(dggContainer); + getRecords().set(dgLoc, drawingGroup); + } + + } + } + + public WindowOneRecord getWindowOne() { + return windowOne; + } + + public EscherBSERecord getBSERecord(int pictureIndex) { + return escherBSERecords.get(pictureIndex-1); + } + + public int addBSERecord(EscherBSERecord e) { + createDrawingGroup(); + + // maybe we don't need that as an instance variable anymore + escherBSERecords.add( e ); + + int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); + DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords().get( dgLoc ); + + EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup.getEscherRecord( 0 ); + EscherContainerRecord bstoreContainer; + if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER ) + { + bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 ); + } + else + { + bstoreContainer = new EscherContainerRecord(); + bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); + List childRecords = dggContainer.getChildRecords(); + childRecords.add(1, bstoreContainer); + dggContainer.setChildRecords(childRecords); + } + bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) ); + + bstoreContainer.addChildRecord( e ); + + return escherBSERecords.size(); + } + + public DrawingManager2 getDrawingManager() + { + return drawingManager; + } + + public WriteProtectRecord getWriteProtect() { + if (writeProtect == null) { + writeProtect = new WriteProtectRecord(); + int i = 0; + for (i = 0; + i < records.size() && !(records.get(i) instanceof BOFRecord); + i++) { + } + records.add(i+1, writeProtect); + } + return this.writeProtect; + } + + public WriteAccessRecord getWriteAccess() { + if (writeAccess == null) { + writeAccess = createWriteAccess(); + int i = 0; + for (i = 0; + i < records.size() && !(records.get(i) instanceof InterfaceEndRecord); + i++) { + } + records.add(i+1, writeAccess); + } + return writeAccess; + } + + public FileSharingRecord getFileSharing() { + if (fileShare == null) { + fileShare = new FileSharingRecord(); + int i = 0; + for (i = 0; + i < records.size() && !(records.get(i) instanceof WriteAccessRecord); + i++) { + } + records.add(i+1, fileShare); + } + return fileShare; + } + + /** + * is the workbook protected with a password (not encrypted)? + */ + public boolean isWriteProtected() { + if (fileShare == null) { + return false; + } + FileSharingRecord frec = getFileSharing(); + return frec.getReadOnly() == 1; + } + + /** + * protect a workbook with a password (not encypted, just sets writeprotect + * flags and the password. + * @param password to set + */ + public void writeProtectWorkbook( String password, String username ) { + int protIdx = -1; + FileSharingRecord frec = getFileSharing(); + WriteAccessRecord waccess = getWriteAccess(); + WriteProtectRecord wprotect = getWriteProtect(); + frec.setReadOnly((short)1); + frec.setPassword(FileSharingRecord.hashPassword(password)); + frec.setUsername(username); + waccess.setUsername(username); + } + + /** + * removes the write protect flag + */ + public void unwriteProtectWorkbook() { + records.remove(fileShare); + records.remove(writeProtect); + fileShare = null; + writeProtect = null; + } + + /** + * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table + * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record + * @return the string representation of the defined or external name + */ + public String resolveNameXText(int refIndex, int definedNameIndex) { + return linkTable.resolveNameXText(refIndex, definedNameIndex); + } + + public NameXPtg getNameXPtg(String name) { + return getOrCreateLinkTable().getNameXPtg(name); + } + + /** + * Check if the cloned sheet has drawings. If yes, then allocate a new drawing group ID and + * re-generate shape IDs + * + * @param sheet the cloned sheet + */ + public void cloneDrawings(Sheet sheet){ + + findDrawingGroup(); + + if(drawingManager == null) { + //this workbook does not have drawings + return; + } + + //check if the cloned sheet has drawings + int aggLoc = sheet.aggregateDrawingRecords(drawingManager, false); + if(aggLoc != -1) { + EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid); + EscherContainerRecord escherContainer = agg.getEscherContainer(); + if (escherContainer == null) { + return; + } + + EscherDggRecord dgg = drawingManager.getDgg(); + + //register a new drawing group for the cloned sheet + int dgId = drawingManager.findNewDrawingGroupId(); + dgg.addCluster( dgId, 0 ); + dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); + + EscherDgRecord dg = null; + for(Iterator it = escherContainer.getChildIterator(); it.hasNext();) { + EscherRecord er = it.next(); + if(er instanceof EscherDgRecord) { + dg = (EscherDgRecord)er; + //update id of the drawing in the cloned sheet + dg.setOptions( (short) ( dgId << 4 ) ); + } else if (er instanceof EscherContainerRecord){ + //recursively find shape records and re-generate shapeId + List spRecords = new ArrayList(); + EscherContainerRecord cp = (EscherContainerRecord)er; + cp.getRecordsById(EscherSpRecord.RECORD_ID, spRecords); + for(Iterator spIt = spRecords.iterator(); spIt.hasNext();) { + EscherSpRecord sp = (EscherSpRecord)spIt.next(); + int shapeId = drawingManager.allocateShapeId((short)dgId, dg); + //allocateShapeId increments the number of shapes. roll back to the previous value + dg.setNumShapes(dg.getNumShapes()-1); + sp.setShapeId(shapeId); + } + } + } + + } + } + + /** + * Updates named ranges due to moving of cells + */ + public void updateNamesAfterCellShift(FormulaShifter shifter) { + for (int i = 0 ; i < getNumNames() ; ++i){ + NameRecord nr = getNameRecord(i); + Ptg[] ptgs = nr.getNameDefinition(); + if (shifter.adjustFormula(ptgs, nr.getSheetNumber())) { + nr.setNameDefinition(ptgs); + } + } + } + +} diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 9bb93a603e..90a9a109ed 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -91,7 +91,7 @@ import org.apache.poi.util.POILogger; * @author Brian Sanders (kestrel at burdell dot org) Active Cell support * @author Jean-Pierre Paris (jean-pierre.paris at m4x dot org) (Just a little) * - * @see org.apache.poi.hssf.model.Workbook + * @see org.apache.poi.hssf.model.InternalWorkbook * @see org.apache.poi.hssf.usermodel.HSSFSheet */ public final class Sheet { @@ -151,7 +151,7 @@ public final class Sheet { * * @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.model.InternalWorkbook * @see org.apache.poi.hssf.record.Record */ public static Sheet createSheet(RecordStream rs) { diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java deleted file mode 100644 index eba4d100d1..0000000000 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ /dev/null @@ -1,2338 +0,0 @@ -/* ==================================================================== - 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.security.AccessControlException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; - -import org.apache.poi.ddf.EscherBSERecord; -import org.apache.poi.ddf.EscherBoolProperty; -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherDgRecord; -import org.apache.poi.ddf.EscherDggRecord; -import org.apache.poi.ddf.EscherOptRecord; -import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.ddf.EscherRGBProperty; -import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.ddf.EscherSpRecord; -import org.apache.poi.ddf.EscherSplitMenuColorsRecord; -import org.apache.poi.hssf.record.BOFRecord; -import org.apache.poi.hssf.record.BackupRecord; -import org.apache.poi.hssf.record.BookBoolRecord; -import org.apache.poi.hssf.record.BoundSheetRecord; -import org.apache.poi.hssf.record.CodepageRecord; -import org.apache.poi.hssf.record.CountryRecord; -import org.apache.poi.hssf.record.DSFRecord; -import org.apache.poi.hssf.record.DateWindow1904Record; -import org.apache.poi.hssf.record.DrawingGroupRecord; -import org.apache.poi.hssf.record.EOFRecord; -import org.apache.poi.hssf.record.EscherAggregate; -import org.apache.poi.hssf.record.ExtSSTRecord; -import org.apache.poi.hssf.record.ExtendedFormatRecord; -import org.apache.poi.hssf.record.ExternSheetRecord; -import org.apache.poi.hssf.record.FileSharingRecord; -import org.apache.poi.hssf.record.FnGroupCountRecord; -import org.apache.poi.hssf.record.FontRecord; -import org.apache.poi.hssf.record.FormatRecord; -import org.apache.poi.hssf.record.HideObjRecord; -import org.apache.poi.hssf.record.HyperlinkRecord; -import org.apache.poi.hssf.record.InterfaceEndRecord; -import org.apache.poi.hssf.record.InterfaceHdrRecord; -import org.apache.poi.hssf.record.MMSRecord; -import org.apache.poi.hssf.record.NameRecord; -import org.apache.poi.hssf.record.PaletteRecord; -import org.apache.poi.hssf.record.PasswordRecord; -import org.apache.poi.hssf.record.PasswordRev4Record; -import org.apache.poi.hssf.record.PrecisionRecord; -import org.apache.poi.hssf.record.ProtectRecord; -import org.apache.poi.hssf.record.ProtectionRev4Record; -import org.apache.poi.hssf.record.RecalcIdRecord; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.RefreshAllRecord; -import org.apache.poi.hssf.record.SSTRecord; -import org.apache.poi.hssf.record.StyleRecord; -import org.apache.poi.hssf.record.SupBookRecord; -import org.apache.poi.hssf.record.TabIdRecord; -import org.apache.poi.hssf.record.UnicodeString; -import org.apache.poi.hssf.record.UseSelFSRecord; -import org.apache.poi.hssf.record.WindowOneRecord; -import org.apache.poi.hssf.record.WindowProtectRecord; -import org.apache.poi.hssf.record.WriteAccessRecord; -import org.apache.poi.hssf.record.WriteProtectRecord; -import org.apache.poi.hssf.record.formula.NameXPtg; -import org.apache.poi.hssf.record.formula.FormulaShifter; -import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.util.HSSFColor; -import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * Low level model implementation of a Workbook. Provides creational methods - * for settings and objects contained in the workbook object. - *

- * This file contains the low level binary records starting at the workbook's BOF and - * ending with the workbook's EOF. Use HSSFWorkbook 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 Luc Girardin (luc dot girardin at macrofocus dot com) - * @author Sergei Kozello (sergeikozello at mail.ru) - * @author Shawn Laubach (slaubach at apache dot org) (Data Formats) - * @author Andrew C. Oliver (acoliver at apache dot org) - * @author Brian Sanders (bsanders at risklabs dot com) - custom palette - * @author Dan Sherman (dsherman at isisph.com) - * @author Glen Stampoultzis (glens at apache.org) - * @see org.apache.poi.hssf.usermodel.HSSFWorkbook - */ -public final class Workbook { - /** - * Excel silently truncates long sheet names to 31 chars. - * This constant is used to ensure uniqueness in the first 31 chars - */ - private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31; - - - private static final POILogger log = POILogFactory.getLogger(Workbook.class); - private static final int DEBUG = POILogger.DEBUG; - - /** - * constant used to set the "codepage" wherever "codepage" is set in records - * (which is duplicated in more than one record) - */ - private final static short CODEPAGE = 0x04B0; - - /** - * this contains the Worksheet record objects - */ - private final WorkbookRecordList records; - - /** - * this contains a reference to the SSTRecord so that new stings can be added - * to it. - */ - protected SSTRecord sst; - - - private LinkTable linkTable; // optionally occurs if there are references in the document. (4.10.3) - - /** - * holds the "boundsheet" records (aka bundlesheet) so that they can have their - * reference to their "BOF" marker - */ - private final List boundsheets; - private final List formats; - private final List hyperlinks; - - /** the number of extended format records */ - private int numxfs; - /** the number of font records */ - private int numfonts; - /** holds the max format id */ - private int maxformatid; - /** whether 1904 date windowing is being used */ - private boolean uses1904datewindowing; - private DrawingManager2 drawingManager; - private List escherBSERecords; - private WindowOneRecord windowOne; - private FileSharingRecord fileShare; - private WriteAccessRecord writeAccess; - private WriteProtectRecord writeProtect; - - private Workbook() { - records = new WorkbookRecordList(); - - boundsheets = new ArrayList(); - formats = new ArrayList(); - hyperlinks = new ArrayList(); - numxfs = 0; - numfonts = 0; - maxformatid = -1; - uses1904datewindowing = false; - escherBSERecords = new ArrayList(); - } - - /** - * read support for low level - * API. Pass in an array of Record objects, A Workbook - * object is constructed and passed back with all of its initialization set - * to the passed in records and references to those records held. Unlike Sheet - * workbook does not use an offset (its assumed to be 0) since its first in a file. - * If you need an offset then construct a new array with a 0 offset or write your - * own ;-p. - * - * @param recs an array of Record objects - * @return Workbook object - */ - public static Workbook createWorkbook(List recs) { - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "Workbook (readfile) created with reclen=", - Integer.valueOf(recs.size())); - Workbook retval = new Workbook(); - List records = new ArrayList(recs.size() / 3); - retval.records.setRecords(records); - - int k; - for (k = 0; k < recs.size(); k++) { - Record rec = recs.get(k); - - if (rec.getSid() == EOFRecord.sid) { - records.add(rec); - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found workbook eof record at " + k); - break; - } - switch (rec.getSid()) { - - case BoundSheetRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found boundsheet record at " + k); - retval.boundsheets.add((BoundSheetRecord) rec); - retval.records.setBspos( k ); - break; - - case SSTRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found sst record at " + k); - retval.sst = ( SSTRecord ) rec; - break; - - case FontRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found font record at " + k); - retval.records.setFontpos( k ); - retval.numfonts++; - break; - - case ExtendedFormatRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found XF record at " + k); - retval.records.setXfpos( k ); - retval.numxfs++; - break; - - case TabIdRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found tabid record at " + k); - retval.records.setTabpos( k ); - break; - - case ProtectRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found protect record at " + k); - retval.records.setProtpos( k ); - break; - - case BackupRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found backup record at " + k); - retval.records.setBackuppos( k ); - break; - case ExternSheetRecord.sid : - throw new RuntimeException("Extern sheet is part of LinkTable"); - case NameRecord.sid : - case SupBookRecord.sid : - // LinkTable can start with either of these - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found SupBook record at " + k); - retval.linkTable = new LinkTable(recs, k, retval.records); - k+=retval.linkTable.getRecordCount() - 1; - continue; - case FormatRecord.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found format record at " + k); - retval.formats.add((FormatRecord) rec); - retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); - break; - case DateWindow1904Record.sid : - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found datewindow1904 record at " + k); - retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1; - break; - case PaletteRecord.sid: - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found palette record at " + k); - retval.records.setPalettepos( k ); - break; - case WindowOneRecord.sid: - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found WindowOneRecord at " + k); - retval.windowOne = (WindowOneRecord) rec; - break; - case WriteAccessRecord.sid: - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found WriteAccess at " + k); - retval.writeAccess = (WriteAccessRecord) rec; - break; - case WriteProtectRecord.sid: - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found WriteProtect at " + k); - retval.writeProtect = (WriteProtectRecord) rec; - break; - case FileSharingRecord.sid: - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "found FileSharing at " + k); - retval.fileShare = (FileSharingRecord) rec; - default : - } - records.add(rec); - } - //What if we dont have any ranges and supbooks - // if (retval.records.supbookpos == 0) { - // retval.records.supbookpos = retval.records.bspos + 1; - // retval.records.namepos = retval.records.supbookpos + 1; - // } - - // Look for other interesting values that - // follow the EOFRecord - for ( ; k < recs.size(); k++) { - Record rec = recs.get(k); - switch (rec.getSid()) { - case HyperlinkRecord.sid: - retval.hyperlinks.add((HyperlinkRecord)rec); - break; - } - } - - if (retval.windowOne == null) { - retval.windowOne = createWindowOne(); - } - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "exit create workbook from existing file function"); - return retval; - } - - /** - * Creates an empty workbook object with three blank sheets and all the empty - * fields. Use this to create a workbook from scratch. - */ - public static Workbook createWorkbook() - { - if (log.check( POILogger.DEBUG )) - log.log( DEBUG, "creating new workbook from scratch" ); - Workbook retval = new Workbook(); - List records = new ArrayList( 30 ); - retval.records.setRecords(records); - List formats = retval.formats; - - records.add(retval.createBOF()); - records.add(retval.createInterfaceHdr()); - records.add(retval.createMMS()); - records.add(retval.createInterfaceEnd()); - records.add(retval.createWriteAccess()); - records.add(retval.createCodepage()); - records.add(retval.createDSF()); - records.add(retval.createTabId()); - retval.records.setTabpos(records.size() - 1); - records.add(retval.createFnGroupCount()); - records.add(createWindowProtect()); - records.add(createProtect()); - retval.records.setProtpos(records.size() - 1); - records.add(createPassword()); - records.add(createProtectionRev4()); - records.add(retval.createPasswordRev4()); - retval.windowOne = createWindowOne(); - records.add(retval.windowOne); - records.add(retval.createBackup()); - retval.records.setBackuppos(records.size() - 1); - records.add(retval.createHideObj()); - records.add(retval.createDateWindow1904()); - records.add(retval.createPrecision()); - records.add(createRefreshAll()); - records.add(retval.createBookBool()); - records.add(retval.createFont()); - records.add(retval.createFont()); - records.add(retval.createFont()); - records.add(retval.createFont()); - retval.records.setFontpos( records.size() - 1 ); // last font record position - retval.numfonts = 4; - - // set up format records - for (int i = 0; i <= 7; i++) { - FormatRecord rec = createFormat(i); - retval.maxformatid = retval.maxformatid >= rec.getIndexCode() ? retval.maxformatid : rec.getIndexCode(); - formats.add(rec); - records.add(rec); - } - - for (int k = 0; k < 21; k++) { - records.add(retval.createExtendedFormat(k)); - retval.numxfs++; - } - retval.records.setXfpos( records.size() - 1 ); - for (int k = 0; k < 6; k++) { - records.add(retval.createStyle(k)); - } - records.add(retval.createUseSelFS()); - - int nBoundSheets = 1; // now just do 1 - for (int k = 0; k < nBoundSheets; k++) { - BoundSheetRecord bsr = createBoundSheet(k); - - records.add(bsr); - retval.boundsheets.add(bsr); - retval.records.setBspos(records.size() - 1); - } - records.add( retval.createCountry() ); - for ( int k = 0; k < nBoundSheets; k++ ) { - retval.getOrCreateLinkTable().checkExternSheet(k); - } - retval.sst = new SSTRecord(); - records.add(retval.sst); - records.add(retval.createExtendedSST()); - - records.add(EOFRecord.instance); - if (log.check( POILogger.DEBUG )) - log.log( DEBUG, "exit create new workbook from scratch" ); - return retval; - } - - - /**Retrieves the Builtin NameRecord that matches the name and index - * There shouldn't be too many names to make the sequential search too slow - * @param name byte representation of the builtin name to match - * @param sheetNumber 1-based sheet number - * @return null if no builtin NameRecord matches - */ - public NameRecord getSpecificBuiltinRecord(byte name, int sheetNumber) - { - return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetNumber); - } - - /** - * Removes the specified Builtin NameRecord that matches the name and index - * @param name byte representation of the builtin to match - * @param sheetIndex zero-based sheet reference - */ - public void removeBuiltinRecord(byte name, int sheetIndex) { - linkTable.removeBuiltinRecord(name, sheetIndex); - // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}? - } - - public int getNumRecords() { - return records.size(); - } - - /** - * gets the font record at the given index in the font table. Remember - * "There is No Four" (someone at M$ must have gone to Rocky Horror one too - * many times) - * - * @param idx the index to look at (0 or greater but NOT 4) - * @return FontRecord located at the given index - */ - - public FontRecord getFontRecordAt(int idx) { - int index = idx; - - if (index > 4) { - index -= 1; // adjust for "There is no 4" - } - if (index > (numfonts - 1)) { - throw new ArrayIndexOutOfBoundsException( - "There are only " + numfonts - + " font records, you asked for " + idx); - } - FontRecord retval = - ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + index); - - return retval; - } - - /** - * Retrieves the index of the given font - */ - public int getFontIndex(FontRecord font) { - for(int i=0; i<=numfonts; i++) { - FontRecord thisFont = - ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i); - if(thisFont == font) { - // There is no 4! - if(i > 3) { - return (i+1); - } - return i; - } - } - throw new IllegalArgumentException("Could not find that font!"); - } - - /** - * creates a new font record and adds it to the "font table". This causes the - * boundsheets to move down one, extended formats to move down (so this function moves - * those pointers as well) - * - * @return FontRecord that was just created - */ - - public FontRecord createNewFont() { - FontRecord rec = createFont(); - - records.add(records.getFontpos()+1, rec); - records.setFontpos( records.getFontpos() + 1 ); - numfonts++; - return rec; - } - - /** - * Removes the given font record from the - * file's list. This will make all - * subsequent font indicies drop by one, - * so you'll need to update those yourself! - */ - public void removeFontRecord(FontRecord rec) { - records.remove(rec); // this updates FontPos for us - numfonts--; - } - - /** - * gets the number of font records - * - * @return number of font records in the "font table" - */ - - public int getNumberOfFontRecords() { - return numfonts; - } - - /** - * Sets the BOF for a given sheet - * - * @param sheetIndex the number of the sheet to set the positing of the bof for - * @param pos the actual bof position - */ - - public void setSheetBof(int sheetIndex, int pos) { - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "setting bof for sheetnum =", Integer.valueOf(sheetIndex), - " at pos=", Integer.valueOf(pos)); - checkSheets(sheetIndex); - getBoundSheetRec(sheetIndex) - .setPositionOfBof(pos); - } - - private BoundSheetRecord getBoundSheetRec(int sheetIndex) { - return boundsheets.get(sheetIndex); - } - - /** - * Returns the position of the backup record. - */ - - public BackupRecord getBackupRecord() { - return ( BackupRecord ) records.get(records.getBackuppos()); - } - - - /** - * sets the name for a given sheet. If the boundsheet record doesn't exist and - * its only one more than we have, go ahead and create it. If it's > 1 more than - * we have, except - * - * @param sheetnum the sheet number (0 based) - * @param sheetname the name for the sheet - */ - public void setSheetName(int sheetnum, String sheetname) { - checkSheets(sheetnum); - BoundSheetRecord sheet = boundsheets.get(sheetnum); - sheet.setSheetname(sheetname); - } - - /** - * Determines whether a workbook contains the provided sheet name. For the purpose of - * comparison, long names are truncated to 31 chars. - * - * @param name the name to test (case insensitive match) - * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check. - * @return true if the sheet contains the name, false otherwise. - */ - public boolean doesContainsSheetName(String name, int excludeSheetIdx) { - String aName = name; - if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) { - aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN); - } - for (int i = 0; i < boundsheets.size(); i++) { - BoundSheetRecord boundSheetRecord = getBoundSheetRec(i); - if (excludeSheetIdx == i) { - continue; - } - String bName = boundSheetRecord.getSheetname(); - if (bName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) { - bName = bName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN); - } - if (aName.equalsIgnoreCase(bName)) { - return true; - } - } - return false; - } - - /** - * sets the order of appearance for a given sheet. - * - * @param sheetname the name of the sheet to reorder - * @param pos the position that we want to insert the sheet into (0 based) - */ - - public void setSheetOrder(String sheetname, int pos ) { - int sheetNumber = getSheetIndex(sheetname); - //remove the sheet that needs to be reordered and place it in the spot we want - boundsheets.add(pos, boundsheets.remove(sheetNumber)); - } - - /** - * gets the name for a given sheet. - * - * @param sheetIndex the sheet number (0 based) - * @return sheetname the name for the sheet - */ - public String getSheetName(int sheetIndex) { - return getBoundSheetRec(sheetIndex).getSheetname(); - } - - /** - * Gets the hidden flag for a given sheet. - * Note that a sheet could instead be - * set to be very hidden, which is different - * ({@link #isSheetVeryHidden(int)}) - * - * @param sheetnum the sheet number (0 based) - * @return True if sheet is hidden - */ - public boolean isSheetHidden(int sheetnum) { - return getBoundSheetRec(sheetnum).isHidden(); - } - - /** - * Gets the very hidden flag for a given sheet. - * This is different from the normal - * hidden flag - * ({@link #isSheetHidden(int)}) - * - * @param sheetnum the sheet number (0 based) - * @return True if sheet is very hidden - */ - public boolean isSheetVeryHidden(int sheetnum) { - return getBoundSheetRec(sheetnum).isVeryHidden(); - } - - /** - * Hide or unhide a sheet - * - * @param sheetnum The sheet number - * @param hidden True to mark the sheet as hidden, false otherwise - */ - public void setSheetHidden(int sheetnum, boolean hidden) { - getBoundSheetRec(sheetnum).setHidden(hidden); - } - - /** - * Hide or unhide a sheet. - * 0 = not hidden - * 1 = hidden - * 2 = very hidden. - * - * @param sheetnum The sheet number - * @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden - */ - public void setSheetHidden(int sheetnum, int hidden) { - BoundSheetRecord bsr = getBoundSheetRec(sheetnum); - boolean h = false; - boolean vh = false; - if(hidden == 0) { - } else if(hidden == 1) { - h = true; - } else if(hidden == 2) { - vh = true; - } else { - throw new IllegalArgumentException("Invalid hidden flag " + hidden + " given, must be 0, 1 or 2"); - } - bsr.setHidden(h); - bsr.setVeryHidden(vh); - } - - - /** - * get the sheet's index - * @param name sheet name - * @return sheet index or -1 if it was not found. - */ - public int getSheetIndex(String name) { - int retval = -1; - - for (int k = 0; k < boundsheets.size(); k++) { - String sheet = getSheetName(k); - - if (sheet.equalsIgnoreCase(name)) { - retval = k; - break; - } - } - return retval; - } - - /** - * if we're trying to address one more sheet than we have, go ahead and add it! if we're - * trying to address >1 more than we have throw an exception! - */ - private void checkSheets(int sheetnum) { - if ((boundsheets.size()) <= sheetnum) { // if we're short one add another.. - if ((boundsheets.size() + 1) <= sheetnum) { - throw new RuntimeException("Sheet number out of bounds!"); - } - BoundSheetRecord bsr = createBoundSheet(sheetnum); - - records.add(records.getBspos()+1, bsr); - records.setBspos( records.getBspos() + 1 ); - boundsheets.add(bsr); - getOrCreateLinkTable().checkExternSheet(sheetnum); - fixTabIdRecord(); - } - } - - /** - * @param sheetIndex zero based sheet index - */ - public void removeSheet(int sheetIndex) { - if (boundsheets.size() > sheetIndex) { - records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetIndex); - boundsheets.remove(sheetIndex); - fixTabIdRecord(); - } - - // Within NameRecords, it's ok to have the formula - // part point at deleted sheets. It's also ok to - // have the ExternSheetNumber point at deleted - // sheets. - // However, the sheet index must be adjusted, or - // excel will break. (Sheet index is either 0 for - // global, or 1 based index to sheet) - int sheetNum1Based = sheetIndex + 1; - for(int i=0; i sheetNum1Based) { - // Bump down by one, so still points - // at the same sheet - nr.setSheetNumber(nr.getSheetNumber()-1); - } - } - } - - /** - * make the tabid record look like the current situation. - * - */ - private void fixTabIdRecord() { - TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos()); - short[] tia = new short[ boundsheets.size() ]; - - for (short k = 0; k < tia.length; k++) { - tia[ k ] = k; - } - tir.setTabIdArray(tia); - } - - /** - * returns the number of boundsheet objects contained in this workbook. - * - * @return number of BoundSheet records - */ - - public int getNumSheets() { - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "getNumSheets=", Integer.valueOf(boundsheets.size())); - return boundsheets.size(); - } - - /** - * get the number of ExtendedFormat records contained in this workbook. - * - * @return int count of ExtendedFormat records - */ - - public int getNumExFormats() { - if (log.check( POILogger.DEBUG )) - log.log(DEBUG, "getXF=", Integer.valueOf(numxfs)); - return numxfs; - } - - /** - * gets the ExtendedFormatRecord at the given 0-based index - * - * @param index of the Extended format record (0-based) - * @return ExtendedFormatRecord at the given index - */ - - public ExtendedFormatRecord getExFormatAt(int index) { - int xfptr = records.getXfpos() - (numxfs - 1); - - xfptr += index; - ExtendedFormatRecord retval = - ( ExtendedFormatRecord ) records.get(xfptr); - - return retval; - } - - /** - * Removes the given ExtendedFormatRecord record from the - * file's list. This will make all - * subsequent font indicies drop by one, - * so you'll need to update those yourself! - */ - public void removeExFormatRecord(ExtendedFormatRecord rec) { - records.remove(rec); // this updates XfPos for us - numxfs--; - } - - - /** - * creates a new Cell-type Extneded Format Record and adds it to the end of - * ExtendedFormatRecords collection - * - * @return ExtendedFormatRecord that was created - */ - - public ExtendedFormatRecord createCellXF() { - ExtendedFormatRecord xf = createExtendedFormat(); - - records.add(records.getXfpos()+1, xf); - records.setXfpos( records.getXfpos() + 1 ); - numxfs++; - return xf; - } - - /** - * Returns the StyleRecord for the given - * xfIndex, or null if that ExtendedFormat doesn't - * have a Style set. - */ - public StyleRecord getStyleRecord(int xfIndex) { - // Style records always follow after - // the ExtendedFormat records - for(int i=records.getXfpos(); i - * horizontal hold - 0x168

- * vertical hold - 0x10e

- * width - 0x3a5c

- * height - 0x23be

- * options - 0x38

- * selected tab - 0

- * displayed tab - 0

- * num selected tab- 0

- * tab width ratio - 0x258

- */ - private static WindowOneRecord createWindowOne() { - WindowOneRecord retval = new WindowOneRecord(); - - retval.setHorizontalHold(( short ) 0x168); - retval.setVerticalHold(( short ) 0x10e); - retval.setWidth(( short ) 0x3a5c); - retval.setHeight(( short ) 0x23be); - retval.setOptions(( short ) 0x38); - retval.setActiveSheetIndex( 0x0); - retval.setFirstVisibleTab(0x0); - retval.setNumSelectedTabs(( short ) 1); - retval.setTabWidthRatio(( short ) 0x258); - return retval; - } - - /** - * creates the Backup record with backup set to 0. (loose the data, who cares) - */ - private static BackupRecord createBackup() { - BackupRecord retval = new BackupRecord(); - - retval.setBackup(( short ) 0); // by default DONT save backups of files...just loose data - return retval; - } - - /** - * creates the HideObj record with hide object set to 0. (don't hide) - */ - private static HideObjRecord createHideObj() { - HideObjRecord retval = new HideObjRecord(); - retval.setHideObj(( short ) 0); // by default set hide object off - return retval; - } - - /** - * creates the DateWindow1904 record with windowing set to 0. (don't window) - */ - private static DateWindow1904Record createDateWindow1904() { - DateWindow1904Record retval = new DateWindow1904Record(); - - retval.setWindowing(( short ) 0); // don't EVER use 1904 date windowing...tick tock.. - return retval; - } - - /** - * creates the Precision record with precision set to true. (full precision) - */ - private static PrecisionRecord createPrecision() { - PrecisionRecord retval = new PrecisionRecord(); - retval.setFullPrecision(true); // always use real numbers in calculations! - return retval; - } - - /** - * @return a new RefreshAll record with refreshAll set to false. (do not refresh all calcs) - */ - private static RefreshAllRecord createRefreshAll() { - return new RefreshAllRecord(false); - } - - /** - * creates the BookBool record with saveLinkValues set to 0. (don't save link values) - */ - private static BookBoolRecord createBookBool() { - BookBoolRecord retval = new BookBoolRecord(); - retval.setSaveLinkValues(( short ) 0); - return retval; - } - - /** - * creates a Font record with the following magic values:

- * fontheight = 0xc8

- * attributes = 0x0

- * color palette index = 0x7fff

- * bold weight = 0x190

- * Font Name Length = 5

- * Font Name = Arial

- */ - private static FontRecord createFont() { - FontRecord retval = new FontRecord(); - - retval.setFontHeight(( short ) 0xc8); - retval.setAttributes(( short ) 0x0); - retval.setColorPaletteIndex(( short ) 0x7fff); - retval.setBoldWeight(( short ) 0x190); - retval.setFontName("Arial"); - return retval; - } - - /** - * Creates a FormatRecord object - * @param id the number of the format record to create (meaning its position in - * a file as M$ Excel would create it.) - */ - private static FormatRecord createFormat(int id) { - // we'll need multiple editions for - // the different formats - - switch (id) { - case 0: return new FormatRecord(5, "\"$\"#,##0_);\\(\"$\"#,##0\\)"); - case 1: return new FormatRecord(6, "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)"); - case 2: return new FormatRecord(7, "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)"); - case 3: return new FormatRecord(8, "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)"); - case 4: return new FormatRecord(0x2a, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"); - case 5: return new FormatRecord(0x29, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"); - case 6: return new FormatRecord(0x2c, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"); - case 7: return new FormatRecord(0x2b, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"); - } - throw new IllegalArgumentException("Unexpected id " + id); - } - - /** - * Creates an ExtendedFormatRecord object - * @param id the number of the extended format record to create (meaning its position in - * a file as MS Excel would create it.) - */ - private static ExtendedFormatRecord createExtendedFormat(int id) { // we'll need multiple editions - ExtendedFormatRecord retval = new ExtendedFormatRecord(); - - switch (id) { - - case 0 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 1 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 2 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 3 : - retval.setFontIndex(( short ) 2); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 4 : - retval.setFontIndex(( short ) 2); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 5 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 6 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 7 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 8 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 9 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 10 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 11 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 12 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 13 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 14 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // cell records - case 15 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x0); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // style - case 16 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2b); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 17 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x29); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 18 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2c); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 19 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2a); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 20 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x9); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // unused from this point down - case 21 : - retval.setFontIndex(( short ) 5); - retval.setFormatIndex(( short ) 0x0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 22 : - retval.setFontIndex(( short ) 6); - retval.setFormatIndex(( short ) 0x0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 23 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0x31); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 24 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0x8); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 25 : - retval.setFontIndex(( short ) 6); - retval.setFormatIndex(( short ) 0x8); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - } - return retval; - } - - /** - * creates an default cell type ExtendedFormatRecord object. - * @return ExtendedFormatRecord with intial defaults (cell-type) - */ - private static ExtendedFormatRecord createExtendedFormat() { - ExtendedFormatRecord retval = new ExtendedFormatRecord(); - - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0x0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index); - retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index); - retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index); - retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index); - return retval; - } - - /** - * Creates a StyleRecord object - * @param id the number of the style record to create (meaning its position in - * a file as MS Excel would create it. - */ - private static StyleRecord createStyle(int id) { // we'll need multiple editions - StyleRecord retval = new StyleRecord(); - - switch (id) { - - case 0 : - retval.setXFIndex(0x010); - retval.setBuiltinStyle(3); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 1 : - retval.setXFIndex(0x011); - retval.setBuiltinStyle(6); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 2 : - retval.setXFIndex(0x012); - retval.setBuiltinStyle(4); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 3 : - retval.setXFIndex(0x013); - retval.setBuiltinStyle(7); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 4 : - retval.setXFIndex(0x000); - retval.setBuiltinStyle(0); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 5 : - retval.setXFIndex(0x014); - retval.setBuiltinStyle(5); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - } - return retval; - } - - /** - * Creates a palette record initialized to the default palette - */ - private static PaletteRecord createPalette() { - return new PaletteRecord(); - } - - /** - * @return a new UseSelFS object with the use natural language flag set to 0 (false) - */ - private static UseSelFSRecord createUseSelFS() { - return new UseSelFSRecord(false); - } - - /** - * create a "bound sheet" or "bundlesheet" (depending who you ask) record - * Always sets the sheet's bof to 0. You'll need to set that yourself. - * @param id either sheet 0,1 or 2. - * @return record containing a BoundSheetRecord - * @see org.apache.poi.hssf.record.BoundSheetRecord - * @see org.apache.poi.hssf.record.Record - */ - private static BoundSheetRecord createBoundSheet(int id) { - return new BoundSheetRecord("Sheet" + (id+1)); - } - - /** - * Creates the Country record with the default country set to 1 - * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise - */ - private static CountryRecord createCountry() { - CountryRecord retval = new CountryRecord(); - - retval.setDefaultCountry(( short ) 1); - - // from Russia with love ;) - if ( Locale.getDefault().toString().equals( "ru_RU" ) ) { - retval.setCurrentCountry(( short ) 7); - } - else { - retval.setCurrentCountry(( short ) 1); - } - - return retval; - } - - /** - * Creates the ExtendedSST record with numstrings per bucket set to 0x8. HSSF - * doesn't yet know what to do with this thing, but we create it with nothing in - * it hardly just to make Excel happy and our sheets look like Excel's - */ - private static ExtSSTRecord createExtendedSST() { - ExtSSTRecord retval = new ExtSSTRecord(); - retval.setNumStringsPerBucket(( short ) 0x8); - return retval; - } - - /** - * lazy initialization - * Note - creating the link table causes creation of 1 EXTERNALBOOK and 1 EXTERNALSHEET record - */ - private LinkTable getOrCreateLinkTable() { - if(linkTable == null) { - linkTable = new LinkTable((short) getNumSheets(), records); - } - return linkTable; - } - - /** finds the sheet name by his extern sheet index - * @param externSheetIndex extern sheet index - * @return sheet name. - */ - public String findSheetNameFromExternSheet(int externSheetIndex){ - - int indexToSheet = linkTable.getIndexToInternalSheet(externSheetIndex); - if (indexToSheet < 0) { - // TODO - what does '-1' mean here? - //error check, bail out gracefully! - return ""; - } - if (indexToSheet >= boundsheets.size()) { - // Not sure if this can ever happen (See bug 45798) - return ""; // Seems to be what excel would do in this case - } - return getSheetName(indexToSheet); - } - public ExternalSheet getExternalSheet(int externSheetIndex) { - String[] extNames = linkTable.getExternalBookAndSheetName(externSheetIndex); - if (extNames == null) { - return null; - } - return new ExternalSheet(extNames[0], extNames[1]); - } - - /** - * Finds the sheet index for a particular external sheet number. - * @param externSheetNumber The external sheet number to convert - * @return The index to the sheet found. - */ - public int getSheetIndexFromExternSheetIndex(int externSheetNumber) - { - return linkTable.getSheetIndexFromExternSheetIndex(externSheetNumber); - } - - /** returns the extern sheet number for specific sheet number , - * if this sheet doesn't exist in extern sheet , add it - * @param sheetNumber sheet number - * @return index to extern sheet - */ - public short checkExternSheet(int sheetNumber){ - return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber); - } - - public int getExternalSheetIndex(String workbookName, String sheetName) { - return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName); - } - - - /** gets the total number of names - * @return number of names - */ - public int getNumNames(){ - if(linkTable == null) { - return 0; - } - return linkTable.getNumNames(); - } - - /** gets the name record - * @param index name index - * @return name record - */ - public NameRecord getNameRecord(int index){ - return linkTable.getNameRecord(index); - } - - /** creates new name - * @return new name record - */ - public NameRecord createName(){ - return addName(new NameRecord()); - } - - - /** creates new name - * @return new name record - */ - public NameRecord addName(NameRecord name) - { - - LinkTable linkTable = getOrCreateLinkTable(); - if(linkTable.nameAlreadyExists(name)) { - throw new IllegalArgumentException( - "You are trying to assign a duplicated name record: " - + name.getNameText()); - } - linkTable.addName(name); - - return name; - } - - /** - * Generates a NameRecord to represent a built-in region - * @return a new NameRecord - */ - public NameRecord createBuiltInName(byte builtInName, int sheetNumber) { - if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) { - throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid "); - } - - NameRecord name = new NameRecord(builtInName, sheetNumber); - - while(linkTable.nameAlreadyExists(name)) { - throw new RuntimeException("Builtin (" + builtInName - + ") already exists for sheet (" + sheetNumber + ")"); - } - addName(name); - return name; - } - - - /** removes the name - * @param nameIndex name index - */ - public void removeName(int nameIndex){ - - if (linkTable.getNumNames() > nameIndex) { - int idx = findFirstRecordLocBySid(NameRecord.sid); - records.remove(idx + nameIndex); - linkTable.removeName(nameIndex); - } - } - - /** - * Returns a format index that matches the passed in format. It does not tie into HSSFDataFormat. - * @param format the format string - * @param createIfNotFound creates a new format if format not found - * @return the format id of a format that matches or -1 if none found and createIfNotFound - */ - public short getFormat(String format, boolean createIfNotFound) { - Iterator iterator; - for (iterator = formats.iterator(); iterator.hasNext();) { - FormatRecord r = (FormatRecord)iterator.next(); - if (r.getFormatString().equals(format)) { - return (short)r.getIndexCode(); - } - } - - if (createIfNotFound) { - return (short)createFormat(format); - } - - return -1; - } - - /** - * Returns the list of FormatRecords in the workbook. - * @return ArrayList of FormatRecords in the notebook - */ - public List getFormats() { - return formats; - } - - /** - * Creates a FormatRecord, inserts it, and returns the index code. - * @param formatString the format string - * @return the index code of the format record. - * @see org.apache.poi.hssf.record.FormatRecord - * @see org.apache.poi.hssf.record.Record - */ - public int createFormat(String formatString) { - - maxformatid = maxformatid >= 0xa4 ? maxformatid + 1 : 0xa4; //Starting value from M$ empircal study. - FormatRecord rec = new FormatRecord(maxformatid, formatString); - - int pos = 0; - while ( pos < records.size() && records.get( pos ).getSid() != FormatRecord.sid ) - pos++; - pos += formats.size(); - formats.add( rec ); - records.add( pos, rec ); - return maxformatid; - } - - - - /** - * 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; - } - - /** - * Returns the index of a record matching a particular sid. - * @param sid The sid of the record to match - * @return The index of -1 if no match 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 next occurance of a record matching a particular sid. - */ - public Record findNextRecordBySid(short sid, int pos) { - int matches = 0; - for (Iterator iterator = records.iterator(); iterator.hasNext(); ) { - Record record = ( Record ) iterator.next(); - - if (record.getSid() == sid) { - if (matches++ == pos) - return record; - } - } - return null; - } - - public List getHyperlinks() - { - return hyperlinks; - } - - public List getRecords() { - return records.getRecords(); - } - - /** - * Whether date windowing is based on 1/2/1904 or 1/1/1900. - * Some versions of Excel (Mac) can save workbooks using 1904 date windowing. - * - * @return true if using 1904 date windowing - */ - public boolean isUsing1904DateWindowing() { - return uses1904datewindowing; - } - - /** - * Returns the custom palette in use for this workbook; if a custom palette record - * does not exist, then it is created. - */ - public PaletteRecord getCustomPalette() - { - PaletteRecord palette; - int palettePos = records.getPalettepos(); - if (palettePos != -1) { - Record rec = records.get(palettePos); - if (rec instanceof PaletteRecord) { - palette = (PaletteRecord) rec; - } else throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'"); - } - else - { - palette = createPalette(); - //Add the palette record after the bof which is always the first record - records.add(1, palette); - records.setPalettepos(1); - } - return palette; - } - - /** - * Finds the primary drawing group, if one already exists - */ - public void findDrawingGroup() { - // Need to find a DrawingGroupRecord that - // contains a EscherDggRecord - for(Iterator rit = records.iterator(); rit.hasNext();) { - Record r = rit.next(); - - if(r instanceof DrawingGroupRecord) { - DrawingGroupRecord dg = (DrawingGroupRecord)r; - dg.processChildRecords(); - - EscherContainerRecord cr = - dg.getEscherContainer(); - if(cr == null) { - continue; - } - - EscherDggRecord dgg = null; - for(Iterator it = cr.getChildIterator(); it.hasNext();) { - Object er = it.next(); - if(er instanceof EscherDggRecord) { - dgg = (EscherDggRecord)er; - } - } - - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - return; - } - } - } - - // Look for the DrawingGroup record - int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); - - // If there is one, does it have a EscherDggRecord? - if(dgLoc != -1) { - DrawingGroupRecord dg = (DrawingGroupRecord)records.get(dgLoc); - EscherDggRecord dgg = null; - for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) { - Object er = it.next(); - if(er instanceof EscherDggRecord) { - dgg = (EscherDggRecord)er; - } - } - - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - } - } - } - - /** - * Creates a primary drawing group record. If it already - * exists then it's modified. - */ - public void createDrawingGroup() { - if (drawingManager == null) { - EscherContainerRecord dggContainer = new EscherContainerRecord(); - EscherDggRecord dgg = new EscherDggRecord(); - EscherOptRecord opt = new EscherOptRecord(); - EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord(); - - dggContainer.setRecordId((short) 0xF000); - dggContainer.setOptions((short) 0x000F); - dgg.setRecordId(EscherDggRecord.RECORD_ID); - dgg.setOptions((short)0x0000); - dgg.setShapeIdMax(1024); - dgg.setNumShapesSaved(0); - dgg.setDrawingsSaved(0); - dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} ); - drawingManager = new DrawingManager2(dgg); - EscherContainerRecord bstoreContainer = null; - if (escherBSERecords.size() > 0) - { - bstoreContainer = new EscherContainerRecord(); - bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); - bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) ); - for ( Iterator iterator = escherBSERecords.iterator(); iterator.hasNext(); ) - { - EscherRecord escherRecord = (EscherRecord) iterator.next(); - bstoreContainer.addChildRecord( escherRecord ); - } - } - opt.setRecordId((short) 0xF00B); - opt.setOptions((short) 0x0033); - opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) ); - opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 0x08000041) ); - opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) ); - splitMenuColors.setRecordId((short) 0xF11E); - splitMenuColors.setOptions((short) 0x0040); - splitMenuColors.setColor1(0x0800000D); - splitMenuColors.setColor2(0x0800000C); - splitMenuColors.setColor3(0x08000017); - splitMenuColors.setColor4(0x100000F7); - - dggContainer.addChildRecord(dgg); - if (bstoreContainer != null) - dggContainer.addChildRecord( bstoreContainer ); - dggContainer.addChildRecord(opt); - dggContainer.addChildRecord(splitMenuColors); - - int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); - if (dgLoc == -1) { - DrawingGroupRecord drawingGroup = new DrawingGroupRecord(); - drawingGroup.addEscherRecord(dggContainer); - int loc = findFirstRecordLocBySid(CountryRecord.sid); - - getRecords().add(loc+1, drawingGroup); - } else { - DrawingGroupRecord drawingGroup = new DrawingGroupRecord(); - drawingGroup.addEscherRecord(dggContainer); - getRecords().set(dgLoc, drawingGroup); - } - - } - } - - public WindowOneRecord getWindowOne() { - return windowOne; - } - - public EscherBSERecord getBSERecord(int pictureIndex) { - return escherBSERecords.get(pictureIndex-1); - } - - public int addBSERecord(EscherBSERecord e) { - createDrawingGroup(); - - // maybe we don't need that as an instance variable anymore - escherBSERecords.add( e ); - - int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); - DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords().get( dgLoc ); - - EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup.getEscherRecord( 0 ); - EscherContainerRecord bstoreContainer; - if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER ) - { - bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 ); - } - else - { - bstoreContainer = new EscherContainerRecord(); - bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); - List childRecords = dggContainer.getChildRecords(); - childRecords.add(1, bstoreContainer); - dggContainer.setChildRecords(childRecords); - } - bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) ); - - bstoreContainer.addChildRecord( e ); - - return escherBSERecords.size(); - } - - public DrawingManager2 getDrawingManager() - { - return drawingManager; - } - - public WriteProtectRecord getWriteProtect() { - if (writeProtect == null) { - writeProtect = new WriteProtectRecord(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof BOFRecord); - i++) { - } - records.add(i+1, writeProtect); - } - return this.writeProtect; - } - - public WriteAccessRecord getWriteAccess() { - if (writeAccess == null) { - writeAccess = createWriteAccess(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof InterfaceEndRecord); - i++) { - } - records.add(i+1, writeAccess); - } - return writeAccess; - } - - public FileSharingRecord getFileSharing() { - if (fileShare == null) { - fileShare = new FileSharingRecord(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof WriteAccessRecord); - i++) { - } - records.add(i+1, fileShare); - } - return fileShare; - } - - /** - * is the workbook protected with a password (not encrypted)? - */ - public boolean isWriteProtected() { - if (fileShare == null) { - return false; - } - FileSharingRecord frec = getFileSharing(); - return frec.getReadOnly() == 1; - } - - /** - * protect a workbook with a password (not encypted, just sets writeprotect - * flags and the password. - * @param password to set - */ - public void writeProtectWorkbook( String password, String username ) { - int protIdx = -1; - FileSharingRecord frec = getFileSharing(); - WriteAccessRecord waccess = getWriteAccess(); - WriteProtectRecord wprotect = getWriteProtect(); - frec.setReadOnly((short)1); - frec.setPassword(FileSharingRecord.hashPassword(password)); - frec.setUsername(username); - waccess.setUsername(username); - } - - /** - * removes the write protect flag - */ - public void unwriteProtectWorkbook() { - records.remove(fileShare); - records.remove(writeProtect); - fileShare = null; - writeProtect = null; - } - - /** - * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table - * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record - * @return the string representation of the defined or external name - */ - public String resolveNameXText(int refIndex, int definedNameIndex) { - return linkTable.resolveNameXText(refIndex, definedNameIndex); - } - - public NameXPtg getNameXPtg(String name) { - return getOrCreateLinkTable().getNameXPtg(name); - } - - /** - * Check if the cloned sheet has drawings. If yes, then allocate a new drawing group ID and - * re-generate shape IDs - * - * @param sheet the cloned sheet - */ - public void cloneDrawings(Sheet sheet){ - - findDrawingGroup(); - - if(drawingManager == null) { - //this workbook does not have drawings - return; - } - - //check if the cloned sheet has drawings - int aggLoc = sheet.aggregateDrawingRecords(drawingManager, false); - if(aggLoc != -1) { - EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid); - EscherContainerRecord escherContainer = agg.getEscherContainer(); - if (escherContainer == null) { - return; - } - - EscherDggRecord dgg = drawingManager.getDgg(); - - //register a new drawing group for the cloned sheet - int dgId = drawingManager.findNewDrawingGroupId(); - dgg.addCluster( dgId, 0 ); - dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); - - EscherDgRecord dg = null; - for(Iterator it = escherContainer.getChildIterator(); it.hasNext();) { - EscherRecord er = it.next(); - if(er instanceof EscherDgRecord) { - dg = (EscherDgRecord)er; - //update id of the drawing in the cloned sheet - dg.setOptions( (short) ( dgId << 4 ) ); - } else if (er instanceof EscherContainerRecord){ - //recursively find shape records and re-generate shapeId - List spRecords = new ArrayList(); - EscherContainerRecord cp = (EscherContainerRecord)er; - cp.getRecordsById(EscherSpRecord.RECORD_ID, spRecords); - for(Iterator spIt = spRecords.iterator(); spIt.hasNext();) { - EscherSpRecord sp = (EscherSpRecord)spIt.next(); - int shapeId = drawingManager.allocateShapeId((short)dgId, dg); - //allocateShapeId increments the number of shapes. roll back to the previous value - dg.setNumShapes(dg.getNumShapes()-1); - sp.setShapeId(shapeId); - } - } - } - - } - } - - /** - * Updates named ranges due to moving of cells - */ - public void updateNamesAfterCellShift(FormulaShifter shifter) { - for (int i = 0 ; i < getNumNames() ; ++i){ - NameRecord nr = getNameRecord(i); - Ptg[] ptgs = nr.getNameDefinition(); - if (shifter.adjustFormula(ptgs, nr.getSheetNumber())) { - nr.setNameDefinition(ptgs); - } - } - } - -} diff --git a/src/java/org/apache/poi/hssf/record/FormatRecord.java b/src/java/org/apache/poi/hssf/record/FormatRecord.java index 2d2f238c51..f587d57c91 100644 --- a/src/java/org/apache/poi/hssf/record/FormatRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormatRecord.java @@ -58,7 +58,7 @@ public final class FormatRecord extends StandardRecord { * get the format index code (for built in formats) * * @return the format index code - * @see org.apache.poi.hssf.model.Workbook + * @see org.apache.poi.hssf.model.InternalWorkbook */ public int getIndexCode() { return field_1_index_code; diff --git a/src/java/org/apache/poi/hssf/record/PaletteRecord.java b/src/java/org/apache/poi/hssf/record/PaletteRecord.java index a58eea67d4..2f222465b6 100644 --- a/src/java/org/apache/poi/hssf/record/PaletteRecord.java +++ b/src/java/org/apache/poi/hssf/record/PaletteRecord.java @@ -34,35 +34,32 @@ public final class PaletteRecord extends StandardRecord { public final static byte STANDARD_PALETTE_SIZE = (byte) 56; /** The byte index of the first color */ public final static short FIRST_COLOR_INDEX = (short) 0x8; - - private List field_2_colors; - public PaletteRecord() - { + private final List _colors; + + public PaletteRecord() { PColor[] defaultPalette = createDefaultPalette(); - field_2_colors = new ArrayList(defaultPalette.length); + _colors = new ArrayList(defaultPalette.length); for (int i = 0; i < defaultPalette.length; i++) { - field_2_colors.add(defaultPalette[i]); + _colors.add(defaultPalette[i]); } } - public PaletteRecord(RecordInputStream in) - { + public PaletteRecord(RecordInputStream in) { int field_1_numcolors = in.readShort(); - field_2_colors = new ArrayList(field_1_numcolors); + _colors = new ArrayList(field_1_numcolors); for (int k = 0; k < field_1_numcolors; k++) { - field_2_colors.add(new PColor(in)); - } + _colors.add(new PColor(in)); + } } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[PALETTE]\n"); - buffer.append(" numcolors = ").append(field_2_colors.size()).append('\n'); - for (int i = 0; i < field_2_colors.size(); i++) { - PColor c = field_2_colors.get(i); + buffer.append(" numcolors = ").append(_colors.size()).append('\n'); + for (int i = 0; i < _colors.size(); i++) { + PColor c = _colors.get(i); buffer.append("* colornum = ").append(i).append('\n'); buffer.append(c.toString()); buffer.append("/*colornum = ").append(i).append('\n'); @@ -71,20 +68,18 @@ public final class PaletteRecord extends StandardRecord { return buffer.toString(); } - public void serialize(LittleEndianOutput out) - { - out.writeShort(field_2_colors.size()); - for (int i = 0; i < field_2_colors.size(); i++) { - field_2_colors.get(i).serialize(out); + public void serialize(LittleEndianOutput out) { + out.writeShort(_colors.size()); + for (int i = 0; i < _colors.size(); i++) { + _colors.get(i).serialize(out); } } protected int getDataSize() { - return 2 + field_2_colors.size() * PColor.ENCODED_SIZE; + return 2 + _colors.size() * PColor.ENCODED_SIZE; } - public short getSid() - { + public short getSid() { return sid; } @@ -94,16 +89,14 @@ public final class PaletteRecord extends StandardRecord { * @return the RGB triplet for the color, or null if the specified index * does not exist */ - public byte[] getColor(short byteIndex) { + public byte[] getColor(int byteIndex) { int i = byteIndex - FIRST_COLOR_INDEX; - if (i < 0 || i >= field_2_colors.size()) - { + if (i < 0 || i >= _colors.size()) { return null; } - PColor color = field_2_colors.get(i); - return new byte[] { color.red, color.green, color.blue }; + return _colors.get(i).getTriplet(); } - + /** * Sets the color value at a given index * @@ -120,18 +113,16 @@ public final class PaletteRecord extends StandardRecord { { return; } - // may need to grow - fill intervening pallette entries with black - while (field_2_colors.size() <= i) { - field_2_colors.add(new PColor(0, 0, 0)); + // may need to grow - fill intervening palette entries with black + while (_colors.size() <= i) { + _colors.add(new PColor(0, 0, 0)); } PColor custColor = new PColor(red, green, blue); - field_2_colors.set(i, custColor); + _colors.set(i, custColor); } - + /** * Creates the default palette as PaletteRecord binary data - * - * @see org.apache.poi.hssf.model.Workbook#createPalette */ private static PColor[] createDefaultPalette() { @@ -199,41 +190,45 @@ public final class PaletteRecord extends StandardRecord { return new PColor(r, g, b); } -/** - * PColor - element in the list of colors - consider it a "struct" - */ -private static final class PColor { - public static final short ENCODED_SIZE = 4; - public byte red; - public byte green; - public byte blue; - - public PColor(int red, int green, int blue) { - this.red=(byte) red; - this.green=(byte) green; - this.blue=(byte) blue; - } - - public PColor(RecordInputStream in) { - red=in.readByte(); - green=in.readByte(); - blue=in.readByte(); - in.readByte(); // unused - } - - public void serialize(LittleEndianOutput out) { - out.writeByte(red); - out.writeByte(green); - out.writeByte(blue); - out.writeByte(0); - } - - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(" red = ").append(red & 0xff).append('\n'); - buffer.append(" green = ").append(green & 0xff).append('\n'); - buffer.append(" blue = ").append(blue & 0xff).append('\n'); - return buffer.toString(); - } + /** + * PColor - element in the list of colors + */ + private static final class PColor { + public static final short ENCODED_SIZE = 4; + private int _red; + private int _green; + private int _blue; + + public PColor(int red, int green, int blue) { + _red = red; + _green = green; + _blue = blue; + } + + public byte[] getTriplet() { + return new byte[] { (byte) _red, (byte) _green, (byte) _blue }; + } + + public PColor(RecordInputStream in) { + _red = in.readByte(); + _green = in.readByte(); + _blue = in.readByte(); + in.readByte(); // unused + } + + public void serialize(LittleEndianOutput out) { + out.writeByte(_red); + out.writeByte(_green); + out.writeByte(_blue); + out.writeByte(0); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(" red = ").append(_red & 0xff).append('\n'); + buffer.append(" green = ").append(_green & 0xff).append('\n'); + buffer.append(" blue = ").append(_blue & 0xff).append('\n'); + return buffer.toString(); + } + } } -} \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java b/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java index c336e14d30..e938552c64 100644 --- a/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java +++ b/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java @@ -25,12 +25,10 @@ import org.apache.poi.util.LittleEndianOutput; * Description: This record contains an ID that marks when a worksheet was last * recalculated. It's an optimization Excel uses to determine if it * needs to recalculate the spreadsheet when it's opened. So far, only - * the two engine ids 0x80 0x38 0x01 0x00 + * the two engine ids 0x80 0x38 0x01 0x00 * and 0x60 0x69 0x01 0x00 have been seen.

* REFERENCE: http://chicago.sourceforge.net/devel/docs/excel/biff8.html

* @author Luc Girardin (luc dot girardin at macrofocus dot com) - * - * @see org.apache.poi.hssf.model.Workbook */ public final class RecalcIdRecord extends StandardRecord { public final static short sid = 0x01C1; diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 551d503560..6557a81226 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -23,7 +23,7 @@ import java.util.*; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.Sheet; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.CellValueRecordInterface; @@ -229,7 +229,7 @@ public class HSSFCell implements Cell { /** * Returns the Workbook that this Cell is bound to */ - protected Workbook getBoundWorkbook() { + protected InternalWorkbook getBoundWorkbook() { return _book.getWorkbook(); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java index 606fe3c5fd..92642b30eb 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java @@ -18,7 +18,7 @@ package org.apache.poi.hssf.usermodel; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.ExtendedFormatRecord; import org.apache.poi.hssf.record.FontRecord; import org.apache.poi.hssf.record.StyleRecord; @@ -38,7 +38,7 @@ import org.apache.poi.ss.usermodel.Font; public final class HSSFCellStyle implements CellStyle { private ExtendedFormatRecord _format = null; private short _index = 0; - private Workbook _workbook = null; + private InternalWorkbook _workbook = null; /** Creates new HSSFCellStyle why would you want to do this?? */ @@ -46,7 +46,7 @@ public final class HSSFCellStyle implements CellStyle { { this(index, rec, workbook.getWorkbook()); } - protected HSSFCellStyle(short index, ExtendedFormatRecord rec, Workbook workbook) + protected HSSFCellStyle(short index, ExtendedFormatRecord rec, InternalWorkbook workbook) { _workbook = workbook; _index = index; @@ -125,7 +125,7 @@ public final class HSSFCellStyle implements CellStyle { * the DataFormat against the supplied low level workbook * @see org.apache.poi.hssf.usermodel.HSSFDataFormat */ - public String getDataFormatString(org.apache.poi.hssf.model.Workbook workbook) { + public String getDataFormatString(org.apache.poi.hssf.model.InternalWorkbook workbook) { HSSFDataFormat format = new HSSFDataFormat( workbook ); return format.getFormat(getDataFormat()); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java index 28fd8e0557..f18f377387 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java @@ -29,7 +29,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Vector; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.FormatRecord; import org.apache.poi.ss.usermodel.BuiltinFormats; import org.apache.poi.ss.usermodel.DataFormat; @@ -37,15 +37,15 @@ import org.apache.poi.ss.usermodel.DataFormat; /** * Identifies both built-in and user defined formats within a workbook.

* See {@link BuiltinFormats} for a list of supported built-in formats.

- * + * * International Formats
- * Since version 2003 Excel has supported international formats. These are denoted + * Since version 2003 Excel has supported international formats. These are denoted * with a prefix "[$-xxx]" (where xxx is a 1-7 digit hexadecimal number). - * See the Microsoft article + * See the Microsoft article * * Creating international number formats * for more details on these codes. - * + * * @author Andrew C. Oliver (acoliver at apache dot org) * @author Shawn M. Laubach (slaubach at apache dot org) */ @@ -53,7 +53,7 @@ public final class HSSFDataFormat implements DataFormat { private static final String[] _builtinFormats = BuiltinFormats.getAll(); private final Vector _formats = new Vector(); - private final Workbook _workbook; + private final InternalWorkbook _workbook; private boolean _movedBuiltins = false; // Flag to see if need to // check the built in list // or if the regular list @@ -64,7 +64,7 @@ public final class HSSFDataFormat implements DataFormat { * access to the workbooks format records. * @param workbook the workbook the formats are tied to. */ - public HSSFDataFormat(Workbook workbook) { + HSSFDataFormat(InternalWorkbook workbook) { _workbook = workbook; @SuppressWarnings("unchecked") diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java index 7b55d81db7..1f10a926ad 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java @@ -18,7 +18,7 @@ package org.apache.poi.hssf.usermodel; import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.NamePtg; @@ -42,7 +42,7 @@ import org.apache.poi.ss.formula.FormulaType; public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook { private final HSSFWorkbook _uBook; - private final Workbook _iBook; + private final InternalWorkbook _iBook; public static HSSFEvaluationWorkbook create(HSSFWorkbook book) { if (book == null) { diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java index 662ec2e1aa..579d3494e9 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -18,7 +18,7 @@ package org.apache.poi.hssf.usermodel; import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.ss.formula.FormulaType; @@ -114,7 +114,7 @@ public final class HSSFName implements Name { public void setNameName(String nameName){ validateName(nameName); - Workbook wb = _book.getWorkbook(); + InternalWorkbook wb = _book.getWorkbook(); _definedNameRec.setNameText(nameName); int sheetNumber = _definedNameRec.getSheetNumber(); @@ -135,7 +135,7 @@ public final class HSSFName implements Name { private static void validateName(String name){ if(name.length() == 0) throw new IllegalArgumentException("Name cannot be blank"); - + char c = name.charAt(0); if(!(c == '_' || Character.isLetter(c)) || name.indexOf(' ') != -1) { throw new IllegalArgumentException("Invalid name: '"+name+"'; Names must begin with a letter or underscore and not contain spaces"); @@ -249,9 +249,7 @@ public final class HSSFName implements Name { * * @param value true indicates the name refers to a function. */ - public void setFunction(boolean value) { - _definedNameRec.setFunction(value); - - } - + public void setFunction(boolean value) { + _definedNameRec.setFunction(value); + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java index 269cabe423..e69a203b9f 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java @@ -19,7 +19,7 @@ package org.apache.poi.hssf.usermodel; import java.util.Iterator; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.UnicodeString; import org.apache.poi.ss.usermodel.Font; @@ -74,7 +74,7 @@ public final class HSSFRichTextString implements Comparable, public static final short NO_FONT = 0; private UnicodeString _string; - private Workbook _book; + private InternalWorkbook _book; private LabelSSTRecord _record; public HSSFRichTextString() @@ -90,7 +90,7 @@ public final class HSSFRichTextString implements Comparable, } } - HSSFRichTextString(Workbook book, LabelSSTRecord record) { + HSSFRichTextString(InternalWorkbook book, LabelSSTRecord record) { setWorkbookReferences(book, record); _string = book.getSSTString(record.getSSTIndex()); @@ -99,7 +99,7 @@ public final class HSSFRichTextString implements Comparable, /** This must be called to setup the internal work book references whenever * a RichTextString is added to a cell */ - void setWorkbookReferences(Workbook book, LabelSSTRecord record) { + void setWorkbookReferences(InternalWorkbook book, LabelSSTRecord record) { _book = book; _record = record; } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index c7972ecc93..6fa9b68dd6 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -32,7 +32,7 @@ import java.util.TreeMap; import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hssf.model.Sheet; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.DVRecord; import org.apache.poi.hssf.record.EscherAggregate; @@ -82,7 +82,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { private final Sheet _sheet; /** stores rows by zero-based row number */ private final TreeMap _rows; - protected final Workbook _book; + protected final InternalWorkbook _book; protected final HSSFWorkbook _workbook; private int _firstrow; private int _lastrow; @@ -636,7 +636,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { /** * Sets whether the worksheet is displayed from right to left instead of from left to right. - * + * * @param value true for right to left, false otherwise. */ public void setRightToLeft(boolean value) @@ -1693,7 +1693,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { FontRenderContext frc = new FontRenderContext(null, true, true); - HSSFWorkbook wb = new HSSFWorkbook(_book); + HSSFWorkbook wb = HSSFWorkbook.create(_book); // TODO - is it important to not use _workbook? HSSFFont defaultFont = wb.getFontAt((short) 0); str = new AttributedString("" + defaultChar); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index ca10a6f874..bd8fa768fc 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -38,7 +38,7 @@ import org.apache.poi.hssf.OldExcelFormatException; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.Sheet; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.AbstractEscherHolderRecord; import org.apache.poi.hssf.record.BackupRecord; import org.apache.poi.hssf.record.DrawingGroupRecord; @@ -78,13 +78,13 @@ import org.apache.poi.util.POILogger; * will construct whether they are reading or writing a workbook. It is also the * top level object for creating new sheets/etc. * - * @see org.apache.poi.hssf.model.Workbook + * @see org.apache.poi.hssf.model.InternalWorkbook * @see org.apache.poi.hssf.usermodel.HSSFSheet * @author Andrew C. Oliver (acoliver at apache dot org) * @author Glen Stampoultzis (glens at apache.org) * @author Shawn Laubach (slaubach at apache dot org) */ -public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook { +public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook { private static final Pattern COMMA_PATTERN = Pattern.compile(","); private static final int MAX_ROW = 0xFFFF; private static final short MAX_COLUMN = (short)0x00FF; @@ -104,7 +104,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm * this is the reference to the low level Workbook object */ - private Workbook workbook; + private InternalWorkbook workbook; /** * this holds the HSSFSheet objects attached to this workbook @@ -162,25 +162,26 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); + public static HSSFWorkbook create(InternalWorkbook book) { + return new HSSFWorkbook(book); + } /** * Creates new HSSFWorkbook from scratch (start here!) * */ - public HSSFWorkbook() - { - this(Workbook.createWorkbook()); + public HSSFWorkbook() { + this(InternalWorkbook.createWorkbook()); } - protected HSSFWorkbook( Workbook book ) - { - super(null, null); - workbook = book; - _sheets = new ArrayList( INITIAL_CAPACITY ); - names = new ArrayList( INITIAL_CAPACITY ); - } + private HSSFWorkbook(InternalWorkbook book) { + super(null, null); + workbook = book; + _sheets = new ArrayList(INITIAL_CAPACITY); + names = new ArrayList(INITIAL_CAPACITY); + } public HSSFWorkbook(POIFSFileSystem fs) throws IOException { - this(fs,true); + this(fs,true); } /** @@ -275,7 +276,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm List records = RecordFactory.createRecords(stream); - workbook = Workbook.createWorkbook(records); + workbook = InternalWorkbook.createWorkbook(records); setPropertiesFromWorkbook(workbook); int recOffset = workbook.getNumRecords(); int sheetNum = 0; @@ -321,7 +322,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm * used internally to set the workbook properties. */ - private void setPropertiesFromWorkbook(Workbook book) + private void setPropertiesFromWorkbook(InternalWorkbook book) { this.workbook = book; @@ -1225,7 +1226,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm * @return byte[] array containing the binary representation of this workbook and all contained * sheets, rows, cells, etc. * - * @see org.apache.poi.hssf.model.Workbook + * @see org.apache.poi.hssf.model.InternalWorkbook * @see org.apache.poi.hssf.model.Sheet */ public byte[] getBytes() { @@ -1290,8 +1291,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm return workbook.getSSTString(index).getString(); } - protected Workbook getWorkbook() - { + InternalWorkbook getWorkbook() { return workbook; } diff --git a/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java index 2c56ea57a1..483a38d755 100644 --- a/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java +++ b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java @@ -27,7 +27,7 @@ import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.formula.Ptg; @@ -41,13 +41,13 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; public final class TestEventWorkbookBuilder extends TestCase { private MockHSSFListener mockListen; private SheetRecordCollectingListener listener; - + public void setUp() { HSSFRequest req = new HSSFRequest(); mockListen = new MockHSSFListener(); listener = new SheetRecordCollectingListener(mockListen); req.addListenerForAllRecords(listener); - + HSSFEventFactory factory = new HSSFEventFactory(); try { InputStream is = HSSFTestDataSamples.openSampleFileStream("3dFormulas.xls"); @@ -56,94 +56,94 @@ public final class TestEventWorkbookBuilder extends TestCase { } catch (IOException e) { throw new RuntimeException(e); } - } - + } + public void testBasics() { assertNotNull(listener.getSSTRecord()); assertNotNull(listener.getBoundSheetRecords()); assertNotNull(listener.getExternSheetRecords()); } - + public void testGetStubWorkbooks() { assertNotNull(listener.getStubWorkbook()); assertNotNull(listener.getStubHSSFWorkbook()); } - + public void testContents() { assertEquals(2, listener.getSSTRecord().getNumStrings()); assertEquals(3, listener.getBoundSheetRecords().length); assertEquals(1, listener.getExternSheetRecords().length); - + assertEquals(3, listener.getStubWorkbook().getNumSheets()); - - Workbook ref = listener.getStubWorkbook(); + + InternalWorkbook ref = listener.getStubWorkbook(); assertEquals("Sh3", ref.findSheetNameFromExternSheet(0)); assertEquals("Sheet1", ref.findSheetNameFromExternSheet(1)); assertEquals("S2", ref.findSheetNameFromExternSheet(2)); } - + public void testFormulas() { - + FormulaRecord[] fRecs = mockListen.getFormulaRecords(); - + // Check our formula records assertEquals(6, fRecs.length); - - Workbook stubWB = listener.getStubWorkbook(); + + InternalWorkbook stubWB = listener.getStubWorkbook(); assertNotNull(stubWB); HSSFWorkbook stubHSSF = listener.getStubHSSFWorkbook(); assertNotNull(stubHSSF); - + // Check these stubs have the right stuff on them assertEquals("Sheet1", stubWB.getSheetName(0)); assertEquals("S2", stubWB.getSheetName(1)); assertEquals("Sh3", stubWB.getSheetName(2)); - + // Check we can get the formula without breaking for(int i=0; i