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