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: /*
0019: * HSSFWorkbook.java
0020: *
0021: * Created on September 30, 2001, 3:37 PM
0022: */
0023: package org.apache.poi.hssf.usermodel;
0024:
0025: import org.apache.poi.POIDocument;
0026: import org.apache.poi.ddf.EscherBSERecord;
0027: import org.apache.poi.ddf.EscherBitmapBlip;
0028: import org.apache.poi.ddf.EscherRecord;
0029: import org.apache.poi.ddf.EscherBlipRecord;
0030: import org.apache.poi.hssf.eventmodel.EventRecordFactory;
0031: import org.apache.poi.hssf.model.Sheet;
0032: import org.apache.poi.hssf.model.Workbook;
0033: import org.apache.poi.hssf.record.*;
0034: import org.apache.poi.hssf.record.formula.Area3DPtg;
0035: import org.apache.poi.hssf.record.formula.MemFuncPtg;
0036: import org.apache.poi.hssf.record.formula.UnionPtg;
0037: import org.apache.poi.hssf.util.CellReference;
0038: import org.apache.poi.poifs.filesystem.*;
0039: import org.apache.poi.util.POILogFactory;
0040: import org.apache.poi.util.POILogger;
0041:
0042: import java.io.ByteArrayInputStream;
0043: import java.io.FileNotFoundException;
0044: import java.io.IOException;
0045: import java.io.InputStream;
0046: import java.io.OutputStream;
0047: import java.io.PrintWriter;
0048: import java.util.ArrayList;
0049: import java.util.Iterator;
0050: import java.util.List;
0051: import java.util.Stack;
0052:
0053: /**
0054: * High level representation of a workbook. This is the first object most users
0055: * will construct whether they are reading or writing a workbook. It is also the
0056: * top level object for creating new sheets/etc.
0057: *
0058: * @see org.apache.poi.hssf.model.Workbook
0059: * @see org.apache.poi.hssf.usermodel.HSSFSheet
0060: * @author Andrew C. Oliver (acoliver at apache dot org)
0061: * @author Glen Stampoultzis (glens at apache.org)
0062: * @author Shawn Laubach (slaubach at apache dot org)
0063: * @version 2.0-pre
0064: */
0065:
0066: public class HSSFWorkbook extends POIDocument {
0067: private static final int DEBUG = POILogger.DEBUG;
0068:
0069: /**
0070: * used for compile-time performance/memory optimization. This determines the
0071: * initial capacity for the sheet collection. Its currently set to 3.
0072: * Changing it in this release will decrease performance
0073: * since you're never allowed to have more or less than three sheets!
0074: */
0075:
0076: public final static int INITIAL_CAPACITY = 3;
0077:
0078: /**
0079: * this is the reference to the low level Workbook object
0080: */
0081:
0082: private Workbook workbook;
0083:
0084: /**
0085: * this holds the HSSFSheet objects attached to this workbook
0086: */
0087:
0088: protected ArrayList sheets;
0089:
0090: /**
0091: * this holds the HSSFName objects attached to this workbook
0092: */
0093:
0094: private ArrayList names;
0095:
0096: /**
0097: * holds whether or not to preserve other nodes in the POIFS. Used
0098: * for macros and embedded objects.
0099: */
0100: private boolean preserveNodes;
0101:
0102: /**
0103: * Used to keep track of the data formatter so that all
0104: * createDataFormatter calls return the same one for a given
0105: * book. This ensures that updates from one places is visible
0106: * someplace else.
0107: */
0108: private HSSFDataFormat formatter;
0109:
0110: /** Extended windows meta file */
0111: public static final int PICTURE_TYPE_EMF = 2;
0112: /** Windows Meta File */
0113: public static final int PICTURE_TYPE_WMF = 3;
0114: /** Mac PICT format */
0115: public static final int PICTURE_TYPE_PICT = 4;
0116: /** JPEG format */
0117: public static final int PICTURE_TYPE_JPEG = 5;
0118: /** PNG format */
0119: public static final int PICTURE_TYPE_PNG = 6;
0120: /** Device independant bitmap */
0121: public static final int PICTURE_TYPE_DIB = 7;
0122:
0123: private static POILogger log = POILogFactory
0124: .getLogger(HSSFWorkbook.class);
0125:
0126: /**
0127: * Creates new HSSFWorkbook from scratch (start here!)
0128: *
0129: */
0130: public HSSFWorkbook() {
0131: this (Workbook.createWorkbook());
0132: }
0133:
0134: protected HSSFWorkbook(Workbook book) {
0135: workbook = book;
0136: sheets = new ArrayList(INITIAL_CAPACITY);
0137: names = new ArrayList(INITIAL_CAPACITY);
0138: }
0139:
0140: public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
0141: this (fs, true);
0142: }
0143:
0144: /**
0145: * given a POI POIFSFileSystem object, read in its Workbook and populate the high and
0146: * low level models. If you're reading in a workbook...start here.
0147: *
0148: * @param fs the POI filesystem that contains the Workbook stream.
0149: * @param preserveNodes whether to preseve other nodes, such as
0150: * macros. This takes more memory, so only say yes if you
0151: * need to. If set, will store all of the POIFSFileSystem
0152: * in memory
0153: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
0154: * @exception IOException if the stream cannot be read
0155: */
0156:
0157: public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes)
0158: throws IOException {
0159: this .preserveNodes = preserveNodes;
0160:
0161: // Read in the HPSF properties
0162: this .filesystem = fs;
0163: readProperties();
0164:
0165: // If we're not preserving nodes, don't track the
0166: // POIFS any more
0167: if (!preserveNodes) {
0168: this .filesystem = null;
0169: }
0170:
0171: sheets = new ArrayList(INITIAL_CAPACITY);
0172: names = new ArrayList(INITIAL_CAPACITY);
0173:
0174: // Normally, the Workbook will be in a POIFS Stream
0175: // called "Workbook". However, some wierd XLS generators
0176: // put theirs in one called "WORKBOOK"
0177: String workbookName = "Workbook";
0178: try {
0179: fs.getRoot().getEntry(workbookName);
0180: // Is the default name
0181: } catch (FileNotFoundException fe) {
0182: // Try the upper case form
0183: try {
0184: workbookName = "WORKBOOK";
0185: fs.getRoot().getEntry(workbookName);
0186: } catch (FileNotFoundException wfe) {
0187: // Doesn't contain it in either form
0188: throw new IllegalArgumentException(
0189: "The supplied POIFSFileSystem contained neither a 'Workbook' entry, nor a 'WORKBOOK' entry. Is it really an excel file?");
0190: }
0191: }
0192:
0193: // Grab the data from the workbook stream, however
0194: // it happens to be spelt.
0195: InputStream stream = fs.createDocumentInputStream(workbookName);
0196:
0197: EventRecordFactory factory = new EventRecordFactory();
0198:
0199: List records = RecordFactory.createRecords(stream);
0200:
0201: workbook = Workbook.createWorkbook(records);
0202: setPropertiesFromWorkbook(workbook);
0203: int recOffset = workbook.getNumRecords();
0204: int sheetNum = 0;
0205:
0206: // convert all LabelRecord records to LabelSSTRecord
0207: convertLabelRecords(records, recOffset);
0208: while (recOffset < records.size()) {
0209: Sheet sheet = Sheet.createSheet(records, sheetNum++,
0210: recOffset);
0211:
0212: recOffset = sheet.getEofLoc() + 1;
0213: if (recOffset == 1) {
0214: break;
0215: }
0216:
0217: HSSFSheet hsheet = new HSSFSheet(this , sheet);
0218:
0219: sheets.add(hsheet);
0220:
0221: // workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
0222: }
0223:
0224: for (int i = 0; i < workbook.getNumNames(); ++i) {
0225: HSSFName name = new HSSFName(workbook, workbook
0226: .getNameRecord(i));
0227: names.add(name);
0228: }
0229: }
0230:
0231: public HSSFWorkbook(InputStream s) throws IOException {
0232: this (s, true);
0233: }
0234:
0235: /**
0236: * Companion to HSSFWorkbook(POIFSFileSystem), this constructs the POI filesystem around your
0237: * inputstream.
0238: *
0239: * @param s the POI filesystem that contains the Workbook stream.
0240: * @param preserveNodes whether to preseve other nodes, such as
0241: * macros. This takes more memory, so only say yes if you
0242: * need to.
0243: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
0244: * @see #HSSFWorkbook(POIFSFileSystem)
0245: * @exception IOException if the stream cannot be read
0246: */
0247:
0248: public HSSFWorkbook(InputStream s, boolean preserveNodes)
0249: throws IOException {
0250: this (new POIFSFileSystem(s), preserveNodes);
0251: }
0252:
0253: /**
0254: * used internally to set the workbook properties.
0255: */
0256:
0257: private void setPropertiesFromWorkbook(Workbook book) {
0258: this .workbook = book;
0259:
0260: // none currently
0261: }
0262:
0263: /**
0264: * This is basically a kludge to deal with the now obsolete Label records. If
0265: * you have to read in a sheet that contains Label records, be aware that the rest
0266: * of the API doesn't deal with them, the low level structure only provides read-only
0267: * semi-immutable structures (the sets are there for interface conformance with NO
0268: * impelmentation). In short, you need to call this function passing it a reference
0269: * to the Workbook object. All labels will be converted to LabelSST records and their
0270: * contained strings will be written to the Shared String tabel (SSTRecord) within
0271: * the Workbook.
0272: *
0273: * @param wb sheet's matching low level Workbook structure containing the SSTRecord.
0274: * @see org.apache.poi.hssf.record.LabelRecord
0275: * @see org.apache.poi.hssf.record.LabelSSTRecord
0276: * @see org.apache.poi.hssf.record.SSTRecord
0277: */
0278:
0279: private void convertLabelRecords(List records, int offset) {
0280: if (log.check(POILogger.DEBUG))
0281: log.log(POILogger.DEBUG, "convertLabelRecords called");
0282: for (int k = offset; k < records.size(); k++) {
0283: Record rec = (Record) records.get(k);
0284:
0285: if (rec.getSid() == LabelRecord.sid) {
0286: LabelRecord oldrec = (LabelRecord) rec;
0287:
0288: records.remove(k);
0289: LabelSSTRecord newrec = new LabelSSTRecord();
0290: int stringid = workbook.addSSTString(new UnicodeString(
0291: oldrec.getValue()));
0292:
0293: newrec.setRow(oldrec.getRow());
0294: newrec.setColumn(oldrec.getColumn());
0295: newrec.setXFIndex(oldrec.getXFIndex());
0296: newrec.setSSTIndex(stringid);
0297: records.add(k, newrec);
0298: }
0299: }
0300: if (log.check(POILogger.DEBUG))
0301: log.log(POILogger.DEBUG, "convertLabelRecords exit");
0302: }
0303:
0304: /**
0305: * sets the order of appearance for a given sheet.
0306: *
0307: * @param sheetname the name of the sheet to reorder
0308: * @param pos the position that we want to insert the sheet into (0 based)
0309: */
0310:
0311: public void setSheetOrder(String sheetname, int pos) {
0312: sheets.add(pos, sheets.remove(getSheetIndex(sheetname)));
0313: workbook.setSheetOrder(sheetname, pos);
0314: }
0315:
0316: /**
0317: * sets the tab whose data is actually seen when the sheet is opened.
0318: * This may be different from the "selected sheet" since excel seems to
0319: * allow you to show the data of one sheet when another is seen "selected"
0320: * in the tabs (at the bottom).
0321: * @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
0322: * @param index
0323: */
0324: public void setSelectedTab(short index) {
0325: workbook.getWindowOne().setSelectedTab(index);
0326: }
0327:
0328: /**
0329: * gets the tab whose data is actually seen when the sheet is opened.
0330: * This may be different from the "selected sheet" since excel seems to
0331: * allow you to show the data of one sheet when another is seen "selected"
0332: * in the tabs (at the bottom).
0333: * @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
0334: */
0335: public short getSelectedTab() {
0336: return workbook.getWindowOne().getSelectedTab();
0337: }
0338:
0339: /**
0340: * sets the first tab that is displayed in the list of tabs
0341: * in excel.
0342: * @param index
0343: */
0344: public void setDisplayedTab(short index) {
0345: workbook.getWindowOne().setDisplayedTab(index);
0346: }
0347:
0348: /**
0349: * sets the first tab that is displayed in the list of tabs
0350: * in excel.
0351: */
0352: public short getDisplayedTab() {
0353: return workbook.getWindowOne().getDisplayedTab();
0354: }
0355:
0356: /**
0357: * @deprecated POI will now properly handle unicode strings without
0358: * forceing an encoding
0359: */
0360: public final static byte ENCODING_COMPRESSED_UNICODE = 0;
0361: /**
0362: * @deprecated POI will now properly handle unicode strings without
0363: * forceing an encoding
0364: */
0365: public final static byte ENCODING_UTF_16 = 1;
0366:
0367: /**
0368: * set the sheet name.
0369: * Will throw IllegalArgumentException if the name is greater than 31 chars
0370: * or contains /\?*[]
0371: * @param sheet number (0 based)
0372: */
0373: public void setSheetName(int sheet, String name) {
0374: if (workbook.doesContainsSheetName(name, sheet))
0375: throw new IllegalArgumentException(
0376: "The workbook already contains a sheet with this name");
0377:
0378: if (sheet > (sheets.size() - 1)) {
0379: throw new RuntimeException("Sheet out of bounds");
0380: }
0381:
0382: workbook.setSheetName(sheet, name);
0383: }
0384:
0385: /**
0386: * set the sheet name forcing the encoding. Forcing the encoding IS A BAD IDEA!!!
0387: * @deprecated 3-Jan-2006 POI now automatically detects unicode and sets the encoding
0388: * appropriately. Simply use setSheetName(int sheet, String encoding)
0389: * @throws IllegalArgumentException if the name is greater than 31 chars
0390: * or contains /\?*[]
0391: * @param sheet number (0 based)
0392: */
0393: public void setSheetName(int sheet, String name, short encoding) {
0394: if (workbook.doesContainsSheetName(name, sheet))
0395: throw new IllegalArgumentException(
0396: "The workbook already contains a sheet with this name");
0397:
0398: if (sheet > (sheets.size() - 1)) {
0399: throw new RuntimeException("Sheet out of bounds");
0400: }
0401:
0402: switch (encoding) {
0403: case ENCODING_COMPRESSED_UNICODE:
0404: case ENCODING_UTF_16:
0405: break;
0406:
0407: default:
0408: // TODO java.io.UnsupportedEncodingException
0409: throw new RuntimeException("Unsupported encoding");
0410: }
0411:
0412: workbook.setSheetName(sheet, name, encoding);
0413: }
0414:
0415: /**
0416: * get the sheet name
0417: * @param sheet Number
0418: * @return Sheet name
0419: */
0420:
0421: public String getSheetName(int sheet) {
0422: if (sheet > (sheets.size() - 1)) {
0423: throw new RuntimeException("Sheet out of bounds");
0424: }
0425: return workbook.getSheetName(sheet);
0426: }
0427:
0428: /*
0429: * get the sheet's index
0430: * @param name sheet name
0431: * @return sheet index or -1 if it was not found.
0432: */
0433:
0434: /** Returns the index of the sheet by his name
0435: * @param name the sheet name
0436: * @return index of the sheet (0 based)
0437: */
0438: public int getSheetIndex(String name) {
0439: int retval = workbook.getSheetIndex(name);
0440:
0441: return retval;
0442: }
0443:
0444: /** Returns the index of the given sheet
0445: * @param sheet the sheet to look up
0446: * @return index of the sheet (0 based)
0447: */
0448: public int getSheetIndex(HSSFSheet sheet) {
0449: for (int i = 0; i < sheets.size(); i++) {
0450: if (sheets.get(i) == sheet) {
0451: return i;
0452: }
0453: }
0454: return -1;
0455: }
0456:
0457: /**
0458: * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns
0459: * the high level representation. Use this to create new sheets.
0460: *
0461: * @return HSSFSheet representing the new sheet.
0462: */
0463:
0464: public HSSFSheet createSheet() {
0465:
0466: // if (getNumberOfSheets() == 3)
0467: // throw new RuntimeException("You cannot have more than three sheets in HSSF 1.0");
0468: HSSFSheet sheet = new HSSFSheet(this );
0469:
0470: sheets.add(sheet);
0471: workbook.setSheetName(sheets.size() - 1, "Sheet"
0472: + (sheets.size() - 1));
0473: WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet()
0474: .findFirstRecordBySid(WindowTwoRecord.sid);
0475: windowTwo.setSelected(sheets.size() == 1);
0476: windowTwo.setPaged(sheets.size() == 1);
0477: return sheet;
0478: }
0479:
0480: /**
0481: * create an HSSFSheet from an existing sheet in the HSSFWorkbook.
0482: *
0483: * @return HSSFSheet representing the cloned sheet.
0484: */
0485:
0486: public HSSFSheet cloneSheet(int sheetNum) {
0487: HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
0488: String srcName = workbook.getSheetName(sheetNum);
0489: if (srcSheet != null) {
0490: HSSFSheet clonedSheet = srcSheet.cloneSheet(this );
0491: WindowTwoRecord windowTwo = (WindowTwoRecord) clonedSheet
0492: .getSheet().findFirstRecordBySid(
0493: WindowTwoRecord.sid);
0494: windowTwo.setSelected(sheets.size() == 1);
0495: windowTwo.setPaged(sheets.size() == 1);
0496:
0497: sheets.add(clonedSheet);
0498: int i = 1;
0499: while (true) {
0500: //Try and find the next sheet name that is unique
0501: String name = srcName;
0502: String index = Integer.toString(i++);
0503: if (name.length() + index.length() + 2 < 31)
0504: name = name + "(" + index + ")";
0505: else
0506: name = name.substring(0, 31 - index.length() - 2)
0507: + "(" + index + ")";
0508:
0509: //If the sheet name is unique, then set it otherwise move on to the next number.
0510: if (workbook.getSheetIndex(name) == -1) {
0511: workbook.setSheetName(sheets.size() - 1, name);
0512: break;
0513: }
0514: }
0515: return clonedSheet;
0516: }
0517: return null;
0518: }
0519:
0520: /**
0521: * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns
0522: * the high level representation. Use this to create new sheets.
0523: *
0524: * @param sheetname sheetname to set for the sheet.
0525: * @return HSSFSheet representing the new sheet.
0526: */
0527:
0528: public HSSFSheet createSheet(String sheetname) {
0529: if (workbook.doesContainsSheetName(sheetname, sheets.size()))
0530: throw new IllegalArgumentException(
0531: "The workbook already contains a sheet of this name");
0532:
0533: HSSFSheet sheet = new HSSFSheet(this );
0534:
0535: sheets.add(sheet);
0536: workbook.setSheetName(sheets.size() - 1, sheetname);
0537: WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet()
0538: .findFirstRecordBySid(WindowTwoRecord.sid);
0539: windowTwo.setSelected(sheets.size() == 1);
0540: windowTwo.setPaged(sheets.size() == 1);
0541: return sheet;
0542: }
0543:
0544: /**
0545: * get the number of spreadsheets in the workbook (this will be three after serialization)
0546: * @return number of sheets
0547: */
0548:
0549: public int getNumberOfSheets() {
0550: return sheets.size();
0551: }
0552:
0553: /**
0554: * Get the HSSFSheet object at the given index.
0555: * @param index of the sheet number (0-based physical & logical)
0556: * @return HSSFSheet at the provided index
0557: */
0558:
0559: public HSSFSheet getSheetAt(int index) {
0560: return (HSSFSheet) sheets.get(index);
0561: }
0562:
0563: /**
0564: * Get sheet with the given name
0565: * @param name of the sheet
0566: * @return HSSFSheet with the name provided or null if it does not exist
0567: */
0568:
0569: public HSSFSheet getSheet(String name) {
0570: HSSFSheet retval = null;
0571:
0572: for (int k = 0; k < sheets.size(); k++) {
0573: String sheetname = workbook.getSheetName(k);
0574:
0575: if (sheetname.equals(name)) {
0576: retval = (HSSFSheet) sheets.get(k);
0577: }
0578: }
0579: return retval;
0580: }
0581:
0582: /**
0583: * removes sheet at the given index
0584: * @param index of the sheet (0-based)
0585: */
0586:
0587: public void removeSheetAt(int index) {
0588: sheets.remove(index);
0589: workbook.removeSheet(index);
0590: }
0591:
0592: /**
0593: * determine whether the Excel GUI will backup the workbook when saving.
0594: *
0595: * @param backupValue true to indicate a backup will be performed.
0596: */
0597:
0598: public void setBackupFlag(boolean backupValue) {
0599: BackupRecord backupRecord = workbook.getBackupRecord();
0600:
0601: backupRecord.setBackup(backupValue ? (short) 1 : (short) 0);
0602: }
0603:
0604: /**
0605: * determine whether the Excel GUI will backup the workbook when saving.
0606: *
0607: * @return the current setting for backups.
0608: */
0609:
0610: public boolean getBackupFlag() {
0611: BackupRecord backupRecord = workbook.getBackupRecord();
0612:
0613: return (backupRecord.getBackup() == 0) ? false : true;
0614: }
0615:
0616: /**
0617: * Sets the repeating rows and columns for a sheet (as found in
0618: * File->PageSetup->Sheet). This is function is included in the workbook
0619: * because it creates/modifies name records which are stored at the
0620: * workbook level.
0621: * <p>
0622: * To set just repeating columns:
0623: * <pre>
0624: * workbook.setRepeatingRowsAndColumns(0,0,1,-1-1);
0625: * </pre>
0626: * To set just repeating rows:
0627: * <pre>
0628: * workbook.setRepeatingRowsAndColumns(0,-1,-1,0,4);
0629: * </pre>
0630: * To remove all repeating rows and columns for a sheet.
0631: * <pre>
0632: * workbook.setRepeatingRowsAndColumns(0,-1,-1,-1,-1);
0633: * </pre>
0634: *
0635: * @param sheetIndex 0 based index to sheet.
0636: * @param startColumn 0 based start of repeating columns.
0637: * @param endColumn 0 based end of repeating columns.
0638: * @param startRow 0 based start of repeating rows.
0639: * @param endRow 0 based end of repeating rows.
0640: */
0641: public void setRepeatingRowsAndColumns(int sheetIndex,
0642: int startColumn, int endColumn, int startRow, int endRow) {
0643: // Check arguments
0644: if (startColumn == -1 && endColumn != -1)
0645: throw new IllegalArgumentException(
0646: "Invalid column range specification");
0647: if (startRow == -1 && endRow != -1)
0648: throw new IllegalArgumentException(
0649: "Invalid row range specification");
0650: if (startColumn < -1 || startColumn >= 0xFF)
0651: throw new IllegalArgumentException(
0652: "Invalid column range specification");
0653: if (endColumn < -1 || endColumn >= 0xFF)
0654: throw new IllegalArgumentException(
0655: "Invalid column range specification");
0656: if (startRow < -1 || startRow > 65535)
0657: throw new IllegalArgumentException(
0658: "Invalid row range specification");
0659: if (endRow < -1 || endRow > 65535)
0660: throw new IllegalArgumentException(
0661: "Invalid row range specification");
0662: if (startColumn > endColumn)
0663: throw new IllegalArgumentException(
0664: "Invalid column range specification");
0665: if (startRow > endRow)
0666: throw new IllegalArgumentException(
0667: "Invalid row range specification");
0668:
0669: HSSFSheet sheet = getSheetAt(sheetIndex);
0670: short externSheetIndex = getWorkbook().checkExternSheet(
0671: sheetIndex);
0672:
0673: boolean settingRowAndColumn = startColumn != -1
0674: && endColumn != -1 && startRow != -1 && endRow != -1;
0675: boolean removingRange = startColumn == -1 && endColumn == -1
0676: && startRow == -1 && endRow == -1;
0677:
0678: boolean isNewRecord = false;
0679: NameRecord nameRecord;
0680: nameRecord = findExistingRowColHeaderNameRecord(sheetIndex);
0681: if (removingRange) {
0682: if (nameRecord != null)
0683: workbook
0684: .removeName(findExistingRowColHeaderNameRecordIdx(sheetIndex + 1));
0685: return;
0686: }
0687: if (nameRecord == null) {
0688: nameRecord = workbook.createBuiltInName(
0689: NameRecord.BUILTIN_PRINT_TITLE, sheetIndex + 1);
0690: //does a lot of the house keeping for builtin records, like setting lengths to zero etc
0691: isNewRecord = true;
0692: }
0693:
0694: short definitionTextLength = settingRowAndColumn ? (short) 0x001a
0695: : (short) 0x000b;
0696: nameRecord.setDefinitionTextLength(definitionTextLength);
0697:
0698: Stack ptgs = new Stack();
0699:
0700: if (settingRowAndColumn) {
0701: MemFuncPtg memFuncPtg = new MemFuncPtg();
0702: memFuncPtg.setLenRefSubexpression(23);
0703: ptgs.add(memFuncPtg);
0704: }
0705: if (startColumn >= 0) {
0706: Area3DPtg area3DPtg1 = new Area3DPtg();
0707: area3DPtg1.setExternSheetIndex(externSheetIndex);
0708: area3DPtg1.setFirstColumn((short) startColumn);
0709: area3DPtg1.setLastColumn((short) endColumn);
0710: area3DPtg1.setFirstRow((short) 0);
0711: area3DPtg1.setLastRow((short) 0xFFFF);
0712: ptgs.add(area3DPtg1);
0713: }
0714: if (startRow >= 0) {
0715: Area3DPtg area3DPtg2 = new Area3DPtg();
0716: area3DPtg2.setExternSheetIndex(externSheetIndex);
0717: area3DPtg2.setFirstColumn((short) 0);
0718: area3DPtg2.setLastColumn((short) 0x00FF);
0719: area3DPtg2.setFirstRow((short) startRow);
0720: area3DPtg2.setLastRow((short) endRow);
0721: ptgs.add(area3DPtg2);
0722: }
0723: if (settingRowAndColumn) {
0724: UnionPtg unionPtg = new UnionPtg();
0725: ptgs.add(unionPtg);
0726: }
0727: nameRecord.setNameDefinition(ptgs);
0728:
0729: if (isNewRecord) {
0730: HSSFName newName = new HSSFName(workbook, nameRecord);
0731: names.add(newName);
0732: }
0733:
0734: HSSFPrintSetup printSetup = sheet.getPrintSetup();
0735: printSetup.setValidSettings(false);
0736:
0737: WindowTwoRecord w2 = (WindowTwoRecord) sheet.getSheet()
0738: .findFirstRecordBySid(WindowTwoRecord.sid);
0739: w2.setPaged(true);
0740: }
0741:
0742: private NameRecord findExistingRowColHeaderNameRecord(int sheetIndex) {
0743: int index = findExistingRowColHeaderNameRecordIdx(sheetIndex);
0744: if (index == -1)
0745: return null;
0746: else
0747: return (NameRecord) workbook.findNextRecordBySid(
0748: NameRecord.sid, index);
0749: }
0750:
0751: private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) {
0752: int index = 0;
0753: NameRecord r = null;
0754: while ((r = (NameRecord) workbook.findNextRecordBySid(
0755: NameRecord.sid, index)) != null) {
0756: int indexToSheet = r.getEqualsToIndexToSheet() - 1;
0757: if (indexToSheet > -1) { //ignore "GLOBAL" name records
0758: int nameRecordSheetIndex = workbook
0759: .getSheetIndexFromExternSheetIndex(indexToSheet);
0760: if (isRowColHeaderRecord(r)
0761: && nameRecordSheetIndex == sheetIndex) {
0762: return index;
0763: }
0764: }
0765: index++;
0766: }
0767:
0768: return -1;
0769: }
0770:
0771: private boolean isRowColHeaderRecord(NameRecord r) {
0772: return r.getOptionFlag() == 0x20
0773: && ("" + ((char) 7)).equals(r.getNameText());
0774: }
0775:
0776: /**
0777: * create a new Font and add it to the workbook's font table
0778: * @return new font object
0779: */
0780:
0781: public HSSFFont createFont() {
0782: FontRecord font = workbook.createNewFont();
0783: short fontindex = (short) (getNumberOfFonts() - 1);
0784:
0785: if (fontindex > 3) {
0786: fontindex++; // THERE IS NO FOUR!!
0787: }
0788: if (fontindex == Short.MAX_VALUE) {
0789: throw new IllegalArgumentException(
0790: "Maximum number of fonts was exceeded");
0791: }
0792: HSSFFont retval = new HSSFFont(fontindex, font);
0793:
0794: return retval;
0795: }
0796:
0797: /**
0798: * Finds a font that matches the one with the supplied attributes
0799: */
0800: public HSSFFont findFont(short boldWeight, short color,
0801: short fontHeight, String name, boolean italic,
0802: boolean strikeout, short typeOffset, byte underline) {
0803: // System.out.println( boldWeight + ", " + color + ", " + fontHeight + ", " + name + ", " + italic + ", " + strikeout + ", " + typeOffset + ", " + underline );
0804: for (short i = 0; i < workbook.getNumberOfFontRecords(); i++) {
0805: if (i == 4)
0806: continue;
0807:
0808: FontRecord font = workbook.getFontRecordAt(i);
0809: HSSFFont hssfFont = new HSSFFont(i, font);
0810: // System.out.println( hssfFont.getBoldweight() + ", " + hssfFont.getColor() + ", " + hssfFont.getFontHeight() + ", " + hssfFont.getFontName() + ", " + hssfFont.getItalic() + ", " + hssfFont.getStrikeout() + ", " + hssfFont.getTypeOffset() + ", " + hssfFont.getUnderline() );
0811: if (hssfFont.getBoldweight() == boldWeight
0812: && hssfFont.getColor() == color
0813: && hssfFont.getFontHeight() == fontHeight
0814: && hssfFont.getFontName().equals(name)
0815: && hssfFont.getItalic() == italic
0816: && hssfFont.getStrikeout() == strikeout
0817: && hssfFont.getTypeOffset() == typeOffset
0818: && hssfFont.getUnderline() == underline) {
0819: // System.out.println( "Found font" );
0820: return hssfFont;
0821: }
0822: }
0823:
0824: // System.out.println( "No font found" );
0825: return null;
0826: }
0827:
0828: /**
0829: * get the number of fonts in the font table
0830: * @return number of fonts
0831: */
0832:
0833: public short getNumberOfFonts() {
0834: return (short) workbook.getNumberOfFontRecords();
0835: }
0836:
0837: /**
0838: * get the font at the given index number
0839: * @param idx index number
0840: * @return HSSFFont at the index
0841: */
0842:
0843: public HSSFFont getFontAt(short idx) {
0844: FontRecord font = workbook.getFontRecordAt(idx);
0845: HSSFFont retval = new HSSFFont(idx, font);
0846:
0847: return retval;
0848: }
0849:
0850: /**
0851: * create a new Cell style and add it to the workbook's style table
0852: * @return the new Cell Style object
0853: */
0854:
0855: public HSSFCellStyle createCellStyle() {
0856: ExtendedFormatRecord xfr = workbook.createCellXF();
0857: short index = (short) (getNumCellStyles() - 1);
0858: HSSFCellStyle style = new HSSFCellStyle(index, xfr);
0859:
0860: return style;
0861: }
0862:
0863: /**
0864: * get the number of styles the workbook contains
0865: * @return count of cell styles
0866: */
0867:
0868: public short getNumCellStyles() {
0869: return (short) workbook.getNumExFormats();
0870: }
0871:
0872: /**
0873: * get the cell style object at the given index
0874: * @param idx index within the set of styles
0875: * @return HSSFCellStyle object at the index
0876: */
0877:
0878: public HSSFCellStyle getCellStyleAt(short idx) {
0879: ExtendedFormatRecord xfr = workbook.getExFormatAt(idx);
0880: HSSFCellStyle style = new HSSFCellStyle(idx, xfr);
0881:
0882: return style;
0883: }
0884:
0885: /**
0886: * Method write - write out this workbook to an Outputstream. Constructs
0887: * a new POI POIFSFileSystem, passes in the workbook binary representation and
0888: * writes it out.
0889: *
0890: * @param stream - the java OutputStream you wish to write the XLS to
0891: *
0892: * @exception IOException if anything can't be written.
0893: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
0894: */
0895:
0896: public void write(OutputStream stream) throws IOException {
0897: byte[] bytes = getBytes();
0898: POIFSFileSystem fs = new POIFSFileSystem();
0899:
0900: // For tracking what we've written out, used if we're
0901: // going to be preserving nodes
0902: List excepts = new ArrayList(1);
0903:
0904: // Write out the Workbook stream
0905: fs.createDocument(new ByteArrayInputStream(bytes), "Workbook");
0906:
0907: // Write out our HPFS properties, if we have them
0908: writeProperties(fs, excepts);
0909:
0910: if (preserveNodes) {
0911: // Don't write out the old Workbook, we'll be doing our new one
0912: excepts.add("Workbook");
0913: // If the file had WORKBOOK instead of Workbook, we'll write it
0914: // out correctly shortly, so don't include the old one
0915: excepts.add("WORKBOOK");
0916:
0917: // Copy over all the other nodes to our new poifs
0918: copyNodes(this .filesystem, fs, excepts);
0919: }
0920: fs.writeFilesystem(stream);
0921: //poifs.writeFilesystem(stream);
0922: }
0923:
0924: /**
0925: * Method getBytes - get the bytes of just the HSSF portions of the XLS file.
0926: * Use this to construct a POI POIFSFileSystem yourself.
0927: *
0928: *
0929: * @return byte[] array containing the binary representation of this workbook and all contained
0930: * sheets, rows, cells, etc.
0931: *
0932: * @see org.apache.poi.hssf.model.Workbook
0933: * @see org.apache.poi.hssf.model.Sheet
0934: */
0935:
0936: public byte[] getBytes() {
0937: if (log.check(POILogger.DEBUG))
0938: log.log(DEBUG, "HSSFWorkbook.getBytes()");
0939:
0940: // before getting the workbook size we must tell the sheets that
0941: // serialization is about to occur.
0942: for (int k = 0; k < sheets.size(); k++)
0943: ((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
0944:
0945: int wbsize = workbook.getSize();
0946:
0947: // log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
0948: // ArrayList sheetbytes = new ArrayList(sheets.size());
0949: int totalsize = wbsize;
0950:
0951: for (int k = 0; k < sheets.size(); k++) {
0952: workbook.setSheetBof(k, totalsize);
0953: totalsize += ((HSSFSheet) sheets.get(k)).getSheet()
0954: .getSize();
0955: }
0956:
0957: /* if (totalsize < 4096)
0958: {
0959: totalsize = 4096;
0960: }*/
0961: byte[] retval = new byte[totalsize];
0962: int pos = workbook.serialize(0, retval);
0963:
0964: // System.arraycopy(wb, 0, retval, 0, wb.length);
0965: for (int k = 0; k < sheets.size(); k++) {
0966:
0967: // byte[] sb = (byte[])sheetbytes.get(k);
0968: // System.arraycopy(sb, 0, retval, pos, sb.length);
0969: int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(
0970: pos, retval);
0971: pos += len; // sb.length;
0972: }
0973: /* for (int k = pos; k < totalsize; k++)
0974: {
0975: retval[k] = 0;
0976: }*/
0977: return retval;
0978: }
0979:
0980: /** @deprecated Do not call this method from your applications. Use the methods
0981: * available in the HSSFRow to add string HSSFCells
0982: */
0983: public int addSSTString(String string) {
0984: return workbook.addSSTString(new UnicodeString(string));
0985: }
0986:
0987: /** @deprecated Do not call this method from your applications. Use the methods
0988: * available in the HSSFRow to get string HSSFCells
0989: */
0990: public String getSSTString(int index) {
0991: return workbook.getSSTString(index).getString();
0992: }
0993:
0994: protected Workbook getWorkbook() {
0995: return workbook;
0996: }
0997:
0998: /** gets the total number of named ranges in the workboko
0999: * @return number of named ranges
1000: */
1001: public int getNumberOfNames() {
1002: int result = names.size();
1003: return result;
1004: }
1005:
1006: /** gets the Named range
1007: * @param index position of the named range
1008: * @return named range high level
1009: */
1010: public HSSFName getNameAt(int index) {
1011: HSSFName result = (HSSFName) names.get(index);
1012:
1013: return result;
1014: }
1015:
1016: /** gets the named range name
1017: * @param index the named range index (0 based)
1018: * @return named range name
1019: */
1020: public String getNameName(int index) {
1021: String result = getNameAt(index).getNameName();
1022:
1023: return result;
1024: }
1025:
1026: /**
1027: * Sets the printarea for the sheet provided
1028: * <p>
1029: * i.e. Reference = $A$1:$B$2
1030: * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
1031: * @param reference Valid name Reference for the Print Area
1032: */
1033: public void setPrintArea(int sheetIndex, String reference) {
1034: NameRecord name = workbook.getSpecificBuiltinRecord(
1035: NameRecord.BUILTIN_PRINT_AREA, sheetIndex + 1);
1036:
1037: if (name == null)
1038: name = workbook.createBuiltInName(
1039: NameRecord.BUILTIN_PRINT_AREA, sheetIndex + 1);
1040: //adding one here because 0 indicates a global named region; doesnt make sense for print areas
1041:
1042: short externSheetIndex = getWorkbook().checkExternSheet(
1043: sheetIndex);
1044: name.setExternSheetNumber(externSheetIndex);
1045: name.setAreaReference(reference);
1046:
1047: }
1048:
1049: /**
1050: * For the Convenience of Java Programmers maintaining pointers.
1051: * @see #setPrintArea(int, String)
1052: * @param sheetIndex Zero-based sheet index (0 = First Sheet)
1053: * @param startColumn Column to begin printarea
1054: * @param endColumn Column to end the printarea
1055: * @param startRow Row to begin the printarea
1056: * @param endRow Row to end the printarea
1057: */
1058: public void setPrintArea(int sheetIndex, int startColumn,
1059: int endColumn, int startRow, int endRow) {
1060:
1061: //using absolute references because they dont get copied and pasted anyway
1062: CellReference cell = new CellReference(startRow, startColumn,
1063: true, true);
1064: String reference = cell.toString();
1065:
1066: cell = new CellReference(endRow, endColumn, true, true);
1067: reference = reference + ":" + cell.toString();
1068:
1069: setPrintArea(sheetIndex, reference);
1070: }
1071:
1072: /**
1073: * Retrieves the reference for the printarea of the specified sheet, the sheet name is appended to the reference even if it was not specified.
1074: * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
1075: * @return String Null if no print area has been defined
1076: */
1077: public String getPrintArea(int sheetIndex) {
1078: NameRecord name = workbook.getSpecificBuiltinRecord(
1079: NameRecord.BUILTIN_PRINT_AREA, sheetIndex + 1);
1080: if (name == null)
1081: return null;
1082: //adding one here because 0 indicates a global named region; doesnt make sense for print areas
1083:
1084: return name.getAreaReference(workbook);
1085: }
1086:
1087: /**
1088: * Delete the printarea for the sheet specified
1089: * @param sheetIndex Zero-based sheet index (0 = First Sheet)
1090: */
1091: public void removePrintArea(int sheetIndex) {
1092: getWorkbook().removeBuiltinRecord(
1093: NameRecord.BUILTIN_PRINT_AREA, sheetIndex + 1);
1094: }
1095:
1096: /** creates a new named range and add it to the model
1097: * @return named range high level
1098: */
1099: public HSSFName createName() {
1100: NameRecord nameRecord = workbook.createName();
1101:
1102: HSSFName newName = new HSSFName(workbook, nameRecord);
1103:
1104: names.add(newName);
1105:
1106: return newName;
1107: }
1108:
1109: /** gets the named range index by his name
1110: * <i>Note:</i>Excel named ranges are case-insensitive and
1111: * this method performs a case-insensitive search.
1112: *
1113: * @param name named range name
1114: * @return named range index
1115: */
1116: public int getNameIndex(String name) {
1117: int retval = -1;
1118:
1119: for (int k = 0; k < names.size(); k++) {
1120: String nameName = getNameName(k);
1121:
1122: if (nameName.equalsIgnoreCase(name)) {
1123: retval = k;
1124: break;
1125: }
1126: }
1127: return retval;
1128: }
1129:
1130: /** remove the named range by his index
1131: * @param index named range index (0 based)
1132: */
1133: public void removeName(int index) {
1134: names.remove(index);
1135: workbook.removeName(index);
1136: }
1137:
1138: /**
1139: * Returns the instance of HSSFDataFormat for this workbook.
1140: * @return the HSSFDataFormat object
1141: * @see org.apache.poi.hssf.record.FormatRecord
1142: * @see org.apache.poi.hssf.record.Record
1143: */
1144: public HSSFDataFormat createDataFormat() {
1145: if (formatter == null)
1146: formatter = new HSSFDataFormat(workbook);
1147: return formatter;
1148: }
1149:
1150: /** remove the named range by his name
1151: * @param name named range name
1152: */
1153: public void removeName(String name) {
1154: int index = getNameIndex(name);
1155:
1156: removeName(index);
1157:
1158: }
1159:
1160: public HSSFPalette getCustomPalette() {
1161: return new HSSFPalette(workbook.getCustomPalette());
1162: }
1163:
1164: /** Test only. Do not use */
1165: public void insertChartRecord() {
1166: int loc = workbook.findFirstRecordLocBySid(SSTRecord.sid);
1167: byte[] data = { (byte) 0x0F, (byte) 0x00, (byte) 0x00,
1168: (byte) 0xF0, (byte) 0x52, (byte) 0x00, (byte) 0x00,
1169: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
1170: (byte) 0xF0, (byte) 0x18, (byte) 0x00, (byte) 0x00,
1171: (byte) 0x00, (byte) 0x01, (byte) 0x08, (byte) 0x00,
1172: (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
1173: (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
1174: (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
1175: (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
1176: (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00,
1177: (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x0B,
1178: (byte) 0xF0, (byte) 0x12, (byte) 0x00, (byte) 0x00,
1179: (byte) 0x00, (byte) 0xBF, (byte) 0x00, (byte) 0x08,
1180: (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x81,
1181: (byte) 0x01, (byte) 0x09, (byte) 0x00, (byte) 0x00,
1182: (byte) 0x08, (byte) 0xC0, (byte) 0x01, (byte) 0x40,
1183: (byte) 0x00, (byte) 0x00, (byte) 0x08, (byte) 0x40,
1184: (byte) 0x00, (byte) 0x1E, (byte) 0xF1, (byte) 0x10,
1185: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0D,
1186: (byte) 0x00, (byte) 0x00, (byte) 0x08, (byte) 0x0C,
1187: (byte) 0x00, (byte) 0x00, (byte) 0x08, (byte) 0x17,
1188: (byte) 0x00, (byte) 0x00, (byte) 0x08, (byte) 0xF7,
1189: (byte) 0x00, (byte) 0x00, (byte) 0x10, };
1190: UnknownRecord r = new UnknownRecord((short) 0x00EB, data);
1191: workbook.getRecords().add(loc, r);
1192: }
1193:
1194: /**
1195: * Spits out a list of all the drawing records in the workbook.
1196: */
1197: public void dumpDrawingGroupRecords(boolean fat) {
1198: DrawingGroupRecord r = (DrawingGroupRecord) workbook
1199: .findFirstRecordBySid(DrawingGroupRecord.sid);
1200: r.decode();
1201: List escherRecords = r.getEscherRecords();
1202: PrintWriter w = new PrintWriter(System.out);
1203: for (Iterator iterator = escherRecords.iterator(); iterator
1204: .hasNext();) {
1205: EscherRecord escherRecord = (EscherRecord) iterator.next();
1206: if (fat)
1207: System.out.println(escherRecord.toString());
1208: else
1209: escherRecord.display(w, 0);
1210: }
1211: w.flush();
1212: }
1213:
1214: /**
1215: * Adds a picture to the workbook.
1216: *
1217: * @param pictureData The bytes of the picture
1218: * @param format The format of the picture. One of <code>PICTURE_TYPE_*</code>
1219: *
1220: * @return the index to this picture (1 based).
1221: */
1222: public int addPicture(byte[] pictureData, int format) {
1223: byte[] uid = newUID();
1224: EscherBitmapBlip blipRecord = new EscherBitmapBlip();
1225: blipRecord
1226: .setRecordId((short) (EscherBitmapBlip.RECORD_ID_START + format));
1227: switch (format) {
1228: case PICTURE_TYPE_EMF:
1229: blipRecord.setOptions(HSSFPictureData.MSOBI_EMF);
1230: break;
1231: case PICTURE_TYPE_WMF:
1232: blipRecord.setOptions(HSSFPictureData.MSOBI_WMF);
1233: break;
1234: case PICTURE_TYPE_PICT:
1235: blipRecord.setOptions(HSSFPictureData.MSOBI_PICT);
1236: break;
1237: case PICTURE_TYPE_PNG:
1238: blipRecord.setOptions(HSSFPictureData.MSOBI_PNG);
1239: break;
1240: case HSSFWorkbook.PICTURE_TYPE_JPEG:
1241: blipRecord.setOptions(HSSFPictureData.MSOBI_JPEG);
1242: break;
1243: case HSSFWorkbook.PICTURE_TYPE_DIB:
1244: blipRecord.setOptions(HSSFPictureData.MSOBI_DIB);
1245: break;
1246: }
1247:
1248: blipRecord.setUID(uid);
1249: blipRecord.setMarker((byte) 0xFF);
1250: blipRecord.setPictureData(pictureData);
1251:
1252: EscherBSERecord r = new EscherBSERecord();
1253: r.setRecordId(EscherBSERecord.RECORD_ID);
1254: r.setOptions((short) (0x0002 | (format << 4)));
1255: r.setBlipTypeMacOS((byte) format);
1256: r.setBlipTypeWin32((byte) format);
1257: r.setUid(uid);
1258: r.setTag((short) 0xFF);
1259: r.setSize(pictureData.length + 25);
1260: r.setRef(1);
1261: r.setOffset(0);
1262: r.setBlipRecord(blipRecord);
1263:
1264: return workbook.addBSERecord(r);
1265: }
1266:
1267: /**
1268: * Gets all pictures from the Workbook.
1269: *
1270: * @return the list of pictures (a list of {@link HSSFPictureData} objects.)
1271: */
1272: public List getAllPictures() {
1273: // The drawing group record always exists at the top level, so we won't need to do this recursively.
1274: List pictures = new ArrayList();
1275: Iterator recordIter = workbook.getRecords().iterator();
1276: while (recordIter.hasNext()) {
1277: Object obj = recordIter.next();
1278: if (obj instanceof AbstractEscherHolderRecord) {
1279: ((AbstractEscherHolderRecord) obj).decode();
1280: List escherRecords = ((AbstractEscherHolderRecord) obj)
1281: .getEscherRecords();
1282: searchForPictures(escherRecords, pictures);
1283: }
1284: }
1285: return pictures;
1286: }
1287:
1288: /**
1289: * Performs a recursive search for pictures in the given list of escher records.
1290: *
1291: * @param escherRecords the escher records.
1292: * @param pictures the list to populate with the pictures.
1293: */
1294: private void searchForPictures(List escherRecords, List pictures) {
1295: Iterator recordIter = escherRecords.iterator();
1296: while (recordIter.hasNext()) {
1297: Object obj = recordIter.next();
1298: if (obj instanceof EscherRecord) {
1299: EscherRecord escherRecord = (EscherRecord) obj;
1300:
1301: if (escherRecord instanceof EscherBSERecord) {
1302: EscherBlipRecord blip = ((EscherBSERecord) escherRecord)
1303: .getBlipRecord();
1304: if (blip != null) {
1305: // TODO: Some kind of structure.
1306: pictures.add(new HSSFPictureData(blip));
1307: }
1308: }
1309:
1310: // Recursive call.
1311: searchForPictures(escherRecord.getChildRecords(),
1312: pictures);
1313: }
1314: }
1315: }
1316:
1317: /**
1318: * protect a workbook with a password (not encypted, just sets writeprotect
1319: * flags and the password.
1320: * @param password to set
1321: */
1322: public void writeProtectWorkbook(String password, String username) {
1323: this .workbook.writeProtectWorkbook(password, username);
1324: }
1325:
1326: /**
1327: * removes the write protect flag
1328: */
1329: public void unwriteProtectWorkbook() {
1330: this .workbook.unwriteProtectWorkbook();
1331: }
1332:
1333: /**
1334: * Gets all embedded OLE2 objects from the Workbook.
1335: *
1336: * @return the list of embedded objects (a list of {@link HSSFObjectData} objects.)
1337: */
1338: public List getAllEmbeddedObjects() {
1339: List objects = new ArrayList();
1340: for (int i = 0; i < getNumberOfSheets(); i++) {
1341: getAllEmbeddedObjects(
1342: getSheetAt(i).getSheet().getRecords(), objects);
1343: }
1344: return objects;
1345: }
1346:
1347: /**
1348: * Gets all embedded OLE2 objects from the Workbook.
1349: *
1350: * @param records the list of records to search.
1351: * @param objects the list of embedded objects to populate.
1352: */
1353: private void getAllEmbeddedObjects(List records, List objects) {
1354: Iterator recordIter = records.iterator();
1355: while (recordIter.hasNext()) {
1356: Object obj = recordIter.next();
1357: if (obj instanceof ObjRecord) {
1358: // TODO: More convenient way of determining if there is stored binary.
1359: // TODO: Link to the data stored in the other stream.
1360: Iterator subRecordIter = ((ObjRecord) obj)
1361: .getSubRecords().iterator();
1362: while (subRecordIter.hasNext()) {
1363: Object sub = subRecordIter.next();
1364: if (sub instanceof EmbeddedObjectRefSubRecord) {
1365: objects.add(new HSSFObjectData((ObjRecord) obj,
1366: filesystem));
1367: }
1368: }
1369: }
1370: }
1371: }
1372:
1373: private byte[] newUID() {
1374: byte[] bytes = new byte[16];
1375: return bytes;
1376: }
1377: }
|