1 /* ==================================================================== 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" and 27 * "Apache POI" must not be used to endorse or promote products 28 * derived from this software without prior written permission. For 29 * written permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * "Apache POI", nor may "Apache" appear in their name, without 33 * prior written permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>. 53 */ 54 55 /* 56 * HSSFRow.java 57 * 58 * Created on September 30, 2001, 3:44 PM 59 */ 60 package org.apache.poi.hssf.usermodel; 61 62 import org.apache.poi.hssf.model.Sheet; 63 import org.apache.poi.hssf.model.Workbook; 64 import org.apache.poi.hssf.record.CellValueRecordInterface; 65 import org.apache.poi.hssf.record.RowRecord; 66 67 import java.util.HashMap; 68 import java.util.Iterator; 69 70 /** 71 * High level representation of a row of a spreadsheet. 72 * 73 * Only rows that have cells should be added to a Sheet. 74 * @version 1.0-pre 75 * @author Andrew C. Oliver (acoliver at apache dot org) 76 * @author Glen Stampoultzis (glens at apache.org) 77 */ 78 79 public class HSSFRow 80 implements Comparable 81 { 82 83 // used for collections 84 public final static int INITIAL_CAPACITY = 5; 85 //private short rowNum; 86 private int rowNum; 87 private HashMap cells; 88 // private short firstcell = -1; 89 // private short lastcell = -1; 90 91 /** 92 * reference to low level representation 93 */ 94 95 private RowRecord row; 96 97 /** 98 * reference to containing low level Workbook 99 */ 100 101 private Workbook book; 102 103 /** 104 * reference to containing Sheet 105 */ 106 107 private Sheet sheet; 108 109 protected HSSFRow() 110 { 111 } 112 113 /** 114 * Creates new HSSFRow from scratch. Only HSSFSheet should do this. 115 * 116 * @param book low-level Workbook object containing the sheet that contains this row 117 * @param sheet low-level Sheet object that contains this Row 118 * @param rowNum the row number of this row (0 based) 119 * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(short) 120 */ 121 122 //protected HSSFRow(Workbook book, Sheet sheet, short rowNum) 123 protected HSSFRow(Workbook book, Sheet sheet, int rowNum) 124 { 125 this.rowNum = rowNum; 126 cells = new HashMap(10); // new ArrayList(INITIAL_CAPACITY); 127 this.book = book; 128 this.sheet = sheet; 129 row = new RowRecord(); 130 row.setHeight((short) 0xff); 131 row.setLastCol((short) -1); 132 row.setFirstCol((short) -1); 133 134 // row.setRowNumber(rowNum); 135 setRowNum(rowNum); 136 } 137 138 /** 139 * Creates an HSSFRow from a low level RowRecord object. Only HSSFSheet should do 140 * this. HSSFSheet uses this when an existing file is read in. 141 * 142 * @param book low-level Workbook object containing the sheet that contains this row 143 * @param sheet low-level Sheet object that contains this Row 144 * @param record the low level api object this row should represent 145 * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(short) 146 */ 147 148 protected HSSFRow(Workbook book, Sheet sheet, RowRecord record) 149 { 150 //this.rowNum = rowNum; 151 cells = new HashMap(); // ArrayList(INITIAL_CAPACITY); 152 this.book = book; 153 this.sheet = sheet; 154 row = record; 155 156 // row.setHeight(record.getHeight()); 157 // row.setRowNumber(rowNum); 158 setRowNum(record.getRowNumber()); 159 160 // addColumns(book, sheet, record); 161 } 162 163 /** 164 * Use this to create new cells within the row and return it. 165 * <p> 166 * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed 167 * either through calling <code>setCellValue</code> or <code>setCellType</code>. 168 * 169 * @param column - the column number this cell represents 170 * 171 * @return HSSFCell a high level representation of the created cell. 172 */ 173 174 public HSSFCell createCell(short column) 175 { 176 HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column); 177 178 addCell(cell); 179 sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); 180 return cell; 181 } 182 183 /** 184 * Use this to create new cells within the row and return it. 185 * <p> 186 * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed 187 * either through calling setCellValue or setCellType. 188 * 189 * @param column - the column number this cell represents 190 * 191 * @return HSSFCell a high level representation of the created cell. 192 * @deprecated As of 22-Jan-2002 use createCell(short) and use setCellValue to 193 * specify the type lazily. 194 */ 195 196 public HSSFCell createCell(short column, int type) 197 { 198 HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column, type); 199 200 addCell(cell); 201 sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); 202 return cell; 203 } 204 205 /** 206 * remove the HSSFCell from this row. 207 * @param cell to remove 208 */ 209 public void removeCell(HSSFCell cell) 210 { 211 CellValueRecordInterface cval = cell.getCellValueRecord(); 212 213 sheet.removeValueRecord(getRowNum(), cval); 214 cells.remove(new Integer(cell.getCellNum())); 215 216 if (cell.getCellNum() == row.getLastCol()) 217 { 218 row.setLastCol(findLastCell(row.getLastCol())); 219 } 220 if (cell.getCellNum() == row.getFirstCol()) 221 { 222 row.setFirstCol(findFirstCell(row.getFirstCol())); 223 } 224 } 225 226 /** 227 * create a high level HSSFCell object from an existing low level record. Should 228 * only be called from HSSFSheet or HSSFRow itself. 229 * @param cell low level cell to create the high level representation from 230 * @return HSSFCell representing the low level record passed in 231 */ 232 233 protected HSSFCell createCellFromRecord(CellValueRecordInterface cell) 234 { 235 HSSFCell hcell = new HSSFCell(book, sheet, getRowNum(), cell); 236 237 addCell(hcell); 238 239 // sheet.addValueRecord(getRowNum(),cell.getCellValueRecord()); 240 return hcell; 241 } 242 243 /** 244 * set the row number of this row. 245 * @param rowNum the row number (0-based) 246 */ 247 248 //public void setRowNum(short rowNum) 249 public void setRowNum(int rowNum) 250 { 251 this.rowNum = rowNum; 252 if (row != null) 253 { 254 row.setRowNumber(rowNum); // used only for KEY comparison (HSSFRow) 255 } 256 } 257 258 /** 259 * get row number this row represents 260 * @return the row number (0 based) 261 */ 262 263 //public short getRowNum() 264 public int getRowNum() 265 { 266 return rowNum; 267 } 268 269 /** 270 * used internally to add a cell. 271 */ 272 273 private void addCell(HSSFCell cell) 274 { 275 if (row.getFirstCol() == -1) 276 { 277 row.setFirstCol(cell.getCellNum()); 278 } 279 if (row.getLastCol() == -1) 280 { 281 row.setLastCol(cell.getCellNum()); 282 } 283 cells.put(new Integer(cell.getCellNum()), cell); 284 285 if (cell.getCellNum() < row.getFirstCol()) 286 { 287 row.setFirstCol(cell.getCellNum()); 288 } 289 if (cell.getCellNum() > row.getLastCol()) 290 { 291 row.setLastCol(cell.getCellNum()); 292 } 293 } 294 295 /** 296 * get the hssfcell representing a given column (logical cell) 0-based. If you 297 * ask for a cell that is not defined....you get a null. 298 * 299 * @param cellnum 0 based column number 300 * @return HSSFCell representing that column or null if undefined. 301 */ 302 303 public HSSFCell getCell(short cellnum) 304 { 305 306 /* for (int k = 0; k < cells.size(); k++) 307 { 308 HSSFCell cell = ( HSSFCell ) cells.get(k); 309 310 if (cell.getCellNum() == cellnum) 311 { 312 return cell; 313 } 314 }*/ 315 return (HSSFCell) cells.get(new Integer(cellnum)); 316 } 317 318 /** 319 * get the number of the first cell contained in this row. 320 * @return short representing the first logical cell in the row 321 */ 322 323 public short getFirstCellNum() 324 { 325 if (getPhysicalNumberOfCells() == 0) 326 return -1; 327 else 328 return row.getFirstCol(); 329 } 330 331 /** 332 * get the number of the last cell contained in this row. 333 * @return short representing the last logical cell in the row 334 */ 335 336 public short getLastCellNum() 337 { 338 if (getPhysicalNumberOfCells() == 0) 339 return -1; 340 else 341 return row.getLastCol(); 342 } 343 344 345 /** 346 * gets the number of defined cells (NOT number of cells in the actual row!). 347 * That is to say if only columns 0,4,5 have values then there would be 3. 348 * @return int representing the number of defined cells in the row. 349 */ 350 351 public int getPhysicalNumberOfCells() 352 { 353 if (cells == null) 354 { 355 return 0; // shouldn't be possible but it is due to missing API support for BLANK/MULBLANK 356 } 357 return cells.size(); 358 } 359 360 /** 361 * set the row's height or set to ff (-1) for undefined/default-height. Set the height in "twips" or 362 * 1/20th of a point. 363 * @param height rowheight or 0xff for undefined (use sheet default) 364 */ 365 366 public void setHeight(short height) 367 { 368 369 // row.setOptionFlags( 370 row.setBadFontHeight(true); 371 row.setHeight(height); 372 } 373 374 /** 375 * set the row's height in points. 376 * @param height row height in points 377 */ 378 379 public void setHeightInPoints(float height) 380 { 381 382 // row.setOptionFlags( 383 row.setBadFontHeight(true); 384 row.setHeight((short) (height * 20)); 385 } 386 387 /** 388 * get the row's height or ff (-1) for undefined/default-height in twips (1/20th of a point) 389 * @return rowheight or 0xff for undefined (use sheet default) 390 */ 391 392 public short getHeight() 393 { 394 return row.getHeight(); 395 } 396 397 /** 398 * get the row's height or ff (-1) for undefined/default-height in points (20*getHeight()) 399 * @return rowheight or 0xff for undefined (use sheet default) 400 */ 401 402 public float getHeightInPoints() 403 { 404 return (row.getHeight() / 20); 405 } 406 407 /** 408 * get the lowlevel RowRecord represented by this object - should only be called 409 * by other parts of the high level API 410 * 411 * @return RowRecord this row represents 412 */ 413 414 protected RowRecord getRowRecord() 415 { 416 return row; 417 } 418 419 /** 420 * used internally to refresh the "last cell" when the last cell is removed. 421 */ 422 423 private short findLastCell(short lastcell) 424 { 425 short cellnum = (short) (lastcell - 1); 426 HSSFCell r = getCell(cellnum); 427 428 while (r == null && cellnum >= 0) 429 { 430 r = getCell(--cellnum); 431 } 432 return cellnum; 433 } 434 435 /** 436 * used internally to refresh the "first cell" when the first cell is removed. 437 */ 438 439 private short findFirstCell(short firstcell) 440 { 441 short cellnum = (short) (firstcell + 1); 442 HSSFCell r = getCell(cellnum); 443 444 while (r == null && cellnum <= getLastCellNum()) 445 { 446 r = getCell(++cellnum); 447 } 448 if (cellnum > getLastCellNum()) 449 return -1; 450 return cellnum; 451 } 452 453 /** 454 * @return cell iterator of the physically defined cells. Note element 4 may 455 * actually be row cell depending on how many are defined! 456 */ 457 458 public Iterator cellIterator() 459 { 460 return cells.values().iterator(); 461 } 462 463 public int compareTo(Object obj) 464 { 465 HSSFRow loc = (HSSFRow) obj; 466 467 if (this.getRowNum() == loc.getRowNum()) 468 { 469 return 0; 470 } 471 if (this.getRowNum() < loc.getRowNum()) 472 { 473 return -1; 474 } 475 if (this.getRowNum() > loc.getRowNum()) 476 { 477 return 1; 478 } 479 return -1; 480 } 481 482 public boolean equals(Object obj) 483 { 484 if (!(obj instanceof HSSFRow)) 485 { 486 return false; 487 } 488 HSSFRow loc = (HSSFRow) obj; 489 490 if (this.getRowNum() == loc.getRowNum()) 491 { 492 return true; 493 } 494 return false; 495 } 496 } 497