Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hssf » usermodel » [javadoc | source]
    1   /* ====================================================================
    2      Licensed to the Apache Software Foundation (ASF) under one or more
    3      contributor license agreements.  See the NOTICE file distributed with
    4      this work for additional information regarding copyright ownership.
    5      The ASF licenses this file to You under the Apache License, Version 2.0
    6      (the "License"); you may not use this file except in compliance with
    7      the License.  You may obtain a copy of the License at
    8   
    9          http://www.apache.org/licenses/LICENSE-2.0
   10   
   11      Unless required by applicable law or agreed to in writing, software
   12      distributed under the License is distributed on an "AS IS" BASIS,
   13      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14      See the License for the specific language governing permissions and
   15      limitations under the License.
   16   ==================================================================== */
   17   
   18   package org.apache.poi.hssf.usermodel;
   19   
   20   import java.util.Iterator;
   21   import java.util.NoSuchElementException;
   22   
   23   import org.apache.poi.hssf.model.Sheet;
   24   import org.apache.poi.hssf.record.CellValueRecordInterface;
   25   import org.apache.poi.hssf.record.RowRecord;
   26   
   27   /**
   28    * High level representation of a row of a spreadsheet.
   29    *
   30    * Only rows that have cells should be added to a Sheet.
   31    * @version 1.0-pre
   32    * @author  Andrew C. Oliver (acoliver at apache dot org)
   33    * @author Glen Stampoultzis (glens at apache.org)
   34    */
   35   public final class HSSFRow implements Comparable {
   36   
   37       // used for collections
   38       public final static int INITIAL_CAPACITY = 5;
   39   
   40       private int rowNum;
   41       private HSSFCell[] cells=new HSSFCell[INITIAL_CAPACITY];
   42   
   43       /**
   44        * reference to low level representation
   45        */
   46   
   47       private RowRecord row;
   48   
   49       /**
   50        * reference to containing low level Workbook
   51        */
   52   
   53       private HSSFWorkbook book;
   54   
   55       /**
   56        * reference to containing Sheet
   57        */
   58   
   59       private Sheet sheet;
   60   
   61       // TODO - ditch this constructor
   62       HSSFRow()
   63       {
   64       }
   65   
   66       /**
   67        * Creates new HSSFRow from scratch. Only HSSFSheet should do this.
   68        *
   69        * @param book low-level Workbook object containing the sheet that contains this row
   70        * @param sheet low-level Sheet object that contains this Row
   71        * @param rowNum the row number of this row (0 based)
   72        * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
   73        */
   74       HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum)
   75       {
   76           this.rowNum = rowNum;
   77           this.book = book;
   78           this.sheet = sheet;
   79           row = new RowRecord(rowNum);
   80   
   81           setRowNum(rowNum);
   82       }
   83   
   84       /**
   85        * Creates an HSSFRow from a low level RowRecord object.  Only HSSFSheet should do
   86        * this.  HSSFSheet uses this when an existing file is read in.
   87        *
   88        * @param book low-level Workbook object containing the sheet that contains this row
   89        * @param sheet low-level Sheet object that contains this Row
   90        * @param record the low level api object this row should represent
   91        * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
   92        */
   93       HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record)
   94       {
   95           this.book = book;
   96           this.sheet = sheet;
   97           row = record;
   98   
   99           setRowNum(record.getRowNumber());
  100       }
  101   
  102       /**
  103        * Use this to create new cells within the row and return it.
  104        * <p>
  105        * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
  106        * either through calling <code>setCellValue</code> or <code>setCellType</code>.
  107        *
  108        * @param column - the column number this cell represents
  109        *
  110        * @return HSSFCell a high level representation of the created cell.
  111        */
  112   
  113       public HSSFCell createCell(short column)
  114       {
  115         return this.createCell(column,HSSFCell.CELL_TYPE_BLANK);
  116       }
  117   
  118       /**
  119        * Use this to create new cells within the row and return it.
  120        * <p>
  121        * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
  122        * either through calling setCellValue or setCellType.
  123        *
  124        * @param column - the column number this cell represents
  125        *
  126        * @return HSSFCell a high level representation of the created cell.
  127        */
  128   
  129       public HSSFCell createCell(short column, int type)
  130       {
  131           HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column, type);
  132   
  133           addCell(cell);
  134           sheet.addValueRecord(getRowNum(), cell.getCellValueRecord());
  135           return cell;
  136       }
  137   
  138       /**
  139        * remove the HSSFCell from this row.
  140        * @param cell to remove
  141        */
  142       public void removeCell(HSSFCell cell) {
  143           if(cell == null) {
  144               throw new IllegalArgumentException("cell must not be null");
  145           }
  146           removeCell(cell, true);
  147       }
  148       private void removeCell(HSSFCell cell, boolean alsoRemoveRecords) {
  149           
  150           short column=cell.getCellNum();
  151           if(column < 0) {
  152               throw new RuntimeException("Negative cell indexes not allowed");
  153           }
  154           if(column >= cells.length || cell != cells[column]) {
  155               throw new RuntimeException("Specified cell is not from this row");
  156           }
  157           cells[column]=null;
  158           
  159           if(alsoRemoveRecords) {
  160               CellValueRecordInterface cval = cell.getCellValueRecord();
  161               sheet.removeValueRecord(getRowNum(), cval);
  162           }
  163           
  164           if (cell.getCellNum()+1 == row.getLastCol()) {
  165               row.setLastCol((short) (findLastCell(row.getLastCol())+1));
  166           }
  167           if (cell.getCellNum() == row.getFirstCol()) {
  168               row.setFirstCol(findFirstCell(row.getFirstCol()));
  169           }
  170       }
  171   
  172       /**
  173        * create a high level HSSFCell object from an existing low level record.  Should
  174        * only be called from HSSFSheet or HSSFRow itself.
  175        * @param cell low level cell to create the high level representation from
  176        * @return HSSFCell representing the low level record passed in
  177        */
  178   
  179       protected HSSFCell createCellFromRecord(CellValueRecordInterface cell)
  180       {
  181           HSSFCell hcell = new HSSFCell(book, sheet, getRowNum(), cell);
  182   
  183           addCell(hcell);
  184   
  185           // sheet.addValueRecord(getRowNum(),cell.getCellValueRecord());
  186           return hcell;
  187       }
  188   
  189       /**
  190        * set the row number of this row.
  191        * @param rowNum  the row number (0-based)
  192        * @throws IndexOutOfBoundsException if the row number is not within the range 0-65535.
  193        */
  194       public void setRowNum(int rowNum) {
  195           if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER)) {
  196             throw new IllegalArgumentException("Invalid row number (" + rowNum 
  197                     + ") outside allowable range (0.." + RowRecord.MAX_ROW_NUMBER + ")");
  198           }
  199           this.rowNum = rowNum;
  200           if (row != null)
  201           {
  202               row.setRowNumber(rowNum);   // used only for KEY comparison (HSSFRow)
  203           }
  204       }
  205   
  206       /**
  207        * get row number this row represents
  208        * @return the row number (0 based)
  209        */
  210       public int getRowNum()
  211       {
  212           return rowNum;
  213       }
  214       
  215       /**
  216        * Returns the rows outline level. Increased as you
  217        *  put it into more groups (outlines), reduced as
  218        *  you take it out of them.
  219        * TODO - Should this really be public?
  220        */
  221       protected int getOutlineLevel() {
  222           return row.getOutlineLevel();
  223       }
  224       
  225       /**
  226        * Moves the supplied cell to a new column, which
  227        *  must not already have a cell there!
  228        * @param cell The cell to move
  229        * @param newColumn The new column number (0 based)
  230        */
  231       public void moveCell(HSSFCell cell, short newColumn) {
  232           // Ensure the destination is free
  233           if(cells.length > newColumn && cells[newColumn] != null) {
  234               throw new IllegalArgumentException("Asked to move cell to column " + newColumn + " but there's already a cell there");
  235           }
  236           
  237           // Check it's one of ours
  238           if(! cells[cell.getCellNum()].equals(cell)) {
  239               throw new IllegalArgumentException("Asked to move a cell, but it didn't belong to our row");
  240           }
  241           
  242           // Move the cell to the new position
  243           // (Don't remove the records though)
  244           removeCell(cell, false);
  245           cell.updateCellNum(newColumn);
  246           addCell(cell);
  247       }
  248   
  249       /**
  250        * used internally to add a cell.
  251        */
  252       private void addCell(HSSFCell cell) {
  253   
  254           short column=cell.getCellNum();
  255           // re-allocate cells array as required.
  256           if(column>=cells.length) {
  257               HSSFCell[] oldCells=cells;
  258               int newSize=oldCells.length*2;
  259               if(newSize<column+1) {
  260                   newSize=column+1;
  261               }
  262               cells=new HSSFCell[newSize];
  263               System.arraycopy(oldCells,0,cells,0,oldCells.length);
  264           }
  265           cells[column]=cell;
  266           
  267           // fix up firstCol and lastCol indexes
  268           if (row.getFirstCol() == -1 || column < row.getFirstCol()) {
  269               row.setFirstCol(column);
  270           }
  271           
  272           if (row.getLastCol() == -1 || column >= row.getLastCol()) {
  273               row.setLastCol((short) (column+1)); // +1 -> for one past the last index 
  274           }
  275       }
  276   
  277       /**
  278        * Get the hssfcell representing a given column (logical cell)
  279        *  0-based. If you ask for a cell that is not defined, then
  280        *  you get a null.
  281        * This is the basic call, with no policies applied
  282        *
  283        * @param cellnum  0 based column number
  284        * @return HSSFCell representing that column or null if undefined.
  285        */
  286       private HSSFCell retrieveCell(int cellnum) {
  287           if(cellnum<0||cellnum>=cells.length) return null;
  288           return cells[cellnum];
  289       }
  290       
  291       /**
  292        * Get the hssfcell representing a given column (logical cell)
  293        *  0-based.  If you ask for a cell that is not defined then
  294        *  you get a null, unless you have set a different
  295        *  {@link MissingCellPolicy} on the base workbook.
  296        * Short method signature provided to retain binary
  297        *  compatibility.
  298        *
  299        * @param cellnum  0 based column number
  300        * @return HSSFCell representing that column or null if undefined.
  301        */
  302       public HSSFCell getCell(short cellnum) {
  303           int ushortCellNum = cellnum & 0x0000FFFF; // avoid sign extension
  304           return getCell(ushortCellNum);
  305       }
  306       
  307       /**
  308        * Get the hssfcell representing a given column (logical cell)
  309        *  0-based.  If you ask for a cell that is not defined then
  310        *  you get a null, unless you have set a different
  311        *  {@link MissingCellPolicy} on the base workbook.
  312        *
  313        * @param cellnum  0 based column number
  314        * @return HSSFCell representing that column or null if undefined.
  315        */
  316       public HSSFCell getCell(int cellnum) {
  317       	return getCell(cellnum, book.getMissingCellPolicy());
  318       }
  319       
  320       /**
  321        * Get the hssfcell representing a given column (logical cell)
  322        *  0-based.  If you ask for a cell that is not defined, then
  323        *  your supplied policy says what to do
  324        *
  325        * @param cellnum  0 based column number
  326        * @param policy Policy on blank / missing cells
  327        * @return representing that column or null if undefined + policy allows.
  328        */
  329       public HSSFCell getCell(int cellnum, MissingCellPolicy policy) {
  330       	HSSFCell cell = retrieveCell(cellnum);
  331       	if(policy == RETURN_NULL_AND_BLANK) {
  332       		return cell;
  333       	}
  334       	if(policy == RETURN_BLANK_AS_NULL) {
  335       		if(cell == null) return cell;
  336       		if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
  337       			return null;
  338       		}
  339       		return cell;
  340       	}
  341       	if(policy == CREATE_NULL_AS_BLANK) {
  342       		if(cell == null) {
  343       			return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK);
  344       		}
  345       		return cell;
  346       	}
  347       	throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
  348       }
  349   
  350       /**
  351        * get the number of the first cell contained in this row.
  352        * @return short representing the first logical cell in the row, or -1 if the row does not contain any cells.
  353        */
  354       public short getFirstCellNum()
  355       {
  356           if (getPhysicalNumberOfCells() == 0)
  357               return -1;
  358           else
  359               return row.getFirstCol();
  360       }
  361   
  362       /**
  363        * Gets the index of the last cell contained in this row <b>PLUS ONE</b>. The result also 
  364        * happens to be the 1-based column number of the last cell.  This value can be used as a
  365        * standard upper bound when iterating over cells:
  366        * <pre> 
  367        * short minColIx = row.getFirstCellNum();
  368        * short maxColIx = row.getLastCellNum();
  369        * for(short colIx=minColIx; colIx&lt;maxColIx; colIx++) {
  370        *   HSSFCell cell = row.getCell(colIx);
  371        *   if(cell == null) {
  372        *     continue;
  373        *   }
  374        *   //... do something with cell
  375        * }
  376        * </pre>
  377        * 
  378        * @return short representing the last logical cell in the row <b>PLUS ONE</b>, or -1 if the
  379        *  row does not contain any cells.
  380        */
  381       public short getLastCellNum() {
  382           if (getPhysicalNumberOfCells() == 0) {
  383               return -1;
  384           }
  385           return row.getLastCol();
  386       }
  387   
  388   
  389       /**
  390        * gets the number of defined cells (NOT number of cells in the actual row!).
  391        * That is to say if only columns 0,4,5 have values then there would be 3.
  392        * @return int representing the number of defined cells in the row.
  393        */
  394   
  395       public int getPhysicalNumberOfCells()
  396       {
  397         int count=0;
  398         for(int i=0;i<cells.length;i++)
  399         {
  400           if(cells[i]!=null) count++;
  401         }
  402         return count;
  403       }
  404   
  405       /**
  406        * set the row's height or set to ff (-1) for undefined/default-height.  Set the height in "twips" or
  407        * 1/20th of a point.
  408        * @param height  rowheight or 0xff for undefined (use sheet default)
  409        */
  410   
  411       public void setHeight(short height)
  412       {
  413   
  414           // row.setOptionFlags(
  415           row.setBadFontHeight(true);
  416           row.setHeight(height);
  417       }
  418   
  419       /**
  420        * set whether or not to display this row with 0 height
  421        * @param zHeight  height is zero or not.
  422        */
  423       public void setZeroHeight(boolean zHeight) {
  424           row.setZeroHeight(zHeight);
  425       }
  426     
  427       /**
  428        * get whether or not to display this row with 0 height
  429        * @return - zHeight height is zero or not.
  430        */
  431       public boolean getZeroHeight() {
  432           return row.getZeroHeight();
  433       }
  434   
  435       /**
  436        * set the row's height in points.
  437        * @param height  row height in points
  438        */
  439   
  440       public void setHeightInPoints(float height)
  441       {
  442   
  443           // row.setOptionFlags(
  444           row.setBadFontHeight(true);
  445           row.setHeight((short) (height * 20));
  446       }
  447   
  448       /**
  449        * get the row's height or ff (-1) for undefined/default-height in twips (1/20th of a point)
  450        * @return rowheight or 0xff for undefined (use sheet default)
  451        */
  452   
  453       public short getHeight()
  454       {
  455           return row.getHeight();
  456       }
  457   
  458       /**
  459        * get the row's height or ff (-1) for undefined/default-height in points (20*getHeight())
  460        * @return rowheight or 0xff for undefined (use sheet default)
  461        */
  462   
  463       public float getHeightInPoints()
  464       {
  465           return (row.getHeight() / 20);
  466       }
  467   
  468       /**
  469        * get the lowlevel RowRecord represented by this object - should only be called
  470        * by other parts of the high level API
  471        *
  472        * @return RowRecord this row represents
  473        */
  474   
  475       protected RowRecord getRowRecord()
  476       {
  477           return row;
  478       }
  479   
  480       /**
  481        * used internally to refresh the "last cell" when the last cell is removed.
  482        */
  483   
  484       private short findLastCell(short lastcell)
  485       {
  486           short cellnum = (short) (lastcell - 1);
  487           HSSFCell r = getCell(cellnum);
  488   
  489           while (r == null && cellnum >= 0)
  490           {
  491               r = getCell(--cellnum);
  492           }
  493           return cellnum;
  494       }
  495   
  496       /**
  497        * used internally to refresh the "first cell" when the first cell is removed.
  498        */
  499   
  500       private short findFirstCell(short firstcell)
  501       {
  502           short cellnum = (short) (firstcell + 1);
  503           HSSFCell r = getCell(cellnum);
  504   
  505           while (r == null && cellnum <= getLastCellNum())
  506           {
  507               r = getCell(++cellnum);
  508           }
  509           if (cellnum > getLastCellNum())
  510               return -1;
  511           return cellnum;
  512       }
  513   
  514       /**
  515        * Used to specify the different possible policies
  516        *  if for the case of null and blank cells
  517        */
  518       public static class MissingCellPolicy {
  519       	private static int NEXT_ID = 1;
  520       	private final int id;
  521       	private MissingCellPolicy() {
  522       		this.id = NEXT_ID++;
  523       	}
  524       }
  525   
  526       /** Missing cells are returned as null, Blank cells are returned as normal */
  527       public static final MissingCellPolicy RETURN_NULL_AND_BLANK = new MissingCellPolicy();
  528       /** Missing cells are returned as null, as are blank cells */
  529       public static final MissingCellPolicy RETURN_BLANK_AS_NULL = new MissingCellPolicy();
  530       /** A new, blank cell is created for missing cells. Blank cells are returned as normal */
  531       public static final MissingCellPolicy CREATE_NULL_AS_BLANK = new MissingCellPolicy();
  532       
  533   
  534       /**
  535        * @return cell iterator of the physically defined cells. 
  536        * Note that the 4th element might well not be cell 4, as the iterator
  537        *  will not return un-defined (null) cells.
  538        * Call getCellNum() on the returned cells to know which cell they are.
  539        */
  540       public Iterator cellIterator()
  541       {
  542         return new CellIterator();
  543       }
  544       /**
  545        * Alias for {@link CellIterator} to allow
  546        *  foreach loops
  547        */
  548       public Iterator iterator() { 
  549          return cellIterator();
  550       }
  551       
  552       /**
  553        * An iterator over the (physical) cells in the row.
  554        */
  555       private class CellIterator implements Iterator
  556       {
  557         int thisId=-1;
  558         int nextId=-1;
  559         
  560         public CellIterator()
  561         {
  562           findNext();
  563         }
  564   
  565         public boolean hasNext() {
  566           return nextId<cells.length;
  567         }
  568   
  569         public Object next() {
  570             if (!hasNext())
  571                 throw new NoSuchElementException("At last element");
  572           HSSFCell cell=cells[nextId];
  573           thisId=nextId;
  574           findNext();
  575           return cell;
  576         }
  577   
  578         public void remove() {
  579             if (thisId == -1)
  580                 throw new IllegalStateException("remove() called before next()");
  581           cells[thisId]=null;
  582         }
  583         
  584         private void findNext()
  585         {
  586           int i=nextId+1;
  587           for(;i<cells.length;i++)
  588           {
  589             if(cells[i]!=null) break;
  590           }
  591           nextId=i;
  592         }
  593         
  594       }
  595   
  596       public int compareTo(Object obj)
  597       {
  598           HSSFRow loc = (HSSFRow) obj;
  599   
  600           if (this.getRowNum() == loc.getRowNum())
  601           {
  602               return 0;
  603           }
  604           if (this.getRowNum() < loc.getRowNum())
  605           {
  606               return -1;
  607           }
  608           if (this.getRowNum() > loc.getRowNum())
  609           {
  610               return 1;
  611           }
  612           return -1;
  613       }
  614   
  615       public boolean equals(Object obj)
  616       {
  617           if (!(obj instanceof HSSFRow))
  618           {
  619               return false;
  620           }
  621           HSSFRow loc = (HSSFRow) obj;
  622   
  623           if (this.getRowNum() == loc.getRowNum())
  624           {
  625               return true;
  626           }
  627           return false;
  628       }
  629   }

Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hssf » usermodel » [javadoc | source]