0001: /* ====================================================================
0002: Licensed to the Apache Software Foundation (ASF) under one or more
0003: contributor license agreements. See the NOTICE file distributed with
0004: this work for additional information regarding copyright ownership.
0005: The ASF licenses this file to You under the Apache License, Version 2.0
0006: (the "License"); you may not use this file except in compliance with
0007: the License. You may obtain a copy of the License at
0008:
0009: http://www.apache.org/licenses/LICENSE-2.0
0010:
0011: Unless required by applicable law or agreed to in writing, software
0012: distributed under the License is distributed on an "AS IS" BASIS,
0013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: See the License for the specific language governing permissions and
0015: limitations under the License.
0016: ==================================================================== */
0017:
0018: package org.apache.poi.hssf.model;
0019:
0020: import org.apache.poi.ddf.*;
0021: import org.apache.poi.hssf.record.*;
0022: import org.apache.poi.hssf.util.HSSFColor;
0023: import org.apache.poi.hssf.util.SheetReferences;
0024: import org.apache.poi.util.POILogFactory;
0025: import org.apache.poi.util.POILogger;
0026:
0027: import java.util.ArrayList;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.Locale;
0031:
0032: /**
0033: * Low level model implementation of a Workbook. Provides creational methods
0034: * for settings and objects contained in the workbook object.
0035: * <P>
0036: * This file contains the low level binary records starting at the workbook's BOF and
0037: * ending with the workbook's EOF. Use HSSFWorkbook for a high level representation.
0038: * <P>
0039: * The structures of the highlevel API use references to this to perform most of their
0040: * operations. Its probably unwise to use these low level structures directly unless you
0041: * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's
0042: * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
0043: * before even attempting to use this.
0044: *
0045: *
0046: * @author Luc Girardin (luc dot girardin at macrofocus dot com)
0047: * @author Sergei Kozello (sergeikozello at mail.ru)
0048: * @author Shawn Laubach (slaubach at apache dot org) (Data Formats)
0049: * @author Andrew C. Oliver (acoliver at apache dot org)
0050: * @author Brian Sanders (bsanders at risklabs dot com) - custom palette
0051: * @author Dan Sherman (dsherman at isisph.com)
0052: * @author Glen Stampoultzis (glens at apache.org)
0053: * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
0054: * @version 1.0-pre
0055: */
0056:
0057: public class Workbook implements Model {
0058: private static final int DEBUG = POILogger.DEBUG;
0059:
0060: // public static Workbook currentBook = null;
0061:
0062: /**
0063: * constant used to set the "codepage" wherever "codepage" is set in records
0064: * (which is duplciated in more than one record)
0065: */
0066:
0067: private final static short CODEPAGE = (short) 0x4b0;
0068:
0069: /**
0070: * this contains the Worksheet record objects
0071: */
0072: protected WorkbookRecordList records = new WorkbookRecordList();
0073:
0074: /**
0075: * this contains a reference to the SSTRecord so that new stings can be added
0076: * to it.
0077: */
0078: protected SSTRecord sst = null;
0079:
0080: /**
0081: * Holds the Extern Sheet with references to bound sheets
0082: */
0083: protected ExternSheetRecord externSheet = null;
0084:
0085: /**
0086: * holds the "boundsheet" records (aka bundlesheet) so that they can have their
0087: * reference to their "BOF" marker
0088: */
0089: protected ArrayList boundsheets = new ArrayList();
0090:
0091: protected ArrayList formats = new ArrayList();
0092:
0093: protected ArrayList names = new ArrayList();
0094:
0095: protected int numxfs = 0; // hold the number of extended format records
0096: protected int numfonts = 0; // hold the number of font records
0097: private short maxformatid = -1; // holds the max format id
0098: private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
0099: private DrawingManager2 drawingManager;
0100: private List escherBSERecords = new ArrayList(); // EscherBSERecord
0101: private WindowOneRecord windowOne;
0102: private FileSharingRecord fileShare;
0103: private WriteAccessRecord writeAccess;
0104: private WriteProtectRecord writeProtect;
0105:
0106: private static POILogger log = POILogFactory
0107: .getLogger(Workbook.class);
0108:
0109: /**
0110: * Creates new Workbook with no intitialization --useless right now
0111: * @see #createWorkbook(List)
0112: */
0113: public Workbook() {
0114: }
0115:
0116: /**
0117: * read support for low level
0118: * API. Pass in an array of Record objects, A Workbook
0119: * object is constructed and passed back with all of its initialization set
0120: * to the passed in records and references to those records held. Unlike Sheet
0121: * workbook does not use an offset (its assumed to be 0) since its first in a file.
0122: * If you need an offset then construct a new array with a 0 offset or write your
0123: * own ;-p.
0124: *
0125: * @param recs an array of Record objects
0126: * @return Workbook object
0127: */
0128: public static Workbook createWorkbook(List recs) {
0129: if (log.check(POILogger.DEBUG))
0130: log.log(DEBUG, "Workbook (readfile) created with reclen=",
0131: new Integer(recs.size()));
0132: Workbook retval = new Workbook();
0133: ArrayList records = new ArrayList(recs.size() / 3);
0134:
0135: for (int k = 0; k < recs.size(); k++) {
0136: Record rec = (Record) recs.get(k);
0137:
0138: if (rec.getSid() == EOFRecord.sid) {
0139: records.add(rec);
0140: if (log.check(POILogger.DEBUG))
0141: log.log(DEBUG, "found workbook eof record at " + k);
0142: break;
0143: }
0144: switch (rec.getSid()) {
0145:
0146: case BoundSheetRecord.sid:
0147: if (log.check(POILogger.DEBUG))
0148: log.log(DEBUG, "found boundsheet record at " + k);
0149: retval.boundsheets.add(rec);
0150: retval.records.setBspos(k);
0151: break;
0152:
0153: case SSTRecord.sid:
0154: if (log.check(POILogger.DEBUG))
0155: log.log(DEBUG, "found sst record at " + k);
0156: retval.sst = (SSTRecord) rec;
0157: break;
0158:
0159: case FontRecord.sid:
0160: if (log.check(POILogger.DEBUG))
0161: log.log(DEBUG, "found font record at " + k);
0162: retval.records.setFontpos(k);
0163: retval.numfonts++;
0164: break;
0165:
0166: case ExtendedFormatRecord.sid:
0167: if (log.check(POILogger.DEBUG))
0168: log.log(DEBUG, "found XF record at " + k);
0169: retval.records.setXfpos(k);
0170: retval.numxfs++;
0171: break;
0172:
0173: case TabIdRecord.sid:
0174: if (log.check(POILogger.DEBUG))
0175: log.log(DEBUG, "found tabid record at " + k);
0176: retval.records.setTabpos(k);
0177: break;
0178:
0179: case ProtectRecord.sid:
0180: if (log.check(POILogger.DEBUG))
0181: log.log(DEBUG, "found protect record at " + k);
0182: retval.records.setProtpos(k);
0183: break;
0184:
0185: case BackupRecord.sid:
0186: if (log.check(POILogger.DEBUG))
0187: log.log(DEBUG, "found backup record at " + k);
0188: retval.records.setBackuppos(k);
0189: break;
0190: case ExternSheetRecord.sid:
0191: if (log.check(POILogger.DEBUG))
0192: log.log(DEBUG, "found extern sheet record at " + k);
0193: retval.externSheet = (ExternSheetRecord) rec;
0194: break;
0195: case NameRecord.sid:
0196: if (log.check(POILogger.DEBUG))
0197: log.log(DEBUG, "found name record at " + k);
0198: retval.names.add(rec);
0199: // retval.records.namepos = k;
0200: break;
0201: case SupBookRecord.sid:
0202: if (log.check(POILogger.DEBUG))
0203: log.log(DEBUG, "found SupBook record at " + k);
0204: // retval.records.supbookpos = k;
0205: break;
0206: case FormatRecord.sid:
0207: if (log.check(POILogger.DEBUG))
0208: log.log(DEBUG, "found format record at " + k);
0209: retval.formats.add(rec);
0210: retval.maxformatid = retval.maxformatid >= ((FormatRecord) rec)
0211: .getIndexCode() ? retval.maxformatid
0212: : ((FormatRecord) rec).getIndexCode();
0213: break;
0214: case DateWindow1904Record.sid:
0215: if (log.check(POILogger.DEBUG))
0216: log.log(DEBUG, "found datewindow1904 record at "
0217: + k);
0218: retval.uses1904datewindowing = ((DateWindow1904Record) rec)
0219: .getWindowing() == 1;
0220: break;
0221: case PaletteRecord.sid:
0222: if (log.check(POILogger.DEBUG))
0223: log.log(DEBUG, "found palette record at " + k);
0224: retval.records.setPalettepos(k);
0225: break;
0226: case WindowOneRecord.sid:
0227: if (log.check(POILogger.DEBUG))
0228: log.log(DEBUG, "found WindowOneRecord at " + k);
0229: retval.windowOne = (WindowOneRecord) rec;
0230: break;
0231: case WriteAccessRecord.sid:
0232: if (log.check(POILogger.DEBUG))
0233: log.log(DEBUG, "found WriteAccess at " + k);
0234: retval.writeAccess = (WriteAccessRecord) rec;
0235: break;
0236: case WriteProtectRecord.sid:
0237: if (log.check(POILogger.DEBUG))
0238: log.log(DEBUG, "found WriteProtect at " + k);
0239: retval.writeProtect = (WriteProtectRecord) rec;
0240: break;
0241: case FileSharingRecord.sid:
0242: if (log.check(POILogger.DEBUG))
0243: log.log(DEBUG, "found FileSharing at " + k);
0244: retval.fileShare = (FileSharingRecord) rec;
0245: default:
0246: }
0247: records.add(rec);
0248: }
0249: //What if we dont have any ranges and supbooks
0250: // if (retval.records.supbookpos == 0) {
0251: // retval.records.supbookpos = retval.records.bspos + 1;
0252: // retval.records.namepos = retval.records.supbookpos + 1;
0253: // }
0254:
0255: retval.records.setRecords(records);
0256:
0257: if (retval.windowOne == null) {
0258: retval.windowOne = (WindowOneRecord) retval
0259: .createWindowOne();
0260: }
0261: if (log.check(POILogger.DEBUG))
0262: log.log(DEBUG,
0263: "exit create workbook from existing file function");
0264: return retval;
0265: }
0266:
0267: /**
0268: * Creates an empty workbook object with three blank sheets and all the empty
0269: * fields. Use this to create a workbook from scratch.
0270: */
0271: public static Workbook createWorkbook() {
0272: if (log.check(POILogger.DEBUG))
0273: log.log(DEBUG, "creating new workbook from scratch");
0274: Workbook retval = new Workbook();
0275: ArrayList records = new ArrayList(30);
0276: ArrayList formats = new ArrayList(8);
0277:
0278: records.add(retval.createBOF());
0279: records.add(retval.createInterfaceHdr());
0280: records.add(retval.createMMS());
0281: records.add(retval.createInterfaceEnd());
0282: records.add(retval.createWriteAccess());
0283: records.add(retval.createCodepage());
0284: records.add(retval.createDSF());
0285: records.add(retval.createTabId());
0286: retval.records.setTabpos(records.size() - 1);
0287: records.add(retval.createFnGroupCount());
0288: records.add(retval.createWindowProtect());
0289: records.add(retval.createProtect());
0290: retval.records.setProtpos(records.size() - 1);
0291: records.add(retval.createPassword());
0292: records.add(retval.createProtectionRev4());
0293: records.add(retval.createPasswordRev4());
0294: retval.windowOne = (WindowOneRecord) retval.createWindowOne();
0295: records.add(retval.windowOne);
0296: records.add(retval.createBackup());
0297: retval.records.setBackuppos(records.size() - 1);
0298: records.add(retval.createHideObj());
0299: records.add(retval.createDateWindow1904());
0300: records.add(retval.createPrecision());
0301: records.add(retval.createRefreshAll());
0302: records.add(retval.createBookBool());
0303: records.add(retval.createFont());
0304: records.add(retval.createFont());
0305: records.add(retval.createFont());
0306: records.add(retval.createFont());
0307: retval.records.setFontpos(records.size() - 1); // last font record postion
0308: retval.numfonts = 4;
0309:
0310: // set up format records
0311: for (int i = 0; i <= 7; i++) {
0312: Record rec;
0313: rec = retval.createFormat(i);
0314: retval.maxformatid = retval.maxformatid >= ((FormatRecord) rec)
0315: .getIndexCode() ? retval.maxformatid
0316: : ((FormatRecord) rec).getIndexCode();
0317: formats.add(rec);
0318: records.add(rec);
0319: }
0320: retval.formats = formats;
0321:
0322: for (int k = 0; k < 21; k++) {
0323: records.add(retval.createExtendedFormat(k));
0324: retval.numxfs++;
0325: }
0326: retval.records.setXfpos(records.size() - 1);
0327: for (int k = 0; k < 6; k++) {
0328: records.add(retval.createStyle(k));
0329: }
0330: records.add(retval.createUseSelFS());
0331: for (int k = 0; k < 1; k++) { // now just do 1
0332: BoundSheetRecord bsr = (BoundSheetRecord) retval
0333: .createBoundSheet(k);
0334:
0335: records.add(bsr);
0336: retval.boundsheets.add(bsr);
0337: retval.records.setBspos(records.size() - 1);
0338: }
0339: // retval.records.supbookpos = retval.records.bspos + 1;
0340: // retval.records.namepos = retval.records.supbookpos + 2;
0341: records.add(retval.createCountry());
0342: retval.sst = (SSTRecord) retval.createSST();
0343: records.add(retval.sst);
0344: records.add(retval.createExtendedSST());
0345:
0346: records.add(retval.createEOF());
0347: retval.records.setRecords(records);
0348: if (log.check(POILogger.DEBUG))
0349: log.log(DEBUG, "exit create new workbook from scratch");
0350: return retval;
0351: }
0352:
0353: /**Retrieves the Builtin NameRecord that matches the name and index
0354: * There shouldn't be too many names to make the sequential search too slow
0355: * @param name byte representation of the builtin name to match
0356: * @param sheetIndex Index to match
0357: * @return null if no builtin NameRecord matches
0358: */
0359: public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) {
0360: Iterator iterator = names.iterator();
0361: while (iterator.hasNext()) {
0362: NameRecord record = (NameRecord) iterator.next();
0363:
0364: //print areas are one based
0365: if (record.getBuiltInName() == name
0366: && record.getIndexToSheet() == sheetIndex) {
0367: return record;
0368: }
0369: }
0370:
0371: return null;
0372:
0373: }
0374:
0375: /**
0376: * Removes the specified Builtin NameRecord that matches the name and index
0377: * @param name byte representation of the builtin to match
0378: * @param sheetIndex zero-based sheet reference
0379: */
0380: public void removeBuiltinRecord(byte name, int sheetIndex) {
0381: //the name array is smaller so searching through it should be faster than
0382: //using the findFirstXXXX methods
0383: NameRecord record = getSpecificBuiltinRecord(name, sheetIndex);
0384: if (record != null) {
0385: names.remove(record);
0386: }
0387:
0388: }
0389:
0390: public int getNumRecords() {
0391: return records.size();
0392: }
0393:
0394: /**
0395: * gets the font record at the given index in the font table. Remember
0396: * "There is No Four" (someone at M$ must have gone to Rocky Horror one too
0397: * many times)
0398: *
0399: * @param idx the index to look at (0 or greater but NOT 4)
0400: * @return FontRecord located at the given index
0401: */
0402:
0403: public FontRecord getFontRecordAt(int idx) {
0404: int index = idx;
0405:
0406: if (index > 4) {
0407: index -= 1; // adjust for "There is no 4"
0408: }
0409: if (index > (numfonts - 1)) {
0410: throw new ArrayIndexOutOfBoundsException("There are only "
0411: + numfonts + " font records, you asked for " + idx);
0412: }
0413: FontRecord retval = (FontRecord) records.get((records
0414: .getFontpos() - (numfonts - 1))
0415: + index);
0416:
0417: return retval;
0418: }
0419:
0420: /**
0421: * creates a new font record and adds it to the "font table". This causes the
0422: * boundsheets to move down one, extended formats to move down (so this function moves
0423: * those pointers as well)
0424: *
0425: * @return FontRecord that was just created
0426: */
0427:
0428: public FontRecord createNewFont() {
0429: FontRecord rec = (FontRecord) createFont();
0430:
0431: records.add(records.getFontpos() + 1, rec);
0432: records.setFontpos(records.getFontpos() + 1);
0433: numfonts++;
0434: return rec;
0435: }
0436:
0437: /**
0438: * gets the number of font records
0439: *
0440: * @return number of font records in the "font table"
0441: */
0442:
0443: public int getNumberOfFontRecords() {
0444: return numfonts;
0445: }
0446:
0447: /**
0448: * Sets the BOF for a given sheet
0449: *
0450: * @param sheetnum the number of the sheet to set the positing of the bof for
0451: * @param pos the actual bof position
0452: */
0453:
0454: public void setSheetBof(int sheetnum, int pos) {
0455: if (log.check(POILogger.DEBUG))
0456: log.log(DEBUG, "setting bof for sheetnum =", new Integer(
0457: sheetnum), " at pos=", new Integer(pos));
0458: checkSheets(sheetnum);
0459: ((BoundSheetRecord) boundsheets.get(sheetnum))
0460: .setPositionOfBof(pos);
0461: }
0462:
0463: /**
0464: * Returns the position of the backup record.
0465: */
0466:
0467: public BackupRecord getBackupRecord() {
0468: return (BackupRecord) records.get(records.getBackuppos());
0469: }
0470:
0471: /**
0472: * sets the name for a given sheet. If the boundsheet record doesn't exist and
0473: * its only one more than we have, go ahead and create it. If its > 1 more than
0474: * we have, except
0475: *
0476: * @param sheetnum the sheet number (0 based)
0477: * @param sheetname the name for the sheet
0478: */
0479: public void setSheetName(int sheetnum, String sheetname) {
0480: checkSheets(sheetnum);
0481: BoundSheetRecord sheet = (BoundSheetRecord) boundsheets
0482: .get(sheetnum);
0483: sheet.setSheetname(sheetname);
0484: sheet.setSheetnameLength((byte) sheetname.length());
0485: }
0486:
0487: /**
0488: * Determines whether a workbook contains the privided sheet name.
0489: *
0490: * @param name the name to test
0491: * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
0492: * @return true if the sheet contains the name, false otherwise.
0493: */
0494: public boolean doesContainsSheetName(String name,
0495: int excludeSheetIdx) {
0496: for (int i = 0; i < boundsheets.size(); i++) {
0497: BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets
0498: .get(i);
0499: if (excludeSheetIdx != i
0500: && name.equals(boundSheetRecord.getSheetname()))
0501: return true;
0502: }
0503: return false;
0504: }
0505:
0506: /**
0507: * sets the name for a given sheet forcing the encoding. This is STILL A BAD IDEA.
0508: * Poi now automatically detects unicode
0509: *
0510: *@deprecated 3-Jan-06 Simply use setSheetNam e(int sheetnum, String sheetname)
0511: * @param sheetnum the sheet number (0 based)
0512: * @param sheetname the name for the sheet
0513: */
0514: public void setSheetName(int sheetnum, String sheetname,
0515: short encoding) {
0516: checkSheets(sheetnum);
0517: BoundSheetRecord sheet = (BoundSheetRecord) boundsheets
0518: .get(sheetnum);
0519: sheet.setSheetname(sheetname);
0520: sheet.setSheetnameLength((byte) sheetname.length());
0521: sheet.setCompressedUnicodeFlag((byte) encoding);
0522: }
0523:
0524: /**
0525: * sets the order of appearance for a given sheet.
0526: *
0527: * @param sheetname the name of the sheet to reorder
0528: * @param pos the position that we want to insert the sheet into (0 based)
0529: */
0530:
0531: public void setSheetOrder(String sheetname, int pos) {
0532: int sheetNumber = getSheetIndex(sheetname);
0533: //remove the sheet that needs to be reordered and place it in the spot we want
0534: boundsheets.add(pos, boundsheets.remove(sheetNumber));
0535: }
0536:
0537: /**
0538: * gets the name for a given sheet.
0539: *
0540: * @param sheetnum the sheet number (0 based)
0541: * @return sheetname the name for the sheet
0542: */
0543:
0544: public String getSheetName(int sheetnum) {
0545: return ((BoundSheetRecord) boundsheets.get(sheetnum))
0546: .getSheetname();
0547: }
0548:
0549: /**
0550: * get the sheet's index
0551: * @param name sheet name
0552: * @return sheet index or -1 if it was not found.
0553: */
0554:
0555: public int getSheetIndex(String name) {
0556: int retval = -1;
0557:
0558: for (int k = 0; k < boundsheets.size(); k++) {
0559: String sheet = getSheetName(k);
0560:
0561: if (sheet.equalsIgnoreCase(name)) {
0562: retval = k;
0563: break;
0564: }
0565: }
0566: return retval;
0567: }
0568:
0569: /**
0570: * if we're trying to address one more sheet than we have, go ahead and add it! if we're
0571: * trying to address >1 more than we have throw an exception!
0572: */
0573:
0574: private void checkSheets(int sheetnum) {
0575: if ((boundsheets.size()) <= sheetnum) { // if we're short one add another..
0576: if ((boundsheets.size() + 1) <= sheetnum) {
0577: throw new RuntimeException(
0578: "Sheet number out of bounds!");
0579: }
0580: BoundSheetRecord bsr = (BoundSheetRecord) createBoundSheet(sheetnum);
0581:
0582: records.add(records.getBspos() + 1, bsr);
0583: records.setBspos(records.getBspos() + 1);
0584: boundsheets.add(bsr);
0585: fixTabIdRecord();
0586: }
0587: }
0588:
0589: public void removeSheet(int sheetnum) {
0590: if (boundsheets.size() > sheetnum) {
0591: records.remove(records.getBspos()
0592: - (boundsheets.size() - 1) + sheetnum);
0593: // records.bspos--;
0594: boundsheets.remove(sheetnum);
0595: fixTabIdRecord();
0596: }
0597: }
0598:
0599: /**
0600: * make the tabid record look like the current situation.
0601: *
0602: */
0603: private void fixTabIdRecord() {
0604: TabIdRecord tir = (TabIdRecord) records
0605: .get(records.getTabpos());
0606: short[] tia = new short[boundsheets.size()];
0607:
0608: for (short k = 0; k < tia.length; k++) {
0609: tia[k] = k;
0610: }
0611: tir.setTabIdArray(tia);
0612: }
0613:
0614: /**
0615: * returns the number of boundsheet objects contained in this workbook.
0616: *
0617: * @return number of BoundSheet records
0618: */
0619:
0620: public int getNumSheets() {
0621: if (log.check(POILogger.DEBUG))
0622: log.log(DEBUG, "getNumSheets=", new Integer(boundsheets
0623: .size()));
0624: return boundsheets.size();
0625: }
0626:
0627: /**
0628: * get the number of ExtendedFormat records contained in this workbook.
0629: *
0630: * @return int count of ExtendedFormat records
0631: */
0632:
0633: public int getNumExFormats() {
0634: if (log.check(POILogger.DEBUG))
0635: log.log(DEBUG, "getXF=", new Integer(numxfs));
0636: return numxfs;
0637: }
0638:
0639: /**
0640: * gets the ExtendedFormatRecord at the given 0-based index
0641: *
0642: * @param index of the Extended format record (0-based)
0643: * @return ExtendedFormatRecord at the given index
0644: */
0645:
0646: public ExtendedFormatRecord getExFormatAt(int index) {
0647: int xfptr = records.getXfpos() - (numxfs - 1);
0648:
0649: xfptr += index;
0650: ExtendedFormatRecord retval = (ExtendedFormatRecord) records
0651: .get(xfptr);
0652:
0653: return retval;
0654: }
0655:
0656: /**
0657: * creates a new Cell-type Extneded Format Record and adds it to the end of
0658: * ExtendedFormatRecords collection
0659: *
0660: * @return ExtendedFormatRecord that was created
0661: */
0662:
0663: public ExtendedFormatRecord createCellXF() {
0664: ExtendedFormatRecord xf = createExtendedFormat();
0665:
0666: records.add(records.getXfpos() + 1, xf);
0667: records.setXfpos(records.getXfpos() + 1);
0668: numxfs++;
0669: return xf;
0670: }
0671:
0672: /**
0673: * Adds a string to the SST table and returns its index (if its a duplicate
0674: * just returns its index and update the counts) ASSUMES compressed unicode
0675: * (meaning 8bit)
0676: *
0677: * @param string the string to be added to the SSTRecord
0678: *
0679: * @return index of the string within the SSTRecord
0680: */
0681:
0682: public int addSSTString(UnicodeString string) {
0683: if (log.check(POILogger.DEBUG))
0684: log.log(DEBUG, "insert to sst string='", string);
0685: if (sst == null) {
0686: insertSST();
0687: }
0688: return sst.addString(string);
0689: }
0690:
0691: /**
0692: * given an index into the SST table, this function returns the corresponding String value
0693: * @return String containing the SST String
0694: */
0695:
0696: public UnicodeString getSSTString(int str) {
0697: if (sst == null) {
0698: insertSST();
0699: }
0700: UnicodeString retval = sst.getString(str);
0701:
0702: if (log.check(POILogger.DEBUG))
0703: log.log(DEBUG, "Returning SST for index=",
0704: new Integer(str), " String= ", retval);
0705: return retval;
0706: }
0707:
0708: /**
0709: * use this function to add a Shared String Table to an existing sheet (say
0710: * generated by a different java api) without an sst....
0711: * @see #createSST()
0712: * @see org.apache.poi.hssf.record.SSTRecord
0713: */
0714:
0715: public void insertSST() {
0716: if (log.check(POILogger.DEBUG))
0717: log.log(DEBUG, "creating new SST via insertSST!");
0718: sst = (SSTRecord) createSST();
0719: records.add(records.size() - 1, createExtendedSST());
0720: records.add(records.size() - 2, sst);
0721: }
0722:
0723: /**
0724: * Serializes all records int the worksheet section into a big byte array. Use
0725: * this to write the Workbook out.
0726: *
0727: * @return byte array containing the HSSF-only portions of the POIFS file.
0728: */
0729: // GJS: Not used so why keep it.
0730: // public byte [] serialize() {
0731: // log.log(DEBUG, "Serializing Workbook!");
0732: // byte[] retval = null;
0733: //
0734: //// ArrayList bytes = new ArrayList(records.size());
0735: // int arraysize = getSize();
0736: // int pos = 0;
0737: //
0738: // retval = new byte[ arraysize ];
0739: // for (int k = 0; k < records.size(); k++) {
0740: //
0741: // Record record = records.get(k);
0742: //// Let's skip RECALCID records, as they are only use for optimization
0743: // if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
0744: // pos += record.serialize(pos, retval); // rec.length;
0745: // }
0746: // }
0747: // log.log(DEBUG, "Exiting serialize workbook");
0748: // return retval;
0749: // }
0750: /**
0751: * Serializes all records int the worksheet section into a big byte array. Use
0752: * this to write the Workbook out.
0753: * @param offset of the data to be written
0754: * @param data array of bytes to write this to
0755: */
0756:
0757: public int serialize(int offset, byte[] data) {
0758: if (log.check(POILogger.DEBUG))
0759: log.log(DEBUG, "Serializing Workbook with offsets");
0760:
0761: int pos = 0;
0762:
0763: SSTRecord sst = null;
0764: int sstPos = 0;
0765: boolean wroteBoundSheets = false;
0766: for (int k = 0; k < records.size(); k++) {
0767:
0768: Record record = records.get(k);
0769: // Let's skip RECALCID records, as they are only use for optimization
0770: if (record.getSid() != RecalcIdRecord.sid
0771: || ((RecalcIdRecord) record).isNeeded()) {
0772: int len = 0;
0773: if (record instanceof SSTRecord) {
0774: sst = (SSTRecord) record;
0775: sstPos = pos;
0776: }
0777: if (record.getSid() == ExtSSTRecord.sid && sst != null) {
0778: record = sst.createExtSSTRecord(sstPos + offset);
0779: }
0780: if (record instanceof BoundSheetRecord) {
0781: if (!wroteBoundSheets) {
0782: for (int i = 0; i < boundsheets.size(); i++) {
0783: len += ((BoundSheetRecord) boundsheets
0784: .get(i)).serialize(pos + offset
0785: + len, data);
0786: }
0787: wroteBoundSheets = true;
0788: }
0789: } else {
0790: len = record.serialize(pos + offset, data);
0791: }
0792: ///// DEBUG BEGIN /////
0793: // if (len != record.getRecordSize())
0794: // throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize());
0795: ///// DEBUG END /////
0796: pos += len; // rec.length;
0797: }
0798: }
0799: if (log.check(POILogger.DEBUG))
0800: log.log(DEBUG, "Exiting serialize workbook");
0801: return pos;
0802: }
0803:
0804: public int getSize() {
0805: int retval = 0;
0806:
0807: SSTRecord sst = null;
0808: for (int k = 0; k < records.size(); k++) {
0809: Record record = records.get(k);
0810: // Let's skip RECALCID records, as they are only use for optimization
0811: if (record.getSid() != RecalcIdRecord.sid
0812: || ((RecalcIdRecord) record).isNeeded()) {
0813: if (record instanceof SSTRecord)
0814: sst = (SSTRecord) record;
0815: if (record.getSid() == ExtSSTRecord.sid && sst != null)
0816: retval += sst.calcExtSSTRecordSize();
0817: else
0818: retval += record.getRecordSize();
0819: }
0820: }
0821: return retval;
0822: }
0823:
0824: /**
0825: * creates the BOF record
0826: * @see org.apache.poi.hssf.record.BOFRecord
0827: * @see org.apache.poi.hssf.record.Record
0828: * @return record containing a BOFRecord
0829: */
0830:
0831: protected Record createBOF() {
0832: BOFRecord retval = new BOFRecord();
0833:
0834: retval.setVersion((short) 0x600);
0835: retval.setType((short) 5);
0836: retval.setBuild((short) 0x10d3);
0837:
0838: // retval.setBuild((short)0x0dbb);
0839: retval.setBuildYear((short) 1996);
0840: retval.setHistoryBitMask(0x41); // was c1 before verify
0841: retval.setRequiredVersion(0x6);
0842: return retval;
0843: }
0844:
0845: /**
0846: * creates the InterfaceHdr record
0847: * @see org.apache.poi.hssf.record.InterfaceHdrRecord
0848: * @see org.apache.poi.hssf.record.Record
0849: * @return record containing a InterfaceHdrRecord
0850: */
0851:
0852: protected Record createInterfaceHdr() {
0853: InterfaceHdrRecord retval = new InterfaceHdrRecord();
0854:
0855: retval.setCodepage(CODEPAGE);
0856: return retval;
0857: }
0858:
0859: /**
0860: * creates an MMS record
0861: * @see org.apache.poi.hssf.record.MMSRecord
0862: * @see org.apache.poi.hssf.record.Record
0863: * @return record containing a MMSRecord
0864: */
0865:
0866: protected Record createMMS() {
0867: MMSRecord retval = new MMSRecord();
0868:
0869: retval.setAddMenuCount((byte) 0);
0870: retval.setDelMenuCount((byte) 0);
0871: return retval;
0872: }
0873:
0874: /**
0875: * creates the InterfaceEnd record
0876: * @see org.apache.poi.hssf.record.InterfaceEndRecord
0877: * @see org.apache.poi.hssf.record.Record
0878: * @return record containing a InterfaceEndRecord
0879: */
0880:
0881: protected Record createInterfaceEnd() {
0882: return new InterfaceEndRecord();
0883: }
0884:
0885: /**
0886: * creates the WriteAccess record containing the logged in user's name
0887: * @see org.apache.poi.hssf.record.WriteAccessRecord
0888: * @see org.apache.poi.hssf.record.Record
0889: * @return record containing a WriteAccessRecord
0890: */
0891:
0892: protected Record createWriteAccess() {
0893: WriteAccessRecord retval = new WriteAccessRecord();
0894:
0895: try {
0896: retval.setUsername(System.getProperty("user.name"));
0897: } catch (java.security.AccessControlException e) {
0898: // AccessControlException can occur in a restricted context
0899: // (client applet/jws application or restricted security server)
0900: retval.setUsername("POI");
0901: }
0902: return retval;
0903: }
0904:
0905: /**
0906: * creates the Codepage record containing the constant stored in CODEPAGE
0907: * @see org.apache.poi.hssf.record.CodepageRecord
0908: * @see org.apache.poi.hssf.record.Record
0909: * @return record containing a CodepageRecord
0910: */
0911:
0912: protected Record createCodepage() {
0913: CodepageRecord retval = new CodepageRecord();
0914:
0915: retval.setCodepage(CODEPAGE);
0916: return retval;
0917: }
0918:
0919: /**
0920: * creates the DSF record containing a 0 since HSSF can't even create Dual Stream Files
0921: * @see org.apache.poi.hssf.record.DSFRecord
0922: * @see org.apache.poi.hssf.record.Record
0923: * @return record containing a DSFRecord
0924: */
0925:
0926: protected Record createDSF() {
0927: DSFRecord retval = new DSFRecord();
0928:
0929: retval.setDsf((short) 0); // we don't even support double stream files
0930: return retval;
0931: }
0932:
0933: /**
0934: * creates the TabId record containing an array of 0,1,2. This release of HSSF
0935: * always has the default three sheets, no less, no more.
0936: * @see org.apache.poi.hssf.record.TabIdRecord
0937: * @see org.apache.poi.hssf.record.Record
0938: * @return record containing a TabIdRecord
0939: */
0940:
0941: protected Record createTabId() {
0942: TabIdRecord retval = new TabIdRecord();
0943: short[] tabidarray = { 0 };
0944:
0945: retval.setTabIdArray(tabidarray);
0946: return retval;
0947: }
0948:
0949: /**
0950: * creates the FnGroupCount record containing the Magic number constant of 14.
0951: * @see org.apache.poi.hssf.record.FnGroupCountRecord
0952: * @see org.apache.poi.hssf.record.Record
0953: * @return record containing a FnGroupCountRecord
0954: */
0955:
0956: protected Record createFnGroupCount() {
0957: FnGroupCountRecord retval = new FnGroupCountRecord();
0958:
0959: retval.setCount((short) 14);
0960: return retval;
0961: }
0962:
0963: /**
0964: * creates the WindowProtect record with protect set to false.
0965: * @see org.apache.poi.hssf.record.WindowProtectRecord
0966: * @see org.apache.poi.hssf.record.Record
0967: * @return record containing a WindowProtectRecord
0968: */
0969:
0970: protected Record createWindowProtect() {
0971: WindowProtectRecord retval = new WindowProtectRecord();
0972:
0973: retval.setProtect(false); // by default even when we support it we won't
0974: return retval; // want it to be protected
0975: }
0976:
0977: /**
0978: * creates the Protect record with protect set to false.
0979: * @see org.apache.poi.hssf.record.ProtectRecord
0980: * @see org.apache.poi.hssf.record.Record
0981: * @return record containing a ProtectRecord
0982: */
0983:
0984: protected Record createProtect() {
0985: ProtectRecord retval = new ProtectRecord();
0986:
0987: retval.setProtect(false); // by default even when we support it we won't
0988: return retval; // want it to be protected
0989: }
0990:
0991: /**
0992: * creates the Password record with password set to 0.
0993: * @see org.apache.poi.hssf.record.PasswordRecord
0994: * @see org.apache.poi.hssf.record.Record
0995: * @return record containing a PasswordRecord
0996: */
0997:
0998: protected Record createPassword() {
0999: PasswordRecord retval = new PasswordRecord();
1000:
1001: retval.setPassword((short) 0); // no password by default!
1002: return retval;
1003: }
1004:
1005: /**
1006: * creates the ProtectionRev4 record with protect set to false.
1007: * @see org.apache.poi.hssf.record.ProtectionRev4Record
1008: * @see org.apache.poi.hssf.record.Record
1009: * @return record containing a ProtectionRev4Record
1010: */
1011:
1012: protected Record createProtectionRev4() {
1013: ProtectionRev4Record retval = new ProtectionRev4Record();
1014:
1015: retval.setProtect(false);
1016: return retval;
1017: }
1018:
1019: /**
1020: * creates the PasswordRev4 record with password set to 0.
1021: * @see org.apache.poi.hssf.record.PasswordRev4Record
1022: * @see org.apache.poi.hssf.record.Record
1023: * @return record containing a PasswordRev4Record
1024: */
1025:
1026: protected Record createPasswordRev4() {
1027: PasswordRev4Record retval = new PasswordRev4Record();
1028:
1029: retval.setPassword((short) 0); // no password by default!
1030: return retval;
1031: }
1032:
1033: /**
1034: * creates the WindowOne record with the following magic values: <P>
1035: * horizontal hold - 0x168 <P>
1036: * vertical hold - 0x10e <P>
1037: * width - 0x3a5c <P>
1038: * height - 0x23be <P>
1039: * options - 0x38 <P>
1040: * selected tab - 0 <P>
1041: * displayed tab - 0 <P>
1042: * num selected tab- 0 <P>
1043: * tab width ratio - 0x258 <P>
1044: * @see org.apache.poi.hssf.record.WindowOneRecord
1045: * @see org.apache.poi.hssf.record.Record
1046: * @return record containing a WindowOneRecord
1047: */
1048:
1049: protected Record createWindowOne() {
1050: WindowOneRecord retval = new WindowOneRecord();
1051:
1052: retval.setHorizontalHold((short) 0x168);
1053: retval.setVerticalHold((short) 0x10e);
1054: retval.setWidth((short) 0x3a5c);
1055: retval.setHeight((short) 0x23be);
1056: retval.setOptions((short) 0x38);
1057: retval.setSelectedTab((short) 0x0);
1058: retval.setDisplayedTab((short) 0x0);
1059: retval.setNumSelectedTabs((short) 1);
1060: retval.setTabWidthRatio((short) 0x258);
1061: return retval;
1062: }
1063:
1064: /**
1065: * creates the Backup record with backup set to 0. (loose the data, who cares)
1066: * @see org.apache.poi.hssf.record.BackupRecord
1067: * @see org.apache.poi.hssf.record.Record
1068: * @return record containing a BackupRecord
1069: */
1070:
1071: protected Record createBackup() {
1072: BackupRecord retval = new BackupRecord();
1073:
1074: retval.setBackup((short) 0); // by default DONT save backups of files...just loose data
1075: return retval;
1076: }
1077:
1078: /**
1079: * creates the HideObj record with hide object set to 0. (don't hide)
1080: * @see org.apache.poi.hssf.record.HideObjRecord
1081: * @see org.apache.poi.hssf.record.Record
1082: * @return record containing a HideObjRecord
1083: */
1084:
1085: protected Record createHideObj() {
1086: HideObjRecord retval = new HideObjRecord();
1087:
1088: retval.setHideObj((short) 0); // by default set hide object off
1089: return retval;
1090: }
1091:
1092: /**
1093: * creates the DateWindow1904 record with windowing set to 0. (don't window)
1094: * @see org.apache.poi.hssf.record.DateWindow1904Record
1095: * @see org.apache.poi.hssf.record.Record
1096: * @return record containing a DateWindow1904Record
1097: */
1098:
1099: protected Record createDateWindow1904() {
1100: DateWindow1904Record retval = new DateWindow1904Record();
1101:
1102: retval.setWindowing((short) 0); // don't EVER use 1904 date windowing...tick tock..
1103: return retval;
1104: }
1105:
1106: /**
1107: * creates the Precision record with precision set to true. (full precision)
1108: * @see org.apache.poi.hssf.record.PrecisionRecord
1109: * @see org.apache.poi.hssf.record.Record
1110: * @return record containing a PrecisionRecord
1111: */
1112:
1113: protected Record createPrecision() {
1114: PrecisionRecord retval = new PrecisionRecord();
1115:
1116: retval.setFullPrecision(true); // always use real numbers in calculations!
1117: return retval;
1118: }
1119:
1120: /**
1121: * creates the RefreshAll record with refreshAll set to true. (refresh all calcs)
1122: * @see org.apache.poi.hssf.record.RefreshAllRecord
1123: * @see org.apache.poi.hssf.record.Record
1124: * @return record containing a RefreshAllRecord
1125: */
1126:
1127: protected Record createRefreshAll() {
1128: RefreshAllRecord retval = new RefreshAllRecord();
1129:
1130: retval.setRefreshAll(false);
1131: return retval;
1132: }
1133:
1134: /**
1135: * creates the BookBool record with saveLinkValues set to 0. (don't save link values)
1136: * @see org.apache.poi.hssf.record.BookBoolRecord
1137: * @see org.apache.poi.hssf.record.Record
1138: * @return record containing a BookBoolRecord
1139: */
1140:
1141: protected Record createBookBool() {
1142: BookBoolRecord retval = new BookBoolRecord();
1143:
1144: retval.setSaveLinkValues((short) 0);
1145: return retval;
1146: }
1147:
1148: /**
1149: * creates a Font record with the following magic values: <P>
1150: * fontheight = 0xc8<P>
1151: * attributes = 0x0<P>
1152: * color palette index = 0x7fff<P>
1153: * bold weight = 0x190<P>
1154: * Font Name Length = 5 <P>
1155: * Font Name = Arial <P>
1156: *
1157: * @see org.apache.poi.hssf.record.FontRecord
1158: * @see org.apache.poi.hssf.record.Record
1159: * @return record containing a FontRecord
1160: */
1161:
1162: protected Record createFont() {
1163: FontRecord retval = new FontRecord();
1164:
1165: retval.setFontHeight((short) 0xc8);
1166: retval.setAttributes((short) 0x0);
1167: retval.setColorPaletteIndex((short) 0x7fff);
1168: retval.setBoldWeight((short) 0x190);
1169: retval.setFontNameLength((byte) 5);
1170: retval.setFontName("Arial");
1171: return retval;
1172: }
1173:
1174: /**
1175: * Creates a FormatRecord object
1176: * @param id the number of the format record to create (meaning its position in
1177: * a file as M$ Excel would create it.)
1178: * @return record containing a FormatRecord
1179: * @see org.apache.poi.hssf.record.FormatRecord
1180: * @see org.apache.poi.hssf.record.Record
1181: */
1182:
1183: protected Record createFormat(int id) { // we'll need multiple editions for
1184: FormatRecord retval = new FormatRecord(); // the differnt formats
1185:
1186: switch (id) {
1187:
1188: case 0:
1189: retval.setIndexCode((short) 5);
1190: retval.setFormatStringLength((byte) 0x17);
1191: retval.setFormatString("\"$\"#,##0_);\\(\"$\"#,##0\\)");
1192: break;
1193:
1194: case 1:
1195: retval.setIndexCode((short) 6);
1196: retval.setFormatStringLength((byte) 0x1c);
1197: retval
1198: .setFormatString("\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)");
1199: break;
1200:
1201: case 2:
1202: retval.setIndexCode((short) 7);
1203: retval.setFormatStringLength((byte) 0x1d);
1204: retval
1205: .setFormatString("\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)");
1206: break;
1207:
1208: case 3:
1209: retval.setIndexCode((short) 8);
1210: retval.setFormatStringLength((byte) 0x22);
1211: retval
1212: .setFormatString("\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)");
1213: break;
1214:
1215: case 4:
1216: retval.setIndexCode((short) 0x2a);
1217: retval.setFormatStringLength((byte) 0x32);
1218: retval
1219: .setFormatString("_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)");
1220: break;
1221:
1222: case 5:
1223: retval.setIndexCode((short) 0x29);
1224: retval.setFormatStringLength((byte) 0x29);
1225: retval
1226: .setFormatString("_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)");
1227: break;
1228:
1229: case 6:
1230: retval.setIndexCode((short) 0x2c);
1231: retval.setFormatStringLength((byte) 0x3a);
1232: retval
1233: .setFormatString("_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)");
1234: break;
1235:
1236: case 7:
1237: retval.setIndexCode((short) 0x2b);
1238: retval.setFormatStringLength((byte) 0x31);
1239: retval
1240: .setFormatString("_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)");
1241: break;
1242: }
1243: return retval;
1244: }
1245:
1246: /**
1247: * Creates an ExtendedFormatRecord object
1248: * @param id the number of the extended format record to create (meaning its position in
1249: * a file as MS Excel would create it.)
1250: *
1251: * @return record containing an ExtendedFormatRecord
1252: * @see org.apache.poi.hssf.record.ExtendedFormatRecord
1253: * @see org.apache.poi.hssf.record.Record
1254: */
1255:
1256: protected Record createExtendedFormat(int id) { // we'll need multiple editions
1257: ExtendedFormatRecord retval = new ExtendedFormatRecord();
1258:
1259: switch (id) {
1260:
1261: case 0:
1262: retval.setFontIndex((short) 0);
1263: retval.setFormatIndex((short) 0);
1264: retval.setCellOptions((short) 0xfffffff5);
1265: retval.setAlignmentOptions((short) 0x20);
1266: retval.setIndentionOptions((short) 0);
1267: retval.setBorderOptions((short) 0);
1268: retval.setPaletteOptions((short) 0);
1269: retval.setAdtlPaletteOptions((short) 0);
1270: retval.setFillPaletteOptions((short) 0x20c0);
1271: break;
1272:
1273: case 1:
1274: retval.setFontIndex((short) 1);
1275: retval.setFormatIndex((short) 0);
1276: retval.setCellOptions((short) 0xfffffff5);
1277: retval.setAlignmentOptions((short) 0x20);
1278: retval.setIndentionOptions((short) 0xfffff400);
1279: retval.setBorderOptions((short) 0);
1280: retval.setPaletteOptions((short) 0);
1281: retval.setAdtlPaletteOptions((short) 0);
1282: retval.setFillPaletteOptions((short) 0x20c0);
1283: break;
1284:
1285: case 2:
1286: retval.setFontIndex((short) 1);
1287: retval.setFormatIndex((short) 0);
1288: retval.setCellOptions((short) 0xfffffff5);
1289: retval.setAlignmentOptions((short) 0x20);
1290: retval.setIndentionOptions((short) 0xfffff400);
1291: retval.setBorderOptions((short) 0);
1292: retval.setPaletteOptions((short) 0);
1293: retval.setAdtlPaletteOptions((short) 0);
1294: retval.setFillPaletteOptions((short) 0x20c0);
1295: break;
1296:
1297: case 3:
1298: retval.setFontIndex((short) 2);
1299: retval.setFormatIndex((short) 0);
1300: retval.setCellOptions((short) 0xfffffff5);
1301: retval.setAlignmentOptions((short) 0x20);
1302: retval.setIndentionOptions((short) 0xfffff400);
1303: retval.setBorderOptions((short) 0);
1304: retval.setPaletteOptions((short) 0);
1305: retval.setAdtlPaletteOptions((short) 0);
1306: retval.setFillPaletteOptions((short) 0x20c0);
1307: break;
1308:
1309: case 4:
1310: retval.setFontIndex((short) 2);
1311: retval.setFormatIndex((short) 0);
1312: retval.setCellOptions((short) 0xfffffff5);
1313: retval.setAlignmentOptions((short) 0x20);
1314: retval.setIndentionOptions((short) 0xfffff400);
1315: retval.setBorderOptions((short) 0);
1316: retval.setPaletteOptions((short) 0);
1317: retval.setAdtlPaletteOptions((short) 0);
1318: retval.setFillPaletteOptions((short) 0x20c0);
1319: break;
1320:
1321: case 5:
1322: retval.setFontIndex((short) 0);
1323: retval.setFormatIndex((short) 0);
1324: retval.setCellOptions((short) 0xfffffff5);
1325: retval.setAlignmentOptions((short) 0x20);
1326: retval.setIndentionOptions((short) 0xfffff400);
1327: retval.setBorderOptions((short) 0);
1328: retval.setPaletteOptions((short) 0);
1329: retval.setAdtlPaletteOptions((short) 0);
1330: retval.setFillPaletteOptions((short) 0x20c0);
1331: break;
1332:
1333: case 6:
1334: retval.setFontIndex((short) 0);
1335: retval.setFormatIndex((short) 0);
1336: retval.setCellOptions((short) 0xfffffff5);
1337: retval.setAlignmentOptions((short) 0x20);
1338: retval.setIndentionOptions((short) 0xfffff400);
1339: retval.setBorderOptions((short) 0);
1340: retval.setPaletteOptions((short) 0);
1341: retval.setAdtlPaletteOptions((short) 0);
1342: retval.setFillPaletteOptions((short) 0x20c0);
1343: break;
1344:
1345: case 7:
1346: retval.setFontIndex((short) 0);
1347: retval.setFormatIndex((short) 0);
1348: retval.setCellOptions((short) 0xfffffff5);
1349: retval.setAlignmentOptions((short) 0x20);
1350: retval.setIndentionOptions((short) 0xfffff400);
1351: retval.setBorderOptions((short) 0);
1352: retval.setPaletteOptions((short) 0);
1353: retval.setAdtlPaletteOptions((short) 0);
1354: retval.setFillPaletteOptions((short) 0x20c0);
1355: break;
1356:
1357: case 8:
1358: retval.setFontIndex((short) 0);
1359: retval.setFormatIndex((short) 0);
1360: retval.setCellOptions((short) 0xfffffff5);
1361: retval.setAlignmentOptions((short) 0x20);
1362: retval.setIndentionOptions((short) 0xfffff400);
1363: retval.setBorderOptions((short) 0);
1364: retval.setPaletteOptions((short) 0);
1365: retval.setAdtlPaletteOptions((short) 0);
1366: retval.setFillPaletteOptions((short) 0x20c0);
1367: break;
1368:
1369: case 9:
1370: retval.setFontIndex((short) 0);
1371: retval.setFormatIndex((short) 0);
1372: retval.setCellOptions((short) 0xfffffff5);
1373: retval.setAlignmentOptions((short) 0x20);
1374: retval.setIndentionOptions((short) 0xfffff400);
1375: retval.setBorderOptions((short) 0);
1376: retval.setPaletteOptions((short) 0);
1377: retval.setAdtlPaletteOptions((short) 0);
1378: retval.setFillPaletteOptions((short) 0x20c0);
1379: break;
1380:
1381: case 10:
1382: retval.setFontIndex((short) 0);
1383: retval.setFormatIndex((short) 0);
1384: retval.setCellOptions((short) 0xfffffff5);
1385: retval.setAlignmentOptions((short) 0x20);
1386: retval.setIndentionOptions((short) 0xfffff400);
1387: retval.setBorderOptions((short) 0);
1388: retval.setPaletteOptions((short) 0);
1389: retval.setAdtlPaletteOptions((short) 0);
1390: retval.setFillPaletteOptions((short) 0x20c0);
1391: break;
1392:
1393: case 11:
1394: retval.setFontIndex((short) 0);
1395: retval.setFormatIndex((short) 0);
1396: retval.setCellOptions((short) 0xfffffff5);
1397: retval.setAlignmentOptions((short) 0x20);
1398: retval.setIndentionOptions((short) 0xfffff400);
1399: retval.setBorderOptions((short) 0);
1400: retval.setPaletteOptions((short) 0);
1401: retval.setAdtlPaletteOptions((short) 0);
1402: retval.setFillPaletteOptions((short) 0x20c0);
1403: break;
1404:
1405: case 12:
1406: retval.setFontIndex((short) 0);
1407: retval.setFormatIndex((short) 0);
1408: retval.setCellOptions((short) 0xfffffff5);
1409: retval.setAlignmentOptions((short) 0x20);
1410: retval.setIndentionOptions((short) 0xfffff400);
1411: retval.setBorderOptions((short) 0);
1412: retval.setPaletteOptions((short) 0);
1413: retval.setAdtlPaletteOptions((short) 0);
1414: retval.setFillPaletteOptions((short) 0x20c0);
1415: break;
1416:
1417: case 13:
1418: retval.setFontIndex((short) 0);
1419: retval.setFormatIndex((short) 0);
1420: retval.setCellOptions((short) 0xfffffff5);
1421: retval.setAlignmentOptions((short) 0x20);
1422: retval.setIndentionOptions((short) 0xfffff400);
1423: retval.setBorderOptions((short) 0);
1424: retval.setPaletteOptions((short) 0);
1425: retval.setAdtlPaletteOptions((short) 0);
1426: retval.setFillPaletteOptions((short) 0x20c0);
1427: break;
1428:
1429: case 14:
1430: retval.setFontIndex((short) 0);
1431: retval.setFormatIndex((short) 0);
1432: retval.setCellOptions((short) 0xfffffff5);
1433: retval.setAlignmentOptions((short) 0x20);
1434: retval.setIndentionOptions((short) 0xfffff400);
1435: retval.setBorderOptions((short) 0);
1436: retval.setPaletteOptions((short) 0);
1437: retval.setAdtlPaletteOptions((short) 0);
1438: retval.setFillPaletteOptions((short) 0x20c0);
1439: break;
1440:
1441: // cell records
1442: case 15:
1443: retval.setFontIndex((short) 0);
1444: retval.setFormatIndex((short) 0);
1445: retval.setCellOptions((short) 0x1);
1446: retval.setAlignmentOptions((short) 0x20);
1447: retval.setIndentionOptions((short) 0x0);
1448: retval.setBorderOptions((short) 0);
1449: retval.setPaletteOptions((short) 0);
1450: retval.setAdtlPaletteOptions((short) 0);
1451: retval.setFillPaletteOptions((short) 0x20c0);
1452: break;
1453:
1454: // style
1455: case 16:
1456: retval.setFontIndex((short) 1);
1457: retval.setFormatIndex((short) 0x2b);
1458: retval.setCellOptions((short) 0xfffffff5);
1459: retval.setAlignmentOptions((short) 0x20);
1460: retval.setIndentionOptions((short) 0xfffff800);
1461: retval.setBorderOptions((short) 0);
1462: retval.setPaletteOptions((short) 0);
1463: retval.setAdtlPaletteOptions((short) 0);
1464: retval.setFillPaletteOptions((short) 0x20c0);
1465: break;
1466:
1467: case 17:
1468: retval.setFontIndex((short) 1);
1469: retval.setFormatIndex((short) 0x29);
1470: retval.setCellOptions((short) 0xfffffff5);
1471: retval.setAlignmentOptions((short) 0x20);
1472: retval.setIndentionOptions((short) 0xfffff800);
1473: retval.setBorderOptions((short) 0);
1474: retval.setPaletteOptions((short) 0);
1475: retval.setAdtlPaletteOptions((short) 0);
1476: retval.setFillPaletteOptions((short) 0x20c0);
1477: break;
1478:
1479: case 18:
1480: retval.setFontIndex((short) 1);
1481: retval.setFormatIndex((short) 0x2c);
1482: retval.setCellOptions((short) 0xfffffff5);
1483: retval.setAlignmentOptions((short) 0x20);
1484: retval.setIndentionOptions((short) 0xfffff800);
1485: retval.setBorderOptions((short) 0);
1486: retval.setPaletteOptions((short) 0);
1487: retval.setAdtlPaletteOptions((short) 0);
1488: retval.setFillPaletteOptions((short) 0x20c0);
1489: break;
1490:
1491: case 19:
1492: retval.setFontIndex((short) 1);
1493: retval.setFormatIndex((short) 0x2a);
1494: retval.setCellOptions((short) 0xfffffff5);
1495: retval.setAlignmentOptions((short) 0x20);
1496: retval.setIndentionOptions((short) 0xfffff800);
1497: retval.setBorderOptions((short) 0);
1498: retval.setPaletteOptions((short) 0);
1499: retval.setAdtlPaletteOptions((short) 0);
1500: retval.setFillPaletteOptions((short) 0x20c0);
1501: break;
1502:
1503: case 20:
1504: retval.setFontIndex((short) 1);
1505: retval.setFormatIndex((short) 0x9);
1506: retval.setCellOptions((short) 0xfffffff5);
1507: retval.setAlignmentOptions((short) 0x20);
1508: retval.setIndentionOptions((short) 0xfffff800);
1509: retval.setBorderOptions((short) 0);
1510: retval.setPaletteOptions((short) 0);
1511: retval.setAdtlPaletteOptions((short) 0);
1512: retval.setFillPaletteOptions((short) 0x20c0);
1513: break;
1514:
1515: // unused from this point down
1516: case 21:
1517: retval.setFontIndex((short) 5);
1518: retval.setFormatIndex((short) 0x0);
1519: retval.setCellOptions((short) 0x1);
1520: retval.setAlignmentOptions((short) 0x20);
1521: retval.setIndentionOptions((short) 0x800);
1522: retval.setBorderOptions((short) 0);
1523: retval.setPaletteOptions((short) 0);
1524: retval.setAdtlPaletteOptions((short) 0);
1525: retval.setFillPaletteOptions((short) 0x20c0);
1526: break;
1527:
1528: case 22:
1529: retval.setFontIndex((short) 6);
1530: retval.setFormatIndex((short) 0x0);
1531: retval.setCellOptions((short) 0x1);
1532: retval.setAlignmentOptions((short) 0x20);
1533: retval.setIndentionOptions((short) 0x5c00);
1534: retval.setBorderOptions((short) 0);
1535: retval.setPaletteOptions((short) 0);
1536: retval.setAdtlPaletteOptions((short) 0);
1537: retval.setFillPaletteOptions((short) 0x20c0);
1538: break;
1539:
1540: case 23:
1541: retval.setFontIndex((short) 0);
1542: retval.setFormatIndex((short) 0x31);
1543: retval.setCellOptions((short) 0x1);
1544: retval.setAlignmentOptions((short) 0x20);
1545: retval.setIndentionOptions((short) 0x5c00);
1546: retval.setBorderOptions((short) 0);
1547: retval.setPaletteOptions((short) 0);
1548: retval.setAdtlPaletteOptions((short) 0);
1549: retval.setFillPaletteOptions((short) 0x20c0);
1550: break;
1551:
1552: case 24:
1553: retval.setFontIndex((short) 0);
1554: retval.setFormatIndex((short) 0x8);
1555: retval.setCellOptions((short) 0x1);
1556: retval.setAlignmentOptions((short) 0x20);
1557: retval.setIndentionOptions((short) 0x5c00);
1558: retval.setBorderOptions((short) 0);
1559: retval.setPaletteOptions((short) 0);
1560: retval.setAdtlPaletteOptions((short) 0);
1561: retval.setFillPaletteOptions((short) 0x20c0);
1562: break;
1563:
1564: case 25:
1565: retval.setFontIndex((short) 6);
1566: retval.setFormatIndex((short) 0x8);
1567: retval.setCellOptions((short) 0x1);
1568: retval.setAlignmentOptions((short) 0x20);
1569: retval.setIndentionOptions((short) 0x5c00);
1570: retval.setBorderOptions((short) 0);
1571: retval.setPaletteOptions((short) 0);
1572: retval.setAdtlPaletteOptions((short) 0);
1573: retval.setFillPaletteOptions((short) 0x20c0);
1574: break;
1575: }
1576: return retval;
1577: }
1578:
1579: /**
1580: * creates an default cell type ExtendedFormatRecord object.
1581: * @return ExtendedFormatRecord with intial defaults (cell-type)
1582: */
1583:
1584: protected ExtendedFormatRecord createExtendedFormat() {
1585: ExtendedFormatRecord retval = new ExtendedFormatRecord();
1586:
1587: retval.setFontIndex((short) 0);
1588: retval.setFormatIndex((short) 0x0);
1589: retval.setCellOptions((short) 0x1);
1590: retval.setAlignmentOptions((short) 0x20);
1591: retval.setIndentionOptions((short) 0);
1592: retval.setBorderOptions((short) 0);
1593: retval.setPaletteOptions((short) 0);
1594: retval.setAdtlPaletteOptions((short) 0);
1595: retval.setFillPaletteOptions((short) 0x20c0);
1596: retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index);
1597: retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index);
1598: retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index);
1599: retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index);
1600: return retval;
1601: }
1602:
1603: /**
1604: * Creates a StyleRecord object
1605: * @param id the number of the style record to create (meaning its position in
1606: * a file as MS Excel would create it.
1607: * @return record containing a StyleRecord
1608: * @see org.apache.poi.hssf.record.StyleRecord
1609: * @see org.apache.poi.hssf.record.Record
1610: */
1611:
1612: protected Record createStyle(int id) { // we'll need multiple editions
1613: StyleRecord retval = new StyleRecord();
1614:
1615: switch (id) {
1616:
1617: case 0:
1618: retval.setIndex((short) 0xffff8010);
1619: retval.setBuiltin((byte) 3);
1620: retval.setOutlineStyleLevel((byte) 0xffffffff);
1621: break;
1622:
1623: case 1:
1624: retval.setIndex((short) 0xffff8011);
1625: retval.setBuiltin((byte) 6);
1626: retval.setOutlineStyleLevel((byte) 0xffffffff);
1627: break;
1628:
1629: case 2:
1630: retval.setIndex((short) 0xffff8012);
1631: retval.setBuiltin((byte) 4);
1632: retval.setOutlineStyleLevel((byte) 0xffffffff);
1633: break;
1634:
1635: case 3:
1636: retval.setIndex((short) 0xffff8013);
1637: retval.setBuiltin((byte) 7);
1638: retval.setOutlineStyleLevel((byte) 0xffffffff);
1639: break;
1640:
1641: case 4:
1642: retval.setIndex((short) 0xffff8000);
1643: retval.setBuiltin((byte) 0);
1644: retval.setOutlineStyleLevel((byte) 0xffffffff);
1645: break;
1646:
1647: case 5:
1648: retval.setIndex((short) 0xffff8014);
1649: retval.setBuiltin((byte) 5);
1650: retval.setOutlineStyleLevel((byte) 0xffffffff);
1651: break;
1652: }
1653: return retval;
1654: }
1655:
1656: /**
1657: * Creates a palette record initialized to the default palette
1658: * @return a PaletteRecord instance populated with the default colors
1659: * @see org.apache.poi.hssf.record.PaletteRecord
1660: */
1661: protected PaletteRecord createPalette() {
1662: return new PaletteRecord();
1663: }
1664:
1665: /**
1666: * Creates the UseSelFS object with the use natural language flag set to 0 (false)
1667: * @return record containing a UseSelFSRecord
1668: * @see org.apache.poi.hssf.record.UseSelFSRecord
1669: * @see org.apache.poi.hssf.record.Record
1670: */
1671:
1672: protected Record createUseSelFS() {
1673: UseSelFSRecord retval = new UseSelFSRecord();
1674:
1675: retval.setFlag((short) 0);
1676: return retval;
1677: }
1678:
1679: /**
1680: * create a "bound sheet" or "bundlesheet" (depending who you ask) record
1681: * Always sets the sheet's bof to 0. You'll need to set that yourself.
1682: * @param id either sheet 0,1 or 2.
1683: * @return record containing a BoundSheetRecord
1684: * @see org.apache.poi.hssf.record.BoundSheetRecord
1685: * @see org.apache.poi.hssf.record.Record
1686: */
1687:
1688: protected Record createBoundSheet(int id) { // 1,2,3 sheets
1689: BoundSheetRecord retval = new BoundSheetRecord();
1690:
1691: switch (id) {
1692:
1693: case 0:
1694: retval.setPositionOfBof(0x0); // should be set later
1695: retval.setOptionFlags((short) 0);
1696: retval.setSheetnameLength((byte) 0x6);
1697: retval.setCompressedUnicodeFlag((byte) 0);
1698: retval.setSheetname("Sheet1");
1699: break;
1700:
1701: case 1:
1702: retval.setPositionOfBof(0x0); // should be set later
1703: retval.setOptionFlags((short) 0);
1704: retval.setSheetnameLength((byte) 0x6);
1705: retval.setCompressedUnicodeFlag((byte) 0);
1706: retval.setSheetname("Sheet2");
1707: break;
1708:
1709: case 2:
1710: retval.setPositionOfBof(0x0); // should be set later
1711: retval.setOptionFlags((short) 0);
1712: retval.setSheetnameLength((byte) 0x6);
1713: retval.setCompressedUnicodeFlag((byte) 0);
1714: retval.setSheetname("Sheet3");
1715: break;
1716: }
1717: return retval;
1718: }
1719:
1720: /**
1721: * Creates the Country record with the default country set to 1
1722: * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise
1723: * @return record containing a CountryRecord
1724: * @see org.apache.poi.hssf.record.CountryRecord
1725: * @see org.apache.poi.hssf.record.Record
1726: */
1727:
1728: protected Record createCountry() { // what a novel idea, create your own!
1729: CountryRecord retval = new CountryRecord();
1730:
1731: retval.setDefaultCountry((short) 1);
1732:
1733: // from Russia with love ;)
1734: if (Locale.getDefault().toString().equals("ru_RU")) {
1735: retval.setCurrentCountry((short) 7);
1736: } else {
1737: retval.setCurrentCountry((short) 1);
1738: }
1739:
1740: return retval;
1741: }
1742:
1743: /**
1744: * Creates the SST record with no strings and the unique/num string set to 0
1745: * @return record containing a SSTRecord
1746: * @see org.apache.poi.hssf.record.SSTRecord
1747: * @see org.apache.poi.hssf.record.Record
1748: */
1749:
1750: protected Record createSST() {
1751: return new SSTRecord();
1752: }
1753:
1754: /**
1755: * Creates the ExtendedSST record with numstrings per bucket set to 0x8. HSSF
1756: * doesn't yet know what to do with this thing, but we create it with nothing in
1757: * it hardly just to make Excel happy and our sheets look like Excel's
1758: *
1759: * @return record containing an ExtSSTRecord
1760: * @see org.apache.poi.hssf.record.ExtSSTRecord
1761: * @see org.apache.poi.hssf.record.Record
1762: */
1763:
1764: protected Record createExtendedSST() {
1765: ExtSSTRecord retval = new ExtSSTRecord();
1766:
1767: retval.setNumStringsPerBucket((short) 0x8);
1768: return retval;
1769: }
1770:
1771: /**
1772: * creates the EOF record
1773: * @see org.apache.poi.hssf.record.EOFRecord
1774: * @see org.apache.poi.hssf.record.Record
1775: * @return record containing a EOFRecord
1776: */
1777:
1778: protected Record createEOF() {
1779: return new EOFRecord();
1780: }
1781:
1782: public SheetReferences getSheetReferences() {
1783: SheetReferences refs = new SheetReferences();
1784:
1785: if (externSheet != null) {
1786: for (int k = 0; k < externSheet.getNumOfREFStructures(); k++) {
1787:
1788: String sheetName = findSheetNameFromExternSheet((short) k);
1789: refs.addSheetReference(sheetName, k);
1790:
1791: }
1792: }
1793: return refs;
1794: }
1795:
1796: /** finds the sheet name by his extern sheet index
1797: * @param num extern sheet index
1798: * @return sheet name
1799: */
1800: public String findSheetNameFromExternSheet(short num) {
1801: String result = "";
1802:
1803: short indexToSheet = externSheet.getREFRecordAt(num)
1804: .getIndexToFirstSupBook();
1805: if (indexToSheet > -1) { //error check, bail out gracefully!
1806: result = getSheetName(indexToSheet);
1807: }
1808:
1809: return result;
1810: }
1811:
1812: /**
1813: * Finds the sheet index for a particular external sheet number.
1814: * @param externSheetNumber The external sheet number to convert
1815: * @return The index to the sheet found.
1816: */
1817: public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
1818: if (externSheetNumber >= externSheet.getNumOfREFStructures())
1819: return -1;
1820: else
1821: return externSheet.getREFRecordAt(externSheetNumber)
1822: .getIndexToFirstSupBook();
1823: }
1824:
1825: /** returns the extern sheet number for specific sheet number ,
1826: * if this sheet doesn't exist in extern sheet , add it
1827: * @param sheetNumber sheet number
1828: * @return index to extern sheet
1829: */
1830: public short checkExternSheet(int sheetNumber) {
1831:
1832: int i = 0;
1833: boolean flag = false;
1834: short result = 0;
1835:
1836: if (externSheet == null) {
1837: externSheet = createExternSheet();
1838: }
1839:
1840: //Trying to find reference to this sheet
1841: while (i < externSheet.getNumOfREFStructures() && !flag) {
1842: ExternSheetSubRecord record = externSheet.getREFRecordAt(i);
1843:
1844: if (record.getIndexToFirstSupBook() == sheetNumber
1845: && record.getIndexToLastSupBook() == sheetNumber) {
1846: flag = true;
1847: result = (short) i;
1848: }
1849:
1850: ++i;
1851: }
1852:
1853: //We Havent found reference to this sheet
1854: if (!flag) {
1855: result = addSheetIndexToExternSheet((short) sheetNumber);
1856: }
1857:
1858: return result;
1859: }
1860:
1861: private short addSheetIndexToExternSheet(short sheetNumber) {
1862: short result;
1863:
1864: ExternSheetSubRecord record = new ExternSheetSubRecord();
1865: record.setIndexToFirstSupBook(sheetNumber);
1866: record.setIndexToLastSupBook(sheetNumber);
1867: externSheet.addREFRecord(record);
1868: externSheet.setNumOfREFStructures((short) (externSheet
1869: .getNumOfREFStructures() + 1));
1870: result = (short) (externSheet.getNumOfREFStructures() - 1);
1871:
1872: return result;
1873: }
1874:
1875: /** gets the total number of names
1876: * @return number of names
1877: */
1878: public int getNumNames() {
1879: int result = names.size();
1880:
1881: return result;
1882: }
1883:
1884: /** gets the name record
1885: * @param index name index
1886: * @return name record
1887: */
1888: public NameRecord getNameRecord(int index) {
1889: NameRecord result = (NameRecord) names.get(index);
1890:
1891: return result;
1892:
1893: }
1894:
1895: /** creates new name
1896: * @return new name record
1897: */
1898: public NameRecord createName() {
1899:
1900: NameRecord name = new NameRecord();
1901:
1902: // Not the most efficient way but the other way was causing too many bugs
1903: int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
1904: if (idx == -1)
1905: idx = findFirstRecordLocBySid(SupBookRecord.sid);
1906: if (idx == -1)
1907: idx = findFirstRecordLocBySid(CountryRecord.sid);
1908:
1909: records.add(idx + names.size() + 1, name);
1910: names.add(name);
1911:
1912: return name;
1913: }
1914:
1915: /** creates new name
1916: * @return new name record
1917: */
1918: public NameRecord addName(NameRecord name) {
1919: // Not the most efficient way but the other way was causing too many bugs
1920: int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
1921: if (idx == -1)
1922: idx = findFirstRecordLocBySid(SupBookRecord.sid);
1923: if (idx == -1)
1924: idx = findFirstRecordLocBySid(CountryRecord.sid);
1925: records.add(idx + names.size() + 1, name);
1926: names.add(name);
1927:
1928: return name;
1929: }
1930:
1931: /**Generates a NameRecord to represent a built-in region
1932: * @return a new NameRecord unless the index is invalid
1933: */
1934: public NameRecord createBuiltInName(byte builtInName, int index) {
1935: if (index == -1 || index + 1 > (int) Short.MAX_VALUE)
1936: throw new IllegalArgumentException("Index is not valid ["
1937: + index + "]");
1938:
1939: NameRecord name = new NameRecord(builtInName, (short) (index));
1940:
1941: addName(name);
1942:
1943: return name;
1944: }
1945:
1946: /** removes the name
1947: * @param namenum name index
1948: */
1949: public void removeName(int namenum) {
1950: if (names.size() > namenum) {
1951: int idx = findFirstRecordLocBySid(NameRecord.sid);
1952: records.remove(idx + namenum);
1953: names.remove(namenum);
1954: }
1955:
1956: }
1957:
1958: /** creates a new extern sheet record
1959: * @return the new extern sheet record
1960: */
1961: protected ExternSheetRecord createExternSheet() {
1962: ExternSheetRecord externSheet = new ExternSheetRecord();
1963:
1964: int idx = findFirstRecordLocBySid(CountryRecord.sid);
1965:
1966: records.add(idx + 1, externSheet);
1967: // records.add(records.supbookpos + 1 , rec);
1968:
1969: //We also adds the supBook for internal reference
1970: SupBookRecord supbook = new SupBookRecord();
1971:
1972: supbook.setNumberOfSheets((short) getNumSheets());
1973: //supbook.setFlag();
1974:
1975: records.add(idx + 1, supbook);
1976: // records.add(records.supbookpos + 1 , supbook);
1977:
1978: return externSheet;
1979: }
1980:
1981: /**
1982: * Returns a format index that matches the passed in format. It does not tie into HSSFDataFormat.
1983: * @param format the format string
1984: * @param createIfNotFound creates a new format if format not found
1985: * @return the format id of a format that matches or -1 if none found and createIfNotFound
1986: */
1987: public short getFormat(String format, boolean createIfNotFound) {
1988: Iterator iterator;
1989: for (iterator = formats.iterator(); iterator.hasNext();) {
1990: FormatRecord r = (FormatRecord) iterator.next();
1991: if (r.getFormatString().equals(format)) {
1992: return r.getIndexCode();
1993: }
1994: }
1995:
1996: if (createIfNotFound) {
1997: return createFormat(format);
1998: }
1999:
2000: return -1;
2001: }
2002:
2003: /**
2004: * Returns the list of FormatRecords in the workbook.
2005: * @return ArrayList of FormatRecords in the notebook
2006: */
2007: public ArrayList getFormats() {
2008: return formats;
2009: }
2010:
2011: /**
2012: * Creates a FormatRecord, inserts it, and returns the index code.
2013: * @param format the format string
2014: * @return the index code of the format record.
2015: * @see org.apache.poi.hssf.record.FormatRecord
2016: * @see org.apache.poi.hssf.record.Record
2017: */
2018: public short createFormat(String format) {
2019: // ++xfpos; //These are to ensure that positions are updated properly
2020: // ++palettepos;
2021: // ++bspos;
2022: FormatRecord rec = new FormatRecord();
2023: maxformatid = maxformatid >= (short) 0xa4 ? (short) (maxformatid + 1)
2024: : (short) 0xa4; //Starting value from M$ empiracle study.
2025: rec.setIndexCode(maxformatid);
2026: rec.setFormatStringLength((byte) format.length());
2027: rec.setFormatString(format);
2028:
2029: int pos = 0;
2030: while (pos < records.size()
2031: && records.get(pos).getSid() != FormatRecord.sid)
2032: pos++;
2033: pos += formats.size();
2034: formats.add(rec);
2035: records.add(pos, rec);
2036: return maxformatid;
2037: }
2038:
2039: /**
2040: * Returns the first occurance of a record matching a particular sid.
2041: */
2042: public Record findFirstRecordBySid(short sid) {
2043: for (Iterator iterator = records.iterator(); iterator.hasNext();) {
2044: Record record = (Record) iterator.next();
2045:
2046: if (record.getSid() == sid) {
2047: return record;
2048: }
2049: }
2050: return null;
2051: }
2052:
2053: /**
2054: * Returns the index of a record matching a particular sid.
2055: * @param sid The sid of the record to match
2056: * @return The index of -1 if no match made.
2057: */
2058: public int findFirstRecordLocBySid(short sid) {
2059: int index = 0;
2060: for (Iterator iterator = records.iterator(); iterator.hasNext();) {
2061: Record record = (Record) iterator.next();
2062:
2063: if (record.getSid() == sid) {
2064: return index;
2065: }
2066: index++;
2067: }
2068: return -1;
2069: }
2070:
2071: /**
2072: * Returns the next occurance of a record matching a particular sid.
2073: */
2074: public Record findNextRecordBySid(short sid, int pos) {
2075: int matches = 0;
2076: for (Iterator iterator = records.iterator(); iterator.hasNext();) {
2077: Record record = (Record) iterator.next();
2078:
2079: if (record.getSid() == sid) {
2080: if (matches++ == pos)
2081: return record;
2082: }
2083: }
2084: return null;
2085: }
2086:
2087: public List getRecords() {
2088: return records.getRecords();
2089: }
2090:
2091: // public void insertChartRecords( List chartRecords )
2092: // {
2093: // backuppos += chartRecords.size();
2094: // fontpos += chartRecords.size();
2095: // palettepos += chartRecords.size();
2096: // bspos += chartRecords.size();
2097: // xfpos += chartRecords.size();
2098: //
2099: // records.addAll(protpos, chartRecords);
2100: // }
2101:
2102: /**
2103: * Whether date windowing is based on 1/2/1904 or 1/1/1900.
2104: * Some versions of Excel (Mac) can save workbooks using 1904 date windowing.
2105: *
2106: * @return true if using 1904 date windowing
2107: */
2108: public boolean isUsing1904DateWindowing() {
2109: return uses1904datewindowing;
2110: }
2111:
2112: /**
2113: * Returns the custom palette in use for this workbook; if a custom palette record
2114: * does not exist, then it is created.
2115: */
2116: public PaletteRecord getCustomPalette() {
2117: PaletteRecord palette;
2118: int palettePos = records.getPalettepos();
2119: if (palettePos != -1) {
2120: Record rec = records.get(palettePos);
2121: if (rec instanceof PaletteRecord) {
2122: palette = (PaletteRecord) rec;
2123: } else
2124: throw new RuntimeException(
2125: "InternalError: Expected PaletteRecord but got a '"
2126: + rec + "'");
2127: } else {
2128: palette = createPalette();
2129: //Add the palette record after the bof which is always the first record
2130: records.add(1, palette);
2131: records.setPalettepos(1);
2132: }
2133: return palette;
2134: }
2135:
2136: /**
2137: * Creates a drawing group record. If it already exists then it's modified.
2138: */
2139: public void createDrawingGroup() {
2140:
2141: if (drawingManager == null) {
2142: EscherContainerRecord dggContainer = new EscherContainerRecord();
2143: EscherDggRecord dgg = new EscherDggRecord();
2144: EscherOptRecord opt = new EscherOptRecord();
2145: EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord();
2146:
2147: dggContainer.setRecordId((short) 0xF000);
2148: dggContainer.setOptions((short) 0x000F);
2149: dgg.setRecordId(EscherDggRecord.RECORD_ID);
2150: dgg.setOptions((short) 0x0000);
2151: dgg.setShapeIdMax(1024);
2152: dgg.setNumShapesSaved(0);
2153: dgg.setDrawingsSaved(0);
2154: dgg
2155: .setFileIdClusters(new EscherDggRecord.FileIdCluster[] {});
2156: drawingManager = new DrawingManager2(dgg);
2157: EscherContainerRecord bstoreContainer = null;
2158: if (escherBSERecords.size() > 0) {
2159: bstoreContainer = new EscherContainerRecord();
2160: bstoreContainer
2161: .setRecordId(EscherContainerRecord.BSTORE_CONTAINER);
2162: bstoreContainer.setOptions((short) ((escherBSERecords
2163: .size() << 4) | 0xF));
2164: for (Iterator iterator = escherBSERecords.iterator(); iterator
2165: .hasNext();) {
2166: EscherRecord escherRecord = (EscherRecord) iterator
2167: .next();
2168: bstoreContainer.addChildRecord(escherRecord);
2169: }
2170: }
2171: opt.setRecordId((short) 0xF00B);
2172: opt.setOptions((short) 0x0033);
2173: opt.addEscherProperty(new EscherBoolProperty(
2174: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE,
2175: 524296));
2176: opt.addEscherProperty(new EscherRGBProperty(
2177: EscherProperties.FILL__FILLCOLOR, 0x08000041));
2178: opt.addEscherProperty(new EscherRGBProperty(
2179: EscherProperties.LINESTYLE__COLOR, 134217792));
2180: splitMenuColors.setRecordId((short) 0xF11E);
2181: splitMenuColors.setOptions((short) 0x0040);
2182: splitMenuColors.setColor1(0x0800000D);
2183: splitMenuColors.setColor2(0x0800000C);
2184: splitMenuColors.setColor3(0x08000017);
2185: splitMenuColors.setColor4(0x100000F7);
2186:
2187: dggContainer.addChildRecord(dgg);
2188: if (bstoreContainer != null)
2189: dggContainer.addChildRecord(bstoreContainer);
2190: dggContainer.addChildRecord(opt);
2191: dggContainer.addChildRecord(splitMenuColors);
2192:
2193: int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
2194: if (dgLoc == -1) {
2195: DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
2196: drawingGroup.addEscherRecord(dggContainer);
2197: int loc = findFirstRecordLocBySid(CountryRecord.sid);
2198:
2199: getRecords().add(loc + 1, drawingGroup);
2200: } else {
2201: DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
2202: drawingGroup.addEscherRecord(dggContainer);
2203: getRecords().set(dgLoc, drawingGroup);
2204: }
2205:
2206: }
2207:
2208: }
2209:
2210: public WindowOneRecord getWindowOne() {
2211: return windowOne;
2212: }
2213:
2214: public EscherBSERecord getBSERecord(int pictureIndex) {
2215: return (EscherBSERecord) escherBSERecords.get(pictureIndex - 1);
2216: }
2217:
2218: public int addBSERecord(EscherBSERecord e) {
2219: createDrawingGroup();
2220:
2221: // maybe we don't need that as an instance variable anymore
2222: escherBSERecords.add(e);
2223:
2224: int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
2225: DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords()
2226: .get(dgLoc);
2227:
2228: EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup
2229: .getEscherRecord(0);
2230: EscherContainerRecord bstoreContainer;
2231: if (dggContainer.getChild(1).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER) {
2232: bstoreContainer = (EscherContainerRecord) dggContainer
2233: .getChild(1);
2234: } else {
2235: bstoreContainer = new EscherContainerRecord();
2236: bstoreContainer
2237: .setRecordId(EscherContainerRecord.BSTORE_CONTAINER);
2238: dggContainer.getChildRecords().add(1, bstoreContainer);
2239: }
2240: bstoreContainer
2241: .setOptions((short) ((escherBSERecords.size() << 4) | 0xF));
2242:
2243: bstoreContainer.addChildRecord(e);
2244:
2245: return escherBSERecords.size();
2246: }
2247:
2248: public DrawingManager2 getDrawingManager() {
2249: return drawingManager;
2250: }
2251:
2252: public WriteProtectRecord getWriteProtect() {
2253: if (this .writeProtect == null) {
2254: this .writeProtect = new WriteProtectRecord();
2255: int i = 0;
2256: for (i = 0; i < records.size()
2257: && !(records.get(i) instanceof BOFRecord); i++) {
2258: }
2259: records.add(i + 1, this .writeProtect);
2260: }
2261: return this .writeProtect;
2262: }
2263:
2264: public WriteAccessRecord getWriteAccess() {
2265: if (this .writeAccess == null) {
2266: this .writeAccess = (WriteAccessRecord) createWriteAccess();
2267: int i = 0;
2268: for (i = 0; i < records.size()
2269: && !(records.get(i) instanceof InterfaceEndRecord); i++) {
2270: }
2271: records.add(i + 1, this .writeAccess);
2272: }
2273: return this .writeAccess;
2274: }
2275:
2276: public FileSharingRecord getFileSharing() {
2277: if (this .fileShare == null) {
2278: this .fileShare = new FileSharingRecord();
2279: int i = 0;
2280: for (i = 0; i < records.size()
2281: && !(records.get(i) instanceof WriteAccessRecord); i++) {
2282: }
2283: records.add(i + 1, this .fileShare);
2284: }
2285: return this .fileShare;
2286: }
2287:
2288: /**
2289: * protect a workbook with a password (not encypted, just sets writeprotect
2290: * flags and the password.
2291: * @param password to set
2292: */
2293: public void writeProtectWorkbook(String password, String username) {
2294: int protIdx = -1;
2295: FileSharingRecord frec = getFileSharing();
2296: WriteAccessRecord waccess = getWriteAccess();
2297: WriteProtectRecord wprotect = getWriteProtect();
2298: frec.setReadOnly((short) 1);
2299: frec.setPassword(FileSharingRecord.hashPassword(password));
2300: frec.setUsername(username);
2301: waccess.setUsername(username);
2302: }
2303:
2304: /**
2305: * removes the write protect flag
2306: */
2307: public void unwriteProtectWorkbook() {
2308: records.remove(fileShare);
2309: records.remove(writeProtect);
2310: fileShare = null;
2311: writeProtect = null;
2312: }
2313:
2314: }
|