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 HashMap cells; 87 // private short firstcell = -1; 88 // private short lastcell = -1; 89 90 /** 91 * reference to low level representation 92 */ 93 94 private RowRecord row; 95 96 /** 97 * reference to containing low level Workbook 98 */ 99 100 private Workbook book; 101 102 /** 103 * reference to containing Sheet 104 */ 105 106 private Sheet sheet; 107 108 protected HSSFRow() 109 { 110 } 111 112 /** 113 * Creates new HSSFRow from scratch. Only HSSFSheet should do this. 114 * 115 * @param book low-level Workbook object containing the sheet that contains this row 116 * @param sheet low-level Sheet object that contains this Row 117 * @param rowNum the row number of this row (0 based) 118 * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(short) 119 */ 120 121 protected HSSFRow(Workbook book, Sheet sheet, short rowNum) 122 { 123 this.rowNum = rowNum; 124 cells = new HashMap(10); // new ArrayList(INITIAL_CAPACITY); 125 this.book = book; 126 this.sheet = sheet; 127 row = new RowRecord(); 128 row.setHeight((short) 0xff); 129 row.setLastCol((short) -1); 130 row.setFirstCol((short) -1); 131 132 // row.setRowNumber(rowNum); 133 setRowNum(rowNum); 134 } 135 136 /** 137 * Creates an HSSFRow from a low level RowRecord object. Only HSSFSheet should do 138 * this. HSSFSheet uses this when an existing file is read in. 139 * 140 * @param book low-level Workbook object containing the sheet that contains this row 141 * @param sheet low-level Sheet object that contains this Row 142 * @param record the low level api object this row should represent 143 * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(short) 144 */ 145 146 protected HSSFRow(Workbook book, Sheet sheet, RowRecord record) 147 { 148 this.rowNum = rowNum; 149 cells = new HashMap(); // ArrayList(INITIAL_CAPACITY); 150 this.book = book; 151 this.sheet = sheet; 152 row = record; 153 154 // row.setHeight(record.getHeight()); 155 // row.setRowNumber(rowNum); 156 setRowNum(record.getRowNumber()); 157 158 // addColumns(book, sheet, record); 159 } 160 161 /** 162 * Use this to create new cells within the row and return it. 163 * <p> 164 * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed 165 * either through calling <code>setCellValue</code> or <code>setCellType</code>. 166 * 167 * @param column - the column number this cell represents 168 * 169 * @return HSSFCell a high level representation of the created cell. 170 */ 171 172 public HSSFCell createCell(short column) 173 { 174 HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column); 175 176 addCell(cell); 177 sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); 178 return cell; 179 } 180 181 /** 182 * Use this to create new cells within the row and return it. 183 * <p> 184 * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed 185 * either through calling setCellValue or setCellType. 186 * 187 * @param column - the column number this cell represents 188 * 189 * @return HSSFCell a high level representation of the created cell. 190 * @deprecated As of 22-Jan-2002 use createCell(short) and use setCellValue to 191 * specify the type lazily. 192 */ 193 194 public HSSFCell createCell(short column, int type) 195 { 196 HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column, type); 197 198 addCell(cell); 199 sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); 200 return cell; 201 } 202 203 /** 204 * remove the HSSFCell from this row. 205 * @param cell to remove 206 */ 207 public void removeCell(HSSFCell cell) 208 { 209 CellValueRecordInterface cval = cell.getCellValueRecord(); 210 211 sheet.removeValueRecord(getRowNum(), cval); 212 cells.remove(new Integer(cell.getCellNum())); 213 214 if (cell.getCellNum() == row.getLastCol()) 215 { 216 row.setLastCol(findLastCell(row.getLastCol())); 217 } 218 if (cell.getCellNum() == row.getFirstCol()) 219 { 220 row.setFirstCol(findFirstCell(row.getFirstCol())); 221 } 222 } 223 224 /** 225 * create a high level HSSFCell object from an existing low level record. Should 226 * only be called from HSSFSheet or HSSFRow itself. 227 * @param cell low level cell to create the high level representation from 228 * @return HSSFCell representing the low level record passed in 229 */ 230 231 protected HSSFCell createCellFromRecord(CellValueRecordInterface cell) 232 { 233 HSSFCell hcell = new HSSFCell(book, sheet, getRowNum(), cell); 234 235 addCell(hcell); 236 237 // sheet.addValueRecord(getRowNum(),cell.getCellValueRecord()); 238 return hcell; 239 } 240 241 /** 242 * set the row number of this row. 243 * @param rowNum the row number (0-based) 244 */ 245 246 public void setRowNum(short rowNum) 247 { 248 this.rowNum = rowNum; 249 if (row != null) 250 { 251 row.setRowNumber(rowNum); // used only for KEY comparison (HSSFRow) 252 } 253 } 254 255 /** 256 * get row number this row represents 257 * @return the row number (0 based) 258 */ 259 260 public short getRowNum() 261 { 262 return rowNum; 263 } 264 265 /** 266 * used internally to add a cell. 267 */ 268 269 private void addCell(HSSFCell cell) 270 { 271 if (row.getFirstCol() == -1) 272 { 273 row.setFirstCol(cell.getCellNum()); 274 } 275 if (row.getLastCol() == -1) 276 { 277 row.setLastCol(cell.getCellNum()); 278 } 279 cells.put(new Integer(cell.getCellNum()), cell); 280 281 if (cell.getCellNum() < row.getFirstCol()) 282 { 283 row.setFirstCol(cell.getCellNum()); 284 } 285 if (cell.getCellNum() > row.getLastCol()) 286 { 287 row.setLastCol(cell.getCellNum()); 288 } 289 } 290 291 /** 292 * get the hssfcell representing a given column (logical cell) 0-based. If you 293 * ask for a cell that is not defined....you get a null. 294 * 295 * @param cellnum 0 based column number 296 * @return HSSFCell representing that column or null if undefined. 297 */ 298 299 public HSSFCell getCell(short cellnum) 300 { 301 302 /* for (int k = 0; k < cells.size(); k++) 303 { 304 HSSFCell cell = ( HSSFCell ) cells.get(k); 305 306 if (cell.getCellNum() == cellnum) 307 { 308 return cell; 309 } 310 }*/ 311 return (HSSFCell) cells.get(new Integer(cellnum)); 312 } 313 314 /** 315 * get the number of the first cell contained in this row. 316 * @return short representing the first logical cell in the row 317 */ 318 319 public short getFirstCellNum() 320 { 321 if (getPhysicalNumberOfCells() == 0) 322 return -1; 323 else 324 return row.getFirstCol(); 325 } 326 327 /** 328 * get the number of the last cell contained in this row. 329 * @return short representing the last logical cell in the row 330 */ 331 332 public short getLastCellNum() 333 { 334 if (getPhysicalNumberOfCells() == 0) 335 return -1; 336 else 337 return row.getLastCol(); 338 } 339 340 341 /** 342 * gets the number of defined cells (NOT number of cells in the actual row!). 343 * That is to say if only columns 0,4,5 have values then there would be 3. 344 * @return int representing the number of defined cells in the row. 345 */ 346 347 public int getPhysicalNumberOfCells() 348 { 349 if (cells == null) 350 { 351 return 0; // shouldn't be possible but it is due to missing API support for BLANK/MULBLANK 352 } 353 return cells.size(); 354 } 355 356 /** 357 * set the row's height or set to ff (-1) for undefined/default-height. Set the height in "twips" or 358 * 1/20th of a point. 359 * @param height rowheight or 0xff for undefined (use sheet default) 360 */ 361 362 public void setHeight(short height) 363 { 364 365 // row.setOptionFlags( 366 row.setBadFontHeight(true); 367 row.setHeight(height); 368 } 369 370 /** 371 * set the row's height in points. 372 * @param height row height in points 373 */ 374 375 public void setHeightInPoints(float height) 376 { 377 378 // row.setOptionFlags( 379 row.setBadFontHeight(true); 380 row.setHeight((short) (height * 20)); 381 } 382 383 /** 384 * get the row's height or ff (-1) for undefined/default-height in twips (1/20th of a point) 385 * @return rowheight or 0xff for undefined (use sheet default) 386 */ 387 388 public short getHeight() 389 { 390 return row.getHeight(); 391 } 392 393 /** 394 * get the row's height or ff (-1) for undefined/default-height in points (20*getHeight()) 395 * @return rowheight or 0xff for undefined (use sheet default) 396 */ 397 398 public float getHeightInPoints() 399 { 400 return (row.getHeight() / 20); 401 } 402 403 /** 404 * get the lowlevel RowRecord represented by this object - should only be called 405 * by other parts of the high level API 406 * 407 * @return RowRecord this row represents 408 */ 409 410 protected RowRecord getRowRecord() 411 { 412 return row; 413 } 414 415 /** 416 * used internally to refresh the "last cell" when the last cell is removed. 417 */ 418 419 private short findLastCell(short lastcell) 420 { 421 short cellnum = (short) (lastcell - 1); 422 HSSFCell r = getCell(cellnum); 423 424 while (r == null && cellnum >= 0) 425 { 426 r = getCell(--cellnum); 427 } 428 return cellnum; 429 } 430 431 /** 432 * used internally to refresh the "first cell" when the first cell is removed. 433 */ 434 435 private short findFirstCell(short firstcell) 436 { 437 short cellnum = (short) (firstcell + 1); 438 HSSFCell r = getCell(cellnum); 439 440 while (r == null && cellnum <= getLastCellNum()) 441 { 442 r = getCell(++cellnum); 443 } 444 if (cellnum > getLastCellNum()) 445 return -1; 446 return cellnum; 447 } 448 449 /** 450 * @return cell iterator of the physically defined cells. Note element 4 may 451 * actually be row cell depending on how many are defined! 452 */ 453 454 public Iterator cellIterator() 455 { 456 return cells.values().iterator(); 457 } 458 459 public int compareTo(Object obj) 460 { 461 HSSFRow loc = (HSSFRow) obj; 462 463 if (this.getRowNum() == loc.getRowNum()) 464 { 465 return 0; 466 } 467 if (this.getRowNum() < loc.getRowNum()) 468 { 469 return -1; 470 } 471 if (this.getRowNum() > loc.getRowNum()) 472 { 473 return 1; 474 } 475 return -1; 476 } 477 478 public boolean equals(Object obj) 479 { 480 if (!(obj instanceof HSSFRow)) 481 { 482 return false; 483 } 484 HSSFRow loc = (HSSFRow) obj; 485 486 if (this.getRowNum() == loc.getRowNum()) 487 { 488 return true; 489 } 490 return false; 491 } 492 } 493