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