1 2 /* ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2002 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" and 28 * "Apache POI" must not be used to endorse or promote products 29 * derived from this software without prior written permission. For 30 * written permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * "Apache POI", nor may "Apache" appear in their name, without 34 * prior written permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 56 package org.apache.poi.hssf.model; 57 58 import java.io.OutputStream; 59 60 import java.util.List; 61 import java.util.ArrayList; 62 import java.util.Iterator; 63 64 import org.apache.poi.util.POILogFactory; 65 import org.apache.poi.hssf 66 .record.*; // normally I don't do this, buy we literally mean ALL 67 import org.apache.poi.hssf.record.formula.FormulaParser; 68 import org.apache.poi.hssf.record.formula.Ptg; 69 import org.apache.poi.util.IntList; 70 import org.apache.poi.util.POILogger; 71 import org.apache.poi.hssf.record 72 .aggregates.*; // normally I don't do this, buy we literally mean ALL 73 74 /** 75 * Low level model implementation of a Sheet (one workbook contains many sheets) 76 * This file contains the low level binary records starting at the sheets BOF and 77 * ending with the sheets EOF. Use HSSFSheet for a high level representation. 78 * <P> 79 * The structures of the highlevel API use references to this to perform most of their 80 * operations. Its probably unwise to use these low level structures directly unless you 81 * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's 82 * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf 83 * before even attempting to use this. 84 * <P> 85 * @author Andrew C. Oliver (acoliver at apache dot org) 86 * @author Glen Stampoultzis (glens at apache.org) 87 * @see org.apache.poi.hssf.model.Workbook 88 * @see org.apache.poi.hssf.usermodel.HSSFSheet 89 * @author Shawn Laubach (laubach at acm.org) Just Gridlines, Headers, Footers, and PrintSetup 90 * @version 1.0-pre 91 */ 92 93 public class Sheet 94 extends java.lang.java.lang.Objecttected ArrayList records = null; 95 int preoffset = 96 0; // offset of the sheet in a new file 97 int loc = 0; 98 protected boolean containsLabels = false; 99 ; 100 protected int dimsloc = 0; 101 protected DimensionsRecord dims; 102 protected DefaultColWidthRecord defaultcolwidth = null; 103 protected DefaultRowHeightRecord defaultrowheight = null; 104 protected GridsetRecord gridset = null; 105 protected PrintSetupRecord printSetup = null; 106 protected HeaderRecord header = null; 107 protected FooterRecord footer = null; 108 protected PrintGridlinesRecord printGridlines = null; 109 protected MergeCellsRecord merged = null; 110 protected int mergedloc = 0; 111 private static POILogger log = 112 POILogFactory.getLogger(Sheet.class); 113 private ArrayList columnSizes = 114 null; // holds column info 115 protected ValueRecordsAggregate cells = null; 116 protected RowRecordsAggregate rows = null; 117 private Iterator valueRecIterator = null; 118 private Iterator rowRecIterator = null; 119 120 /** 121 * Creates new Sheet with no intialization --useless at this point 122 * @see #createSheet(List,int,int) 123 */ 124 125 public Sheet() 126 { 127 } 128 129 /** 130 * read support (offset used as starting point for search) for low level 131 * API. Pass in an array of Record objects, the sheet number (0 based) and 132 * a record offset (should be the location of the sheets BOF record). A Sheet 133 * object is constructed and passed back with all of its initialization set 134 * to the passed in records and references to those records held. This function 135 * is normally called via Workbook. 136 * 137 * @param recs array containing those records in the sheet in sequence (normally obtained from RecordFactory) 138 * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release) 139 * @param offset of the sheet's BOF record 140 * 141 * @return Sheet object with all values set to those read from the file 142 * 143 * @see org.apache.poi.hssf.model.Workbook 144 * @see org.apache.poi.hssf.record.Record 145 */ 146 public static Sheet createSheet(List recs, int sheetnum, int offset) 147 { 148 log.logFormatted(log.DEBUG, 149 "Sheet createSheet (existing file) with %", 150 new Integer(recs.size())); 151 Sheet retval = new Sheet(); 152 ArrayList records = new ArrayList(recs.size() / 5); 153 boolean isfirstcell = true; 154 boolean isfirstrow = true; 155 int bofEofNestingLevel = 0; 156 157 for (int k = offset; k < recs.size(); k++) 158 { 159 Record rec = ( Record ) recs.get(k); 160 161 if (rec.getSid() == LabelRecord.sid) 162 { 163 log.log(log.DEBUG, "Hit label record"); 164 retval.containsLabels = true; 165 } 166 else if (rec.getSid() == BOFRecord.sid) 167 { 168 bofEofNestingLevel++; 169 } 170 else if ((rec.getSid() == EOFRecord.sid) 171 && (--bofEofNestingLevel == 0)) 172 { 173 log.log(log.DEBUG, "Hit EOF record at "); 174 records.add(rec); 175 break; 176 } 177 else if (rec.getSid() == DimensionsRecord.sid) 178 { 179 retval.dims = ( DimensionsRecord ) rec; 180 retval.dimsloc = records.size(); 181 } 182 else if (rec.getSid() == MergeCellsRecord.sid) 183 { 184 retval.merged = ( MergeCellsRecord ) rec; 185 retval.mergedloc = k - offset; 186 } 187 else if (rec.getSid() == ColumnInfoRecord.sid) 188 { 189 if (retval.columnSizes == null) 190 { 191 retval.columnSizes = new ArrayList(); 192 } 193 retval.columnSizes.add(( ColumnInfoRecord ) rec); 194 } 195 else if (rec.getSid() == DefaultColWidthRecord.sid) 196 { 197 retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; 198 } 199 else if (rec.getSid() == DefaultRowHeightRecord.sid) 200 { 201 retval.defaultrowheight = ( DefaultRowHeightRecord ) rec; 202 } 203 else if (rec.isValue()) 204 { 205 if (isfirstcell) 206 { 207 retval.cells = new ValueRecordsAggregate(); 208 rec = retval.cells; 209 retval.cells.construct(k, recs); 210 isfirstcell = false; 211 } 212 else 213 { 214 rec = null; 215 } 216 } 217 else if (rec.getSid() == RowRecord.sid) 218 { 219 if (isfirstrow) 220 { 221 retval.rows = new RowRecordsAggregate(); 222 rec = retval.rows; 223 retval.rows.construct(k, recs); 224 isfirstrow = false; 225 } 226 else 227 { 228 rec = null; 229 } 230 } 231 else if (rec.getSid () == PrintGridlinesRecord.sid) 232 { 233 retval.printGridlines = (PrintGridlinesRecord) rec; 234 } 235 else if (rec.getSid () == HeaderRecord.sid) 236 { 237 retval.header = (HeaderRecord) rec; 238 } 239 else if (rec.getSid () == FooterRecord.sid) 240 { 241 retval.footer = (FooterRecord) rec; 242 } 243 else if (rec.getSid () == PrintSetupRecord.sid) 244 { 245 retval.printSetup = (PrintSetupRecord) rec; 246 } 247 248 if (rec != null) 249 { 250 records.add(rec); 251 } 252 } 253 retval.records = records; 254 log.log(log.DEBUG, "sheet createSheet (existing file) exited"); 255 return retval; 256 } 257 258 /** 259 * read support (offset = 0) Same as createSheet(Record[] recs, int, int) 260 * only the record offset is assumed to be 0. 261 * 262 * @param records array containing those records in the sheet in sequence (normally obtained from RecordFactory) 263 * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release) 264 * @return Sheet object 265 */ 266 267 public static Sheet createSheet(List records, int sheetnum) 268 { 269 log.log(log.DEBUG, 270 "Sheet createSheet (exisiting file) assumed offset 0"); 271 return createSheet(records, sheetnum, 0); 272 } 273 274 /** 275 * Creates a sheet with all the usual records minus values and the "index" 276 * record (not required). Sets the location pointer to where the first value 277 * records should go. Use this to create a sheet from "scratch". 278 * 279 * @return Sheet object with all values set to defaults 280 */ 281 282 public static Sheet createSheet() 283 { 284 log.log(log.DEBUG, "Sheet createsheet from scratch called"); 285 Sheet retval = new Sheet(); 286 ArrayList records = new ArrayList(30); 287 288 records.add(retval.createBOF()); 289 290 // records.add(retval.createIndex()); 291 records.add(retval.createCalcMode()); 292 records.add(retval.createCalcCount()); 293 records.add(retval.createRefMode()); 294 records.add(retval.createIteration()); 295 records.add(retval.createDelta()); 296 records.add(retval.createSaveRecalc()); 297 records.add(retval.createPrintHeaders()); 298 retval.printGridlines = (PrintGridlinesRecord) retval.createPrintGridlines (); 299 records.add (retval.printGridlines); 300 retval.gridset = ( GridsetRecord ) retval.createGridset(); 301 records.add(retval.gridset); 302 records.add(retval.createGuts()); 303 retval.defaultrowheight = 304 ( DefaultRowHeightRecord ) retval.createDefaultRowHeight(); 305 records.add(retval.defaultrowheight); 306 records.add(retval.createWSBool()); 307 retval.header = (HeaderRecord) retval.createHeader (); 308 records.add (retval.header); 309 retval.footer = (FooterRecord) retval.createFooter (); 310 records.add (retval.footer); 311 records.add(retval.createHCenter()); 312 records.add(retval.createVCenter()); 313 retval.printSetup = (PrintSetupRecord) retval.createPrintSetup (); 314 records.add (retval.printSetup); 315 retval.defaultcolwidth = 316 ( DefaultColWidthRecord ) retval.createDefaultColWidth(); 317 records.add(retval.defaultcolwidth); 318 retval.dims = ( DimensionsRecord ) retval.createDimensions(); 319 retval.dimsloc = 19; 320 records.add(retval.dims); 321 records.add(retval.createWindowTwo()); 322 retval.setLoc(records.size() - 1); 323 records.add(retval.createSelection()); 324 records.add(retval.createEOF()); 325 retval.records = records; 326 log.log(log.DEBUG, "Sheet createsheet from scratch exit"); 327 return retval; 328 } 329 330 private void checkCells() 331 { 332 if (cells == null) 333 { 334 cells = new ValueRecordsAggregate(); 335 records.add(getDimsLoc() + 1, cells); 336 } 337 } 338 339 private void checkRows() 340 { 341 if (rows == null) 342 { 343 rows = new RowRecordsAggregate(); 344 records.add(getDimsLoc() + 1, rows); 345 } 346 } 347 348 public int addMergedRegion(short rowFrom, short colFrom, short rowTo, 349 short colTo) 350 { 351 if (merged == null) 352 { 353 merged = ( MergeCellsRecord ) createMergedCells(); 354 mergedloc = records.size() - 1; 355 records.add(records.size() - 1, merged); 356 } 357 return merged.addArea(rowFrom, colFrom, rowTo, colTo); 358 } 359 360 public void removeMergedRegion(int index) 361 { 362 merged.removeAreaAt(index); 363 if (merged.getNumAreas() == 0) 364 { 365 merged = null; 366 records.remove(mergedloc); 367 mergedloc = 0; 368 } 369 } 370 371 public MergeCellsRecord.MergedRegion getMergedRegionAt(int index) 372 { 373 return merged.getAreaAt(index); 374 } 375 376 public int getNumMergedRegions() 377 { 378 return merged.getNumAreas(); 379 } 380 381 /** 382 * This is basically a kludge to deal with the now obsolete Label records. If 383 * you have to read in a sheet that contains Label records, be aware that the rest 384 * of the API doesn't deal with them, the low level structure only provides read-only 385 * semi-immutable structures (the sets are there for interface conformance with NO 386 * impelmentation). In short, you need to call this function passing it a reference 387 * to the Workbook object. All labels will be converted to LabelSST records and their 388 * contained strings will be written to the Shared String tabel (SSTRecord) within 389 * the Workbook. 390 * 391 * @param wb sheet's matching low level Workbook structure containing the SSTRecord. 392 * @see org.apache.poi.hssf.record.LabelRecord 393 * @see org.apache.poi.hssf.record.LabelSSTRecord 394 * @see org.apache.poi.hssf.record.SSTRecord 395 */ 396 397 public void convertLabelRecords(Workbook wb) 398 { 399 log.log(log.DEBUG, "convertLabelRecords called"); 400 if (containsLabels) 401 { 402 for (int k = 0; k < records.size(); k++) 403 { 404 Record rec = ( Record ) records.get(k); 405 406 if (rec.getSid() == LabelRecord.sid) 407 { 408 LabelRecord oldrec = ( LabelRecord ) rec; 409 410 records.remove(k); 411 LabelSSTRecord newrec = new LabelSSTRecord(); 412 int stringid = 413 wb.addSSTString(oldrec.getValue()); 414 415 newrec.setRow(oldrec.getRow()); 416 newrec.setColumn(oldrec.getColumn()); 417 newrec.setXFIndex(oldrec.getXFIndex()); 418 newrec.setSSTIndex(stringid); 419 records.add(k, newrec); 420 } 421 } 422 } 423 log.log(log.DEBUG, "convertLabelRecords exit"); 424 } 425 426 /** 427 * Returns the number of low level binary records in this sheet. This adjusts things for the so called 428 * AgregateRecords. 429 * 430 * @see org.apache.poi.hssf.record.Record 431 */ 432 433 public int getNumRecords() 434 { 435 checkCells(); 436 checkRows(); 437 log.log(log.DEBUG, "Sheet.getNumRecords"); 438 log.logFormatted(log.DEBUG, "returning % + % + % - 2 = %", new int[] 439 { 440 records.size(), cells.getPhysicalNumberOfCells(), 441 rows.getPhysicalNumberOfRows(), 442 records.size() + cells.getPhysicalNumberOfCells() 443 + rows.getPhysicalNumberOfRows() - 2 444 }); 445 return records.size() + cells.getPhysicalNumberOfCells() 446 + rows.getPhysicalNumberOfRows() - 2; 447 } 448 449 /** 450 * Per an earlier reported bug in working with Andy Khan's excel read library. This 451 * sets the values in the sheet's DimensionsRecord object to be correct. Excel doesn't 452 * really care, but we want to play nice with other libraries. 453 * 454 * @see org.apache.poi.hssf.record.DimensionsRecord 455 */ 456 457 public void setDimensions(short firstrow, short firstcol, short lastrow, 458 short lastcol) 459 { 460 log.log(log.DEBUG, "Sheet.setDimensions"); 461 log.log(log.DEBUG, 462 (new StringBuffer("firstrow")).append(firstrow) 463 .append("firstcol").append(firstcol).append("lastrow") 464 .append(lastrow).append("lastcol").append(lastcol) 465 .toString()); 466 dims.setFirstCol(firstcol); 467 dims.setFirstRow(firstrow); 468 dims.setLastCol(lastcol); 469 dims.setLastRow(lastrow); 470 log.log(log.DEBUG, "Sheet.setDimensions exiting"); 471 } 472 473 /** 474 * set the locator for where we should look for the next value record. The 475 * algorythm will actually start here and find the correct location so you 476 * can set this to 0 and watch performance go down the tubes but it will work. 477 * After a value is set this is automatically advanced. Its also set by the 478 * create method. So you probably shouldn't mess with this unless you have 479 * a compelling reason why or the help for the method you're calling says so. 480 * Check the other methods for whether they care about 481 * the loc pointer. Many of the "modify" and "remove" methods re-initialize this 482 * to "dimsloc" which is the location of the Dimensions Record and presumably the 483 * start of the value section (at or around 19 dec). 484 * 485 * @param loc the record number to start at 486 * 487 */ 488 489 public void setLoc(int loc) 490 { 491 valueRecIterator = null; 492 log.log(log.DEBUG, "sheet.setLoc(): " + loc); 493 this.loc = loc; 494 } 495 496 /** 497 * Returns the location pointer to the first record to look for when adding rows/values 498 * 499 */ 500 501 public int getLoc() 502 { 503 log.log(log.DEBUG, "sheet.getLoc():" + loc); 504 return loc; 505 } 506 507 /** 508 * Set the preoffset when using DBCELL records (currently unused) - this is 509 * the position of this sheet within the whole file. 510 * 511 * @param offset the offset of the sheet's BOF within the file. 512 */ 513 514 public void setPreOffset(int offset) 515 { 516 this.preoffset = offset; 517 } 518 519 /** 520 * get the preoffset when using DBCELL records (currently unused) - this is 521 * the position of this sheet within the whole file. 522 * 523 * @return offset the offset of the sheet's BOF within the file. 524 */ 525 526 public int getPreOffset() 527 { 528 return preoffset; 529 } 530 531 /** 532 * Serializes all records in the sheet into one big byte array. Use this to write 533 * the sheet out. 534 * 535 * @return byte[] array containing the binary representation of the records in this sheet 536 * 537 */ 538 539 public byte [] serialize() 540 { 541 log.log(log.DEBUG, "Sheet.serialize"); 542 543 // addDBCellRecords(); 544 byte[] retval = null; 545 546 // ArrayList bytes = new ArrayList(4096); 547 int arraysize = getSize(); 548 int pos = 0; 549 550 // for (int k = 0; k < records.size(); k++) 551 // { 552 // bytes.add((( Record ) records.get(k)).serialize()); 553 // 554 // } 555 // for (int k = 0; k < bytes.size(); k++) 556 // { 557 // arraysize += (( byte [] ) bytes.get(k)).length; 558 // log.debug((new StringBuffer("arraysize=")).append(arraysize) 559 // .toString()); 560 // } 561 retval = new byte[ arraysize ]; 562 for (int k = 0; k < records.size(); k++) 563 { 564 565 // byte[] rec = (( byte [] ) bytes.get(k)); 566 // System.arraycopy(rec, 0, retval, pos, rec.length); 567 pos += (( Record ) records.get(k)).serialize(pos, 568 retval); // rec.length; 569 } 570 log.log(log.DEBUG, "Sheet.serialize returning " + retval); 571 return retval; 572 } 573 574 /** 575 * Serializes all records in the sheet into one big byte array. Use this to write 576 * the sheet out. 577 * 578 * @param offset to begin write at 579 * @param data array containing the binary representation of the records in this sheet 580 * 581 */ 582 583 public int serialize(int offset, byte [] data) 584 { 585 log.log(log.DEBUG, "Sheet.serialize using offsets"); 586 587 // addDBCellRecords(); 588 // ArrayList bytes = new ArrayList(4096); 589 // int arraysize = getSize(); // 0; 590 int pos = 0; 591 592 // for (int k = 0; k < records.size(); k++) 593 // { 594 // bytes.add((( Record ) records.get(k)).serialize()); 595 // 596 // } 597 // for (int k = 0; k < bytes.size(); k++) 598 // { 599 // arraysize += (( byte [] ) bytes.get(k)).length; 600 // log.debug((new StringBuffer("arraysize=")).append(arraysize) 601 // .toString()); 602 // } 603 for (int k = 0; k < records.size(); k++) 604 { 605 606 // byte[] rec = (( byte [] ) bytes.get(k)); 607 // System.arraycopy(rec, 0, data, offset + pos, rec.length); 608 pos += (( Record ) records.get(k)).serialize(pos + offset, 609 data); // rec.length; 610 } 611 log.log(log.DEBUG, "Sheet.serialize returning "); 612 return pos; 613 } 614 615 /** 616 * Create a row record. (does not add it to the records contained in this sheet) 617 * 618 * @param row number 619 * @return RowRecord created for the passed in row number 620 * @see org.apache.poi.hssf.record.RowRecord 621 */ 622 623 public RowRecord createRow(int row) 624 { 625 log.log(log.DEBUG, "create row number " + row); 626 RowRecord rowrec = new RowRecord(); 627 628 rowrec.setRowNumber(( short ) row); 629 rowrec.setHeight(( short ) 0xff); 630 rowrec.setOptimize(( short ) 0x0); 631 rowrec.setOptionFlags(( short ) 0x0); 632 rowrec.setXFIndex(( short ) 0x0); 633 return rowrec; 634 } 635 636 /** 637 * Create a LABELSST Record (does not add it to the records contained in this sheet) 638 * 639 * @param row the row the LabelSST is a member of 640 * @param col the column the LabelSST defines 641 * @param index the index of the string within the SST (use workbook addSSTString method) 642 * @return LabelSSTRecord newly created containing your SST Index, row,col. 643 * @see org.apache.poi.hssf.record.SSTRecord 644 */ 645 646 public LabelSSTRecord createLabelSST(short row, short col, int index) 647 { 648 log.logFormatted(log.DEBUG, "create labelsst row,col,index %,%,%", 649 new int[] 650 { 651 row, col, index 652 }); 653 LabelSSTRecord rec = new LabelSSTRecord(); 654 655 rec.setRow(row); 656 rec.setColumn(col); 657 rec.setSSTIndex(index); 658 rec.setXFIndex(( short ) 0x0f); 659 return rec; 660 } 661 662 /** 663 * Create a NUMBER Record (does not add it to the records contained in this sheet) 664 * 665 * @param row the row the NumberRecord is a member of 666 * @param col the column the NumberRecord defines 667 * @param value for the number record 668 * 669 * @return NumberRecord for that row, col containing that value as added to the sheet 670 */ 671 672 public NumberRecord createNumber(short row, short col, double value) 673 { 674 log.logFormatted(log.DEBUG, "create number row,col,value %,%,%", 675 new double[] 676 { 677 row, col, value 678 }); 679 NumberRecord rec = new NumberRecord(); 680 681 rec.setRow(( short ) row); 682 rec.setColumn(col); 683 rec.setValue(value); 684 rec.setXFIndex(( short ) 0x0f); 685 return rec; 686 } 687 688 /** 689 * create a BLANK record (does not add it to the records contained in this sheet) 690 * 691 * @param row - the row the BlankRecord is a member of 692 * @param col - the column the BlankRecord is a member of 693 */ 694 695 public BlankRecord createBlank(short row, short col) 696 { 697 log.logFormatted(log.DEBUG, "create blank row,col %,%", new short[] 698 { 699 row, col 700 }); 701 BlankRecord rec = new BlankRecord(); 702 703 rec.setRow(( short ) row); 704 rec.setColumn(col); 705 rec.setXFIndex(( short ) 0x0f); 706 return rec; 707 } 708 709 /** 710 * Attempts to parse the formula into PTGs and create a formula record 711 * DOES NOT WORK YET 712 * 713 * @param row - the row for the formula record 714 * @param col - the column of the formula record 715 * @param formula - a String representing the formula. To be parsed to PTGs 716 * @return bogus/useless formula record 717 */ 718 719 public FormulaRecord createFormula(short row, short col, String formula) 720 { 721 log.logFormatted(log.DEBUG, "create formula row,col,formula %,%,%", 722 new short[] 723 { 724 row, col 725 }, formula); 726 FormulaRecord rec = new FormulaRecord(); 727 728 rec.setRow(row); 729 rec.setColumn(col); 730 rec.setOptions(( short ) 2); 731 rec.setValue(0); 732 rec.setXFIndex(( short ) 0x0f); 733 FormulaParser fp = new FormulaParser(formula); 734 fp.parse(); 735 Ptg[] ptg = fp.getRPNPtg(); 736 int size = 0; 737 738 for (int k = 0; k < ptg.length; k++) 739 { 740 size += ptg[ k ].getSize(); 741 rec.pushExpressionToken(ptg[ k ]); 742 } 743 rec.setExpressionLength(( short ) size); 744 return rec; 745 } 746 747 /** 748 * Adds a value record to the sheet's contained binary records 749 * (i.e. LabelSSTRecord or NumberRecord). 750 * <P> 751 * This method is "loc" sensitive. Meaning you need to set LOC to where you 752 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 753 * When adding several rows you can just start at the last one by leaving loc 754 * at what this sets it to. 755 * 756 * @param row the row to add the cell value to 757 * @param col the cell value record itself. 758 */ 759 760 public void addValueRecord(short row, CellValueRecordInterface col) 761 { 762 checkCells(); 763 log.logFormatted(log.DEBUG, "add value record row,loc %,%", new int[] 764 { 765 row, loc 766 }); 767 DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); 768 769 if (col.getColumn() > d.getLastCol()) 770 { 771 d.setLastCol(( short ) (col.getColumn() + 1)); 772 } 773 if (col.getColumn() < d.getFirstCol()) 774 { 775 d.setFirstCol(col.getColumn()); 776 } 777 cells.insertCell(col); 778 779 /* 780 * for (int k = loc; k < records.size(); k++) 781 * { 782 * Record rec = ( Record ) records.get(k); 783 * 784 * if (rec.getSid() == RowRecord.sid) 785 * { 786 * RowRecord rowrec = ( RowRecord ) rec; 787 * 788 * if (rowrec.getRowNumber() == col.getRow()) 789 * { 790 * records.add(k + 1, col); 791 * loc = k; 792 * if (rowrec.getLastCol() <= col.getColumn()) 793 * { 794 * rowrec.setLastCol((( short ) (col.getColumn() + 1))); 795 * } 796 * break; 797 * } 798 * } 799 * } 800 */ 801 } 802 803 /** 804 * remove a value record from the records array. 805 * 806 * This method is not loc sensitive, it resets loc to = dimsloc so no worries. 807 * 808 * @param row - the row of the value record you wish to remove 809 * @param col - a record supporting the CellValueRecordInterface. 810 * @see org.apache.poi.hssf.record.CellValueRecordInterface 811 */ 812 813 public void removeValueRecord(short row, CellValueRecordInterface col) 814 { 815 checkCells(); 816 log.logFormatted(log.DEBUG, "remove value record row,dimsloc %,%", 817 new int[] 818 { 819 row, dimsloc 820 }); 821 loc = dimsloc; 822 cells.removeCell(col); 823 824 /* 825 * for (int k = loc; k < records.size(); k++) 826 * { 827 * Record rec = ( Record ) records.get(k); 828 * 829 * // checkDimsLoc(rec,k); 830 * if (rec.isValue()) 831 * { 832 * CellValueRecordInterface cell = 833 * ( CellValueRecordInterface ) rec; 834 * 835 * if ((cell.getRow() == col.getRow()) 836 * && (cell.getColumn() == col.getColumn())) 837 * { 838 * records.remove(k); 839 * break; 840 * } 841 * } 842 * } 843 */ 844 } 845 846 /** 847 * replace a value record from the records array. 848 * 849 * This method is not loc sensitive, it resets loc to = dimsloc so no worries. 850 * 851 * @param newval - a record supporting the CellValueRecordInterface. this will replace 852 * the cell value with the same row and column. If there isn't one, one will 853 * be added. 854 */ 855 856 public void replaceValueRecord(CellValueRecordInterface newval) 857 { 858 checkCells(); 859 setLoc(dimsloc); 860 log.log(log.DEBUG, "replaceValueRecord "); 861 cells.insertCell(newval); 862 863 /* 864 * CellValueRecordInterface oldval = getNextValueRecord(); 865 * 866 * while (oldval != null) 867 * { 868 * if (oldval.isEqual(newval)) 869 * { 870 * records.set(( short ) (getLoc() - 1), newval); 871 * return; 872 * } 873 * oldval = getNextValueRecord(); 874 * } 875 * addValueRecord(newval.getRow(), newval); 876 * setLoc(dimsloc); 877 */ 878 } 879 880 /** 881 * Adds a row record to the sheet 882 * 883 * <P> 884 * This method is "loc" sensitive. Meaning you need to set LOC to where you 885 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 886 * When adding several rows you can just start at the last one by leaving loc 887 * at what this sets it to. 888 * 889 * @param row the row record to be added 890 * @see #setLoc(int) 891 */ 892 893 public void addRow(RowRecord row) 894 { 895 checkRows(); 896 log.log(log.DEBUG, "addRow "); 897 DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); 898 899 if (row.getRowNumber() > d.getLastRow()) 900 { 901 d.setLastRow(row.getRowNumber() + 1); 902 } 903 if (row.getRowNumber() < d.getFirstRow()) 904 { 905 d.setFirstRow(row.getRowNumber()); 906 } 907 //IndexRecord index = null; 908 909 rows.insertRow(row); 910 911 /* 912 * for (int k = loc; k < records.size(); k++) 913 * { 914 * Record rec = ( Record ) records.get(k); 915 * 916 * if (rec.getSid() == IndexRecord.sid) 917 * { 918 * index = ( IndexRecord ) rec; 919 * } 920 * if (rec.getSid() == RowRecord.sid) 921 * { 922 * RowRecord rowrec = ( RowRecord ) rec; 923 * 924 * if (rowrec.getRowNumber() > row.getRowNumber()) 925 * { 926 * records.add(k, row); 927 * loc = k; 928 * break; 929 * } 930 * } 931 * if (rec.getSid() == WindowTwoRecord.sid) 932 * { 933 * records.add(k, row); 934 * loc = k; 935 * break; 936 * } 937 * } 938 * if (index != null) 939 * { 940 * if (index.getLastRowAdd1() <= row.getRowNumber()) 941 * { 942 * index.setLastRowAdd1(row.getRowNumber() + 1); 943 * } 944 * } 945 */ 946 log.log(log.DEBUG, "exit addRow"); 947 } 948 949 /** 950 * Removes a row record 951 * 952 * This method is not loc sensitive, it resets loc to = dimsloc so no worries. 953 * 954 * @param row the row record to remove 955 */ 956 957 public void removeRow(RowRecord row) 958 { 959 checkRows(); 960 // IndexRecord index = null; 961 962 setLoc(getDimsLoc()); 963 rows.removeRow(row); 964 965 /* 966 * for (int k = loc; k < records.size(); k++) 967 * { 968 * Record rec = ( Record ) records.get(k); 969 * 970 * // checkDimsLoc(rec,k); 971 * if (rec.getSid() == RowRecord.sid) 972 * { 973 * RowRecord rowrec = ( RowRecord ) rec; 974 * 975 * if (rowrec.getRowNumber() == row.getRowNumber()) 976 * { 977 * records.remove(k); 978 * break; 979 * } 980 * } 981 * if (rec.getSid() == WindowTwoRecord.sid) 982 * { 983 * break; 984 * } 985 * } 986 */ 987 } 988 989 /** 990 * get the NEXT value record (from LOC). The first record that is a value record 991 * (starting at LOC) will be returned. 992 * 993 * <P> 994 * This method is "loc" sensitive. Meaning you need to set LOC to where you 995 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 996 * When adding several rows you can just start at the last one by leaving loc 997 * at what this sets it to. For this method, set loc to dimsloc to start with, 998 * subsequent calls will return values in (physical) sequence or NULL when you get to the end. 999 * 1000 * @return CellValueRecordInterface representing the next value record or NULL if there are no more 1001 * @see #setLoc(int) 1002 */ 1003 1004 public CellValueRecordInterface getNextValueRecord() 1005 { 1006 log.log(log.DEBUG, "getNextValue loc= " + loc); 1007 if (valueRecIterator == null) 1008 { 1009 valueRecIterator = cells.getIterator(); 1010 } 1011 if (!valueRecIterator.hasNext()) 1012 { 1013 return null; 1014 } 1015 return ( CellValueRecordInterface ) valueRecIterator.next(); 1016 1017 /* 1018 * if (this.getLoc() < records.size()) 1019 * { 1020 * for (int k = getLoc(); k < records.size(); k++) 1021 * { 1022 * Record rec = ( Record ) records.get(k); 1023 * 1024 * this.setLoc(k + 1); 1025 * if (rec instanceof CellValueRecordInterface) 1026 * { 1027 * return ( CellValueRecordInterface ) rec; 1028 * } 1029 * } 1030 * } 1031 * return null; 1032 */ 1033 } 1034 1035 /** 1036 * get the NEXT RowRecord or CellValueRecord(from LOC). The first record that 1037 * is a Row record or CellValueRecord(starting at LOC) will be returned. 1038 * <P> 1039 * This method is "loc" sensitive. Meaning you need to set LOC to where you 1040 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 1041 * When adding several rows you can just start at the last one by leaving loc 1042 * at what this sets it to. For this method, set loc to dimsloc to start with. 1043 * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. 1044 * 1045 * @return RowRecord representing the next row record or CellValueRecordInterface 1046 * representing the next cellvalue or NULL if there are no more 1047 * @see #setLoc(int) 1048 * 1049 */ 1050 1051 /* public Record getNextRowOrValue() 1052 { 1053 log.debug((new StringBuffer("getNextRow loc= ")).append(loc) 1054 .toString()); 1055 if (this.getLoc() < records.size()) 1056 { 1057 for (int k = this.getLoc(); k < records.size(); k++) 1058 { 1059 Record rec = ( Record ) records.get(k); 1060 1061 this.setLoc(k + 1); 1062 if (rec.getSid() == RowRecord.sid) 1063 { 1064 return rec; 1065 } 1066 else if (rec.isValue()) 1067 { 1068 return rec; 1069 } 1070 } 1071 } 1072 return null; 1073 } 1074 */ 1075 1076 /** 1077 * get the NEXT RowRecord (from LOC). The first record that is a Row record 1078 * (starting at LOC) will be returned. 1079 * <P> 1080 * This method is "loc" sensitive. Meaning you need to set LOC to where you 1081 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 1082 * When adding several rows you can just start at the last one by leaving loc 1083 * at what this sets it to. For this method, set loc to dimsloc to start with. 1084 * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. 1085 * 1086 * @return RowRecord representing the next row record or NULL if there are no more 1087 * @see #setLoc(int) 1088 * 1089 */ 1090 1091 public RowRecord getNextRow() 1092 { 1093 log.log(log.DEBUG, "getNextRow loc= " + loc); 1094 if (rowRecIterator == null) 1095 { 1096 rowRecIterator = rows.getIterator(); 1097 } 1098 if (!rowRecIterator.hasNext()) 1099 { 1100 return null; 1101 } 1102 return ( RowRecord ) rowRecIterator.next(); 1103 1104 /* if (this.getLoc() < records.size()) 1105 { 1106 for (int k = this.getLoc(); k < records.size(); k++) 1107 { 1108 Record rec = ( Record ) records.get(k); 1109 1110 this.setLoc(k + 1); 1111 if (rec.getSid() == RowRecord.sid) 1112 { 1113 return ( RowRecord ) rec; 1114 } 1115 } 1116 }*/ 1117 } 1118 1119 /** 1120 * get the NEXT (from LOC) RowRecord where rownumber matches the given rownum. 1121 * The first record that is a Row record (starting at LOC) that has the 1122 * same rownum as the given rownum will be returned. 1123 * <P> 1124 * This method is "loc" sensitive. Meaning you need to set LOC to where you 1125 * want it to start searching. If you don't know do this: setLoc(getDimsLoc). 1126 * When adding several rows you can just start at the last one by leaving loc 1127 * at what this sets it to. For this method, set loc to dimsloc to start with. 1128 * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. 1129 * 1130 * @param rownum which row to return (careful with LOC) 1131 * @return RowRecord representing the next row record or NULL if there are no more 1132 * @see #setLoc(int) 1133 * 1134 */ 1135 1136 public RowRecord getRow(short rownum) 1137 { 1138 log.log(log.DEBUG, "getNextRow loc= " + loc); 1139 return rows.getRow(rownum); 1140 1141 /* 1142 * if (this.getLoc() < records.size()) 1143 * { 1144 * for (int k = this.getLoc(); k < records.size(); k++) 1145 * { 1146 * Record rec = ( Record ) records.get(k); 1147 * 1148 * this.setLoc(k + 1); 1149 * if (rec.getSid() == RowRecord.sid) 1150 * { 1151 * if ((( RowRecord ) rec).getRowNumber() == rownum) 1152 * { 1153 * return ( RowRecord ) rec; 1154 * } 1155 * } 1156 * } 1157 * } 1158 */ 1159 1160 // return null; 1161 } 1162 1163 /** 1164 * Not currently used method to calculate and add dbcell records 1165 * 1166 */ 1167 1168 public void addDBCellRecords() 1169 { 1170 int offset = 0; 1171 int recnum = 0; 1172 int rownum = 0; 1173 //int lastrow = 0; 1174 //long lastrowoffset = 0; 1175 IndexRecord index = null; 1176 1177 // ArrayList rowOffsets = new ArrayList(); 1178 IntList rowOffsets = new IntList(); 1179 1180 for (recnum = 0; recnum < records.size(); recnum++) 1181 { 1182 Record rec = ( Record ) records.get(recnum); 1183 1184 if (rec.getSid() == IndexRecord.sid) 1185 { 1186 index = ( IndexRecord ) rec; 1187 } 1188 if (rec.getSid() != RowRecord.sid) 1189 { 1190 offset += rec.serialize().length; 1191 } 1192 else 1193 { 1194 break; 1195 } 1196 } 1197 1198 // First Row Record 1199 for (; recnum < records.size(); recnum++) 1200 { 1201 Record rec = ( Record ) records.get(recnum); 1202 1203 if (rec.getSid() == RowRecord.sid) 1204 { 1205 rownum++; 1206 rowOffsets.add(offset); 1207 if ((rownum % 32) == 0) 1208 { 1209 1210 // if this is the last rec in a dbcell block 1211 // find the next row or last value record 1212 for (int rn = recnum; rn < records.size(); rn++) 1213 { 1214 rec = ( Record ) records.get(rn); 1215 if ((!rec.isInValueSection()) 1216 || (rec.getSid() == RowRecord.sid)) 1217 { 1218 1219 // here is the next row or last value record 1220 records.add(rn, 1221 createDBCell(offset, rowOffsets, 1222 index)); 1223 recnum = rn; 1224 break; 1225 } 1226 } 1227 } 1228 else 1229 { 1230 } 1231 } 1232 if (!rec.isInValueSection()) 1233 { 1234 records.add(recnum, createDBCell(offset, rowOffsets, index)); 1235 break; 1236 } 1237 offset += rec.serialize().length; 1238 } 1239 } 1240 1241 /** not currently used */ 1242 1243 private DBCellRecord createDBCell(int offset, IntList rowoffsets, 1244 IndexRecord index) 1245 { 1246 DBCellRecord rec = new DBCellRecord(); 1247 1248 rec.setRowOffset(offset - rowoffsets.get(0)); 1249 1250 // test hack 1251 rec.addCellOffset(( short ) 0x0); 1252 1253 // end test hack 1254 addDbCellToIndex(offset, index); 1255 return rec; 1256 } 1257 1258 /** not currently used */ 1259 1260 private void addDbCellToIndex(int offset, IndexRecord index) 1261 { 1262 int numdbcells = index.getNumDbcells() + 1; 1263 1264 index.addDbcell(offset + preoffset); 1265 1266 // stupid but whenever we add an offset that causes everything to be shifted down 4 1267 for (int k = 0; k < numdbcells; k++) 1268 { 1269 int dbval = index.getDbcellAt(k); 1270 1271 index.setDbcell(k, dbval + 4); 1272 } 1273 } 1274 1275 /** 1276 * creates the BOF record 1277 * @see org.apache.poi.hssf.record.BOFRecord 1278 * @see org.apache.poi.hssf.record.Record 1279 * @return record containing a BOFRecord 1280 */ 1281 1282 protected Record createBOF() 1283 { 1284 BOFRecord retval = new BOFRecord(); 1285 1286 retval.setVersion(( short ) 0x600); 1287 retval.setType(( short ) 0x010); 1288 1289 // retval.setBuild((short)0x10d3); 1290 retval.setBuild(( short ) 0x0dbb); 1291 retval.setBuildYear(( short ) 1996); 1292 retval.setHistoryBitMask(0xc1); 1293 retval.setRequiredVersion(0x6); 1294 return retval; 1295 } 1296 1297 /** 1298 * creates the Index record - not currently used 1299 * @see org.apache.poi.hssf.record.IndexRecord 1300 * @see org.apache.poi.hssf.record.Record 1301 * @return record containing a IndexRecord 1302 */ 1303 1304 protected Record createIndex() 1305 { 1306 IndexRecord retval = new IndexRecord(); 1307 1308 retval.setFirstRow(0); // must be set explicitly 1309 retval.setLastRowAdd1(0); 1310 return retval; 1311 } 1312 1313 /** 1314 * creates the CalcMode record and sets it to 1 (automatic formula caculation) 1315 * @see org.apache.poi.hssf.record.CalcModeRecord 1316 * @see org.apache.poi.hssf.record.Record 1317 * @return record containing a CalcModeRecord 1318 */ 1319 1320 protected Record createCalcMode() 1321 { 1322 CalcModeRecord retval = new CalcModeRecord(); 1323 1324 retval.setCalcMode(( short ) 1); 1325 return retval; 1326 } 1327 1328 /** 1329 * creates the CalcCount record and sets it to 0x64 (default number of iterations) 1330 * @see org.apache.poi.hssf.record.CalcCountRecord 1331 * @see org.apache.poi.hssf.record.Record 1332 * @return record containing a CalcCountRecord 1333 */ 1334 1335 protected Record createCalcCount() 1336 { 1337 CalcCountRecord retval = new CalcCountRecord(); 1338 1339 retval.setIterations(( short ) 0x64); // default 64 iterations 1340 return retval; 1341 } 1342 1343 /** 1344 * creates the RefMode record and sets it to A1 Mode (default reference mode) 1345 * @see org.apache.poi.hssf.record.RefModeRecord 1346 * @see org.apache.poi.hssf.record.Record 1347 * @return record containing a RefModeRecord 1348 */ 1349 1350 protected Record createRefMode() 1351 { 1352 RefModeRecord retval = new RefModeRecord(); 1353 1354 retval.setMode(retval.USE_A1_MODE); 1355 return retval; 1356 } 1357 1358 /** 1359 * creates the Iteration record and sets it to false (don't iteratively calculate formulas) 1360 * @see org.apache.poi.hssf.record.IterationRecord 1361 * @see org.apache.poi.hssf.record.Record 1362 * @return record containing a IterationRecord 1363 */ 1364 1365 protected Record createIteration() 1366 { 1367 IterationRecord retval = new IterationRecord(); 1368 1369 retval.setIteration(false); 1370 return retval; 1371 } 1372 1373 /** 1374 * creates the Delta record and sets it to 0.0010 (default accuracy) 1375 * @see org.apache.poi.hssf.record.DeltaRecord 1376 * @see org.apache.poi.hssf.record.Record 1377 * @return record containing a DeltaRecord 1378 */ 1379 1380 protected Record createDelta() 1381 { 1382 DeltaRecord retval = new DeltaRecord(); 1383 1384 retval.setMaxChange((( double ) 0.0010)); 1385 return retval; 1386 } 1387 1388 /** 1389 * creates the SaveRecalc record and sets it to true (recalculate before saving) 1390 * @see org.apache.poi.hssf.record.SaveRecalcRecord 1391 * @see org.apache.poi.hssf.record.Record 1392 * @return record containing a SaveRecalcRecord 1393 */ 1394 1395 protected Record createSaveRecalc() 1396 { 1397 SaveRecalcRecord retval = new SaveRecalcRecord(); 1398 1399 retval.setRecalc(true); 1400 return retval; 1401 } 1402 1403 /** 1404 * creates the PrintHeaders record and sets it to false (we don't create headers yet so why print them) 1405 * @see org.apache.poi.hssf.record.PrintHeadersRecord 1406 * @see org.apache.poi.hssf.record.Record 1407 * @return record containing a PrintHeadersRecord 1408 */ 1409 1410 protected Record createPrintHeaders() 1411 { 1412 PrintHeadersRecord retval = new PrintHeadersRecord(); 1413 1414 retval.setPrintHeaders(false); 1415 return retval; 1416 } 1417 1418 /** 1419 * creates the PrintGridlines record and sets it to false (that makes for ugly sheets). As far as I can 1420 * tell this does the same thing as the GridsetRecord 1421 * 1422 * @see org.apache.poi.hssf.record.PrintGridlinesRecord 1423 * @see org.apache.poi.hssf.record.Record 1424 * @return record containing a PrintGridlinesRecord 1425 */ 1426 1427 protected Record createPrintGridlines() 1428 { 1429 PrintGridlinesRecord retval = new PrintGridlinesRecord(); 1430 1431 retval.setPrintGridlines(false); 1432 return retval; 1433 } 1434 1435 /** 1436 * creates the Gridset record and sets it to true (user has mucked with the gridlines) 1437 * @see org.apache.poi.hssf.record.GridsetRecord 1438 * @see org.apache.poi.hssf.record.Record 1439 * @return record containing a GridsetRecord 1440 */ 1441 1442 protected Record createGridset() 1443 { 1444 GridsetRecord retval = new GridsetRecord(); 1445 1446 retval.setGridset(true); 1447 return retval; 1448 } 1449 1450 /** 1451 * creates the Guts record and sets leftrow/topcol guttter and rowlevelmax/collevelmax to 0 1452 * @see org.apache.poi.hssf.record.GutsRecord 1453 * @see org.apache.poi.hssf.record.Record 1454 * @return record containing a GutsRecordRecord 1455 */ 1456 1457 protected Record createGuts() 1458 { 1459 GutsRecord retval = new GutsRecord(); 1460 1461 retval.setLeftRowGutter(( short ) 0); 1462 retval.setTopColGutter(( short ) 0); 1463 retval.setRowLevelMax(( short ) 0); 1464 retval.setColLevelMax(( short ) 0); 1465 return retval; 1466 } 1467 1468 /** 1469 * creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff 1470 * @see org.apache.poi.hssf.record.DefaultRowHeightRecord 1471 * @see org.apache.poi.hssf.record.Record 1472 * @return record containing a DefaultRowHeightRecord 1473 */ 1474 1475 protected Record createDefaultRowHeight() 1476 { 1477 DefaultRowHeightRecord retval = new DefaultRowHeightRecord(); 1478 1479 retval.setOptionFlags(( short ) 0); 1480 retval.setRowHeight(( short ) 0xff); 1481 return retval; 1482 } 1483 1484 /** 1485 * creates the WSBoolRecord and sets its values to defaults 1486 * @see org.apache.poi.hssf.record.WSBoolRecord 1487 * @see org.apache.poi.hssf.record.Record 1488 * @return record containing a WSBoolRecord 1489 */ 1490 1491 protected Record createWSBool() 1492 { 1493 WSBoolRecord retval = new WSBoolRecord(); 1494 1495 retval.setWSBool1(( byte ) 0x4); 1496 retval.setWSBool2(( byte ) 0xffffffc1); 1497 return retval; 1498 } 1499 1500 /** 1501 * creates the Header Record and sets it to nothing/0 length 1502 * @see org.apache.poi.hssf.record.HeaderRecord 1503 * @see org.apache.poi.hssf.record.Record 1504 * @return record containing a HeaderRecord 1505 */ 1506 1507 protected Record createHeader() 1508 { 1509 HeaderRecord retval = new HeaderRecord(); 1510 1511 retval.setHeaderLength(( byte ) 0); 1512 retval.setHeader(null); 1513 return retval; 1514 } 1515 1516 /** 1517 * creates the Footer Record and sets it to nothing/0 length 1518 * @see org.apache.poi.hssf.record.FooterRecord 1519 * @see org.apache.poi.hssf.record.Record 1520 * @return record containing a FooterRecord 1521 */ 1522 1523 protected Record createFooter() 1524 { 1525 FooterRecord retval = new FooterRecord(); 1526 1527 retval.setFooterLength(( byte ) 0); 1528 retval.setFooter(null); 1529 return retval; 1530 } 1531 1532 /** 1533 * creates the HCenter Record and sets it to false (don't horizontally center) 1534 * @see org.apache.poi.hssf.record.HCenterRecord 1535 * @see org.apache.poi.hssf.record.Record 1536 * @return record containing a HCenterRecord 1537 */ 1538 1539 protected Record createHCenter() 1540 { 1541 HCenterRecord retval = new HCenterRecord(); 1542 1543 retval.setHCenter(false); 1544 return retval; 1545 } 1546 1547 /** 1548 * creates the VCenter Record and sets it to false (don't horizontally center) 1549 * @see org.apache.poi.hssf.record.VCenterRecord 1550 * @see org.apache.poi.hssf.record.Record 1551 * @return record containing a VCenterRecord 1552 */ 1553 1554 protected Record createVCenter() 1555 { 1556 VCenterRecord retval = new VCenterRecord(); 1557 1558 retval.setVCenter(false); 1559 return retval; 1560 } 1561 1562 /** 1563 * creates the PrintSetup Record and sets it to defaults and marks it invalid 1564 * @see org.apache.poi.hssf.record.PrintSetupRecord 1565 * @see org.apache.poi.hssf.record.Record 1566 * @return record containing a PrintSetupRecord 1567 */ 1568 1569 protected Record createPrintSetup() 1570 { 1571 PrintSetupRecord retval = new PrintSetupRecord(); 1572 1573 retval.setPaperSize(( short ) 1); 1574 retval.setScale(( short ) 100); 1575 retval.setPageStart(( short ) 1); 1576 retval.setFitWidth(( short ) 1); 1577 retval.setFitHeight(( short ) 1); 1578 retval.setOptions(( short ) 2); 1579 retval.setHResolution(( short ) 300); 1580 retval.setVResolution(( short ) 300); 1581 retval.setHeaderMargin(( double ) 0.5); 1582 retval.setFooterMargin(( double ) 0.5); 1583 retval.setCopies(( short ) 0); 1584 return retval; 1585 } 1586 1587 /** 1588 * creates the DefaultColWidth Record and sets it to 8 1589 * @see org.apache.poi.hssf.record.DefaultColWidthRecord 1590 * @see org.apache.poi.hssf.record.Record 1591 * @return record containing a DefaultColWidthRecord 1592 */ 1593 1594 protected Record createDefaultColWidth() 1595 { 1596 DefaultColWidthRecord retval = new DefaultColWidthRecord(); 1597 1598 retval.setColWidth(( short ) 8); 1599 return retval; 1600 } 1601 1602 /** 1603 * creates the ColumnInfo Record and sets it to a default column/width 1604 * @see org.apache.poi.hssf.record.ColumnInfoRecord 1605 * @return record containing a ColumnInfoRecord 1606 */ 1607 1608 protected Record createColInfo() 1609 { 1610 ColumnInfoRecord retval = new ColumnInfoRecord(); 1611 1612 retval.setColumnWidth(( short ) 0x8); 1613 retval.setOptions(( short ) 6); 1614 retval.setXFIndex(( short ) 0x0f); 1615 return retval; 1616 } 1617 1618 /** 1619 * get the default column width for the sheet (if the columns do not define their own width) 1620 * @return default column width 1621 */ 1622 1623 public short getDefaultColumnWidth() 1624 { 1625 return defaultcolwidth.getColWidth(); 1626 } 1627 1628 /** 1629 * get whether gridlines are printed. 1630 * @return true if printed 1631 */ 1632 1633 public boolean isGridsPrinted() 1634 { 1635 return !gridset.getGridset(); 1636 } 1637 1638 /** 1639 * set whether gridlines printed or not. 1640 * @param value True if gridlines printed. 1641 */ 1642 1643 public void setGridsPrinted(boolean value) 1644 { 1645 gridset.setGridset(!value); 1646 } 1647 1648 /** 1649 * set the default column width for the sheet (if the columns do not define their own width) 1650 * @param dcw default column width 1651 */ 1652 1653 public void setDefaultColumnWidth(short dcw) 1654 { 1655 defaultcolwidth.setColWidth(dcw); 1656 } 1657 1658 /** 1659 * set the default row height for the sheet (if the rows do not define their own height) 1660 */ 1661 1662 public void setDefaultRowHeight(short dch) 1663 { 1664 defaultrowheight.setRowHeight(dch); 1665 } 1666 1667 /** 1668 * get the default row height for the sheet (if the rows do not define their own height) 1669 * @return default row height 1670 */ 1671 1672 public short getDefaultRowHeight() 1673 { 1674 return defaultrowheight.getRowHeight(); 1675 } 1676 1677 /** 1678 * get the width of a given column in units of 1/20th of a point width (twips?) 1679 * @param column index 1680 * @see org.apache.poi.hssf.record.DefaultColWidthRecord 1681 * @see org.apache.poi.hssf.record.ColumnInfoRecord 1682 * @see #setColumnWidth(short,short) 1683 * @return column width in units of 1/20th of a point (twips?) 1684 */ 1685 1686 public short getColumnWidth(short column) 1687 { 1688 short retval = 0; 1689 ColumnInfoRecord ci = null; 1690 int k = 0; 1691 1692 if (columnSizes != null) 1693 { 1694 for (k = 0; k < columnSizes.size(); k++) 1695 { 1696 ci = ( ColumnInfoRecord ) columnSizes.get(k); 1697 if ((ci.getFirstColumn() >= column) 1698 && (ci.getLastColumn() <= column)) 1699 { 1700 break; 1701 } 1702 ci = null; 1703 } 1704 } 1705 if (ci != null) 1706 { 1707 retval = ci.getColumnWidth(); 1708 } 1709 else 1710 { 1711 retval = defaultcolwidth.getColWidth(); 1712 } 1713 return retval; 1714 } 1715 1716 /** 1717 * set the width for a given column in 1/20th of a character width units 1718 * @param column - the column number 1719 * @param width (in units of 1/20th of a character width) 1720 */ 1721 1722 public void setColumnWidth(short column, short width) 1723 { 1724 ColumnInfoRecord ci = null; 1725 int k = 0; 1726 1727 if (columnSizes == null) 1728 { 1729 columnSizes = new ArrayList(); 1730 } 1731 //int cioffset = getDimsLoc() - columnSizes.size(); 1732 1733 for (k = 0; k < columnSizes.size(); k++) 1734 { 1735 ci = ( ColumnInfoRecord ) columnSizes.get(k); 1736 if ((ci.getFirstColumn() >= column) 1737 && (ci.getLastColumn() <= column)) 1738 { 1739 break; 1740 } 1741 ci = null; 1742 } 1743 if (ci != null) 1744 { 1745 if (ci.getColumnWidth() == width) 1746 { 1747 1748 // do nothing...the cell's width is equal to what we're setting it to. 1749 } 1750 else if ((ci.getFirstColumn() == column) 1751 && (ci.getLastColumn() == column)) 1752 { // if its only for this cell then 1753 ci.setColumnWidth(width); // who cares, just change the width 1754 } 1755 else if ((ci.getFirstColumn() == column) 1756 || (ci.getLastColumn() == column)) 1757 { 1758 1759 // okay so the width is different but the first or last column == the column we'return setting 1760 // we'll just divide the info and create a new one 1761 if (ci.getFirstColumn() == column) 1762 { 1763 ci.setFirstColumn(( short ) (column + 1)); 1764 } 1765 else 1766 { 1767 ci.setLastColumn(( short ) (column - 1)); 1768 } 1769 ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); 1770 1771 nci.setFirstColumn(column); 1772 nci.setLastColumn(column); 1773 nci.setOptions(ci.getOptions()); 1774 nci.setXFIndex(ci.getXFIndex()); 1775 nci.setColumnWidth(width); 1776 columnSizes.add(k, nci); 1777 records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); 1778 dimsloc++; 1779 } 1780 } 1781 else 1782 { 1783 1784 // okay so there ISN'T a column info record that cover's this column so lets create one! 1785 ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); 1786 1787 nci.setFirstColumn(column); 1788 nci.setLastColumn(column); 1789 nci.setColumnWidth(width); 1790 columnSizes.add(k, nci); 1791 records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); 1792 dimsloc++; 1793 } 1794 } 1795 1796 /** 1797 * creates the Dimensions Record and sets it to bogus values (you should set this yourself 1798 * or let the high level API do it for you) 1799 * @see org.apache.poi.hssf.record.DimensionsRecord 1800 * @see org.apache.poi.hssf.record.Record 1801 * @return record containing a DimensionsRecord 1802 */ 1803 1804 protected Record createDimensions() 1805 { 1806 DimensionsRecord retval = new DimensionsRecord(); 1807 1808 retval.setFirstCol(( short ) 0); 1809 retval.setLastRow(1); // one more than it is 1810 retval.setFirstRow(0); 1811 retval.setLastCol(( short ) 1); // one more than it is 1812 return retval; 1813 } 1814 1815 /** 1816 * creates the WindowTwo Record and sets it to: <P> 1817 * options = 0x6b6 <P> 1818 * toprow = 0 <P> 1819 * leftcol = 0 <P> 1820 * headercolor = 0x40 <P> 1821 * pagebreakzoom = 0x0 <P> 1822 * normalzoom = 0x0 <p> 1823 * @see org.apache.poi.hssf.record.WindowTwoRecord 1824 * @see org.apache.poi.hssf.record.Record 1825 * @return record containing a WindowTwoRecord 1826 */ 1827 1828 protected Record createWindowTwo() 1829 { 1830 WindowTwoRecord retval = new WindowTwoRecord(); 1831 1832 retval.setOptions(( short ) 0x6b6); 1833 retval.setTopRow(( short ) 0); 1834 retval.setLeftCol(( short ) 0); 1835 retval.setHeaderColor(0x40); 1836 retval.setPageBreakZoom(( short ) 0); 1837 retval.setNormalZoom(( short ) 0); 1838 return retval; 1839 } 1840 1841 /** 1842 * Creates the Selection record and sets it to nothing selected 1843 * 1844 * @see org.apache.poi.hssf.record.SelectionRecord 1845 * @see org.apache.poi.hssf.record.Record 1846 * @return record containing a SelectionRecord 1847 */ 1848 1849 protected Record createSelection() 1850 { 1851 SelectionRecord retval = new SelectionRecord(); 1852 1853 retval.setPane(( byte ) 0x3); 1854 retval.setActiveCellCol(( short ) 0x0); 1855 retval.setActiveCellRow(( short ) 0x0); 1856 retval.setNumRefs(( short ) 0x0); 1857 return retval; 1858 } 1859 1860 protected Record createMergedCells() 1861 { 1862 MergeCellsRecord retval = new MergeCellsRecord(); 1863 1864 retval.setNumAreas(( short ) 0); 1865 return retval; 1866 } 1867 1868 /** 1869 * creates the EOF record 1870 * @see org.apache.poi.hssf.record.EOFRecord 1871 * @see org.apache.poi.hssf.record.Record 1872 * @return record containing a EOFRecord 1873 */ 1874 1875 protected Record createEOF() 1876 { 1877 return new EOFRecord(); 1878 } 1879 1880 /** 1881 * get the location of the DimensionsRecord (which is the last record before the value section) 1882 * @return location in the array of records of the DimensionsRecord 1883 */ 1884 1885 public int getDimsLoc() 1886 { 1887 log.log(log.DEBUG, "getDimsLoc dimsloc= " + dimsloc); 1888 return dimsloc; 1889 } 1890 1891 /** 1892 * in the event the record is a dimensions record, resets both the loc index and dimsloc index 1893 */ 1894 1895 public void checkDimsLoc(Record rec, int recloc) 1896 { 1897 if (rec.getSid() == DimensionsRecord.sid) 1898 { 1899 loc = recloc; 1900 dimsloc = recloc; 1901 } 1902 } 1903 1904 public int getSize() 1905 { 1906 int retval = 0; 1907 1908 for (int k = 0; k < records.size(); k++) 1909 { 1910 retval += (( Record ) records.get(k)).getRecordSize(); 1911 } 1912 return retval; 1913 } 1914 1915 public List getRecords() 1916 { 1917 return records; 1918 } 1919 1920 /** 1921 * Gets the gridset record for this sheet. 1922 */ 1923 1924 public GridsetRecord getGridsetRecord() 1925 { 1926 return gridset; 1927 } 1928 1929 /** 1930 * Returns the first occurance of a record matching a particular sid. 1931 */ 1932 1933 public Record findFirstRecordBySid(short sid) 1934 { 1935 for (Iterator iterator = records.iterator(); iterator.hasNext(); ) 1936 { 1937 Record record = ( Record ) iterator.next(); 1938 1939 if (record.getSid() == sid) 1940 { 1941 return record; 1942 } 1943 } 1944 return null; 1945 } 1946 1947 /** 1948 * Returns the HeaderRecord. 1949 * @return HeaderRecord for the sheet. 1950 */ 1951 public HeaderRecord getHeader () 1952 { 1953 return header; 1954 } 1955 1956 /** 1957 * Sets the HeaderRecord. 1958 * @param newHeader The new HeaderRecord for the sheet. 1959 */ 1960 public void setHeader (HeaderRecord newHeader) 1961 { 1962 header = newHeader; 1963 } 1964 1965 /** 1966 * Returns the FooterRecord. 1967 * @return FooterRecord for the sheet. 1968 */ 1969 public FooterRecord getFooter () 1970 { 1971 return footer; 1972 } 1973 1974 /** 1975 * Sets the FooterRecord. 1976 * @param newFooter The new FooterRecord for the sheet. 1977 */ 1978 public void setFooter (FooterRecord newFooter) 1979 { 1980 footer = newFooter; 1981 } 1982 1983 /** 1984 * Returns the PrintSetupRecord. 1985 * @return PrintSetupRecord for the sheet. 1986 */ 1987 public PrintSetupRecord getPrintSetup () 1988 { 1989 return printSetup; 1990 } 1991 1992 /** 1993 * Sets the PrintSetupRecord. 1994 * @param newPrintSetup The new PrintSetupRecord for the sheet. 1995 */ 1996 public void setPrintSetup (PrintSetupRecord newPrintSetup) 1997 { 1998 printSetup = newPrintSetup; 1999 } 2000 2001 /** 2002 * Returns the PrintGridlinesRecord. 2003 * @return PrintGridlinesRecord for the sheet. 2004 */ 2005 public PrintGridlinesRecord getPrintGridlines () 2006 { 2007 return printGridlines; 2008 } 2009 2010 /** 2011 * Sets the PrintGridlinesRecord. 2012 * @param newPrintGridlines The new PrintGridlinesRecord for the sheet. 2013 */ 2014 public void setPrintGridlines (PrintGridlinesRecord newPrintGridlines) 2015 { 2016 printGridlines = newPrintGridlines; 2017 } 2018 2019 } 2020