Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hssf » record » aggregates » [javadoc | source]
    1   
    2   /* ====================================================================
    3      Licensed to the Apache Software Foundation (ASF) under one or more
    4      contributor license agreements.  See the NOTICE file distributed with
    5      this work for additional information regarding copyright ownership.
    6      The ASF licenses this file to You under the Apache License, Version 2.0
    7      (the "License"); you may not use this file except in compliance with
    8      the License.  You may obtain a copy of the License at
    9   
   10          http://www.apache.org/licenses/LICENSE-2.0
   11   
   12      Unless required by applicable law or agreed to in writing, software
   13      distributed under the License is distributed on an "AS IS" BASIS,
   14      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15      See the License for the specific language governing permissions and
   16      limitations under the License.
   17   ==================================================================== */
   18   
   19   
   20   package org.apache.poi.hssf.record.aggregates;
   21   
   22   import org.apache.poi.hssf.record;
   23   
   24   import java.util.Iterator;
   25   import java.util.List;
   26   
   27   
   28   /**
   29    *
   30    * Aggregate value records together.  Things are easier to handle that way.
   31    *
   32    * @author  andy
   33    * @author  Glen Stampoultzis (glens at apache.org)
   34    * @author Jason Height (jheight at chariot dot net dot au)
   35    */
   36   
   37   public final class ValueRecordsAggregate
   38       extends Record
   39   {
   40       public final static short sid       = -1001; // 1000 clashes with RowRecordsAggregate
   41       int                       firstcell = -1;
   42       int                       lastcell  = -1;
   43     CellValueRecordInterface[][] records;
   44   
   45       /** Creates a new instance of ValueRecordsAggregate */
   46   
   47       public ValueRecordsAggregate()
   48       {
   49       records = new CellValueRecordInterface[30][]; // We start with 30 Rows.
   50       }
   51   
   52     public void insertCell(CellValueRecordInterface cell) {
   53       short column = cell.getColumn();
   54       int row = cell.getRow();
   55       if (row >= records.length) {
   56         CellValueRecordInterface[][] oldRecords = records;
   57         int newSize = oldRecords.length * 2;
   58         if(newSize<row+1) newSize=row+1;
   59         records = new CellValueRecordInterface[newSize][];
   60         System.arraycopy(oldRecords, 0, records, 0, oldRecords.length);
   61       }
   62       CellValueRecordInterface[] rowCells = records[row];
   63       if (rowCells == null) {
   64         int newSize = column + 1;
   65         if(newSize<10) newSize=10;
   66         rowCells = new CellValueRecordInterface[newSize];
   67         records[row] = rowCells;
   68       }
   69       if (column >= rowCells.length) {
   70         CellValueRecordInterface[] oldRowCells = rowCells;
   71         int newSize = oldRowCells.length * 2;
   72         if(newSize<column+1) newSize=column+1;
   73         // if(newSize>257) newSize=257; // activate?
   74         rowCells = new CellValueRecordInterface[newSize];
   75         System.arraycopy(oldRowCells, 0, rowCells, 0, oldRowCells.length);
   76         records[row] = rowCells;
   77       }
   78       rowCells[column] = cell;
   79   
   80       if ((column < firstcell) || (firstcell == -1)) {
   81         firstcell = column;
   82       }
   83       if ((column > lastcell) || (lastcell == -1)) {
   84         lastcell = column;
   85       }
   86     }
   87   
   88       public void removeCell(CellValueRecordInterface cell)
   89       {
   90       	if (cell != null) {
   91             short column = cell.getColumn();
   92             int row = cell.getRow();
   93             if(row>=records.length) return;
   94             CellValueRecordInterface[] rowCells=records[row];
   95             if(rowCells==null) return;
   96             if(column>=rowCells.length) return;
   97             rowCells[column]=null;
   98       	}
   99       }
  100   
  101       public int getPhysicalNumberOfCells()
  102       {
  103       int count=0;
  104       for(int r=0;r<records.length;r++) {
  105         CellValueRecordInterface[] rowCells=records[r];
  106         if (rowCells != null)
  107           for(short c=0;c<rowCells.length;c++) {
  108             if(rowCells[c]!=null) count++;
  109           }
  110       }
  111       return count;
  112       }
  113   
  114       public int getFirstCellNum()
  115       {
  116           return firstcell;
  117       }
  118   
  119       public int getLastCellNum()
  120       {
  121           return lastcell;
  122       }
  123   
  124       public int construct(int offset, List records)
  125       {
  126           int k = 0;
  127   
  128           FormulaRecordAggregate lastFormulaAggregate = null;
  129           
  130           // First up, locate all the shared formulas for this sheet
  131           List sharedFormulas = new java.util.ArrayList();
  132           for (k = offset; k < records.size(); k++)
  133           {
  134               Record rec = ( Record ) records.get(k);
  135               if (rec instanceof SharedFormulaRecord) {
  136               	sharedFormulas.add(rec);
  137               }
  138               if(rec instanceof EOFRecord) {
  139                   // End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449)
  140                   break;
  141               }
  142           }
  143   
  144           // Now do the main processing sweep
  145           for (k = offset; k < records.size(); k++)
  146           {
  147               Record rec = ( Record ) records.get(k);
  148   
  149               if (rec instanceof StringRecord == false && !rec.isInValueSection() && !(rec instanceof UnknownRecord))
  150               {
  151                   break;
  152               } else if (rec instanceof SharedFormulaRecord) {
  153               	// Already handled, not to worry
  154               } else if (rec instanceof FormulaRecord)
  155               {
  156                 FormulaRecord formula = (FormulaRecord)rec;
  157                 if (formula.isSharedFormula()) {
  158                   // Traverse the list of shared formulas in
  159               	//  reverse order, and try to find the correct one
  160                   //  for us
  161                   boolean found = false;
  162                   for (int i=sharedFormulas.size()-1;i>=0;i--) {
  163                       // TODO - there is no junit test case to justify this reversed loop
  164                       // perhaps it could just run in the normal direction?
  165                   	SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
  166                   	if (shrd.isFormulaInShared(formula)) {
  167                   		shrd.convertSharedFormulaRecord(formula);
  168                   		found = true;
  169                   		break;
  170                   	}
  171                   }
  172                   if (!found) {
  173                       handleMissingSharedFormulaRecord(formula);
  174                   }
  175                 }
  176               	
  177                 lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
  178                 insertCell( lastFormulaAggregate );
  179               }
  180               else if (rec instanceof StringRecord)
  181               {
  182                   lastFormulaAggregate.setStringRecord((StringRecord)rec);
  183               }
  184               else if (rec.isValue())
  185               {
  186                   insertCell(( CellValueRecordInterface ) rec);
  187               }
  188           }
  189           return k;
  190       }
  191   
  192       /**
  193        * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no 
  194        * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the 
  195        * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
  196        * As it turns out, this is not a problem, because in these circumstances, the existing value
  197        * for <tt>parsedExpression</tt> is perfectly OK.<p/>
  198        * 
  199        * This method may also be used for setting breakpoints to help diagnose issues regarding the
  200        * abnormally-set 'shared formula' flags. 
  201        * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
  202        * 
  203        * The method currently does nothing but do not delete it without finding a nice home for this 
  204        * comment.
  205        */
  206       private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
  207           // could log an info message here since this is a fairly unusual occurrence.
  208       }
  209   
  210       /**
  211        * called by the class that is responsible for writing this sucker.
  212        * Subclasses should implement this so that their data is passed back in a
  213        * byte array.
  214        *
  215        * @param offset to begin writing at
  216        * @param data byte array containing instance data
  217        * @return number of bytes written
  218        */
  219   
  220       public int serialize(int offset, byte [] data)
  221       {
  222         throw new RuntimeException("This method shouldnt be called. ValueRecordsAggregate.serializeCellRow() should be called from RowRecordsAggregate.");
  223       }
  224       
  225       /** Tallies a count of the size of the cell records
  226        *  that are attached to the rows in the range specified.
  227        */
  228       public int getRowCellBlockSize(int startRow, int endRow) {
  229         MyIterator itr = new MyIterator(startRow, endRow);
  230         int size = 0;
  231         while (itr.hasNext()) {
  232           CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
  233           int row = cell.getRow();
  234           if (row > endRow)
  235             break;
  236           if ((row >=startRow) && (row <= endRow))
  237             size += ((Record)cell).getRecordSize();
  238         }
  239         return size;
  240       }
  241   
  242       /** Returns true if the row has cells attached to it */
  243       public boolean rowHasCells(int row) {
  244       	if (row > records.length-1) //previously this said row > records.length which means if 
  245       		return false;  // if records.length == 60 and I pass "60" here I get array out of bounds
  246         CellValueRecordInterface[] rowCells=records[row]; //because a 60 length array has the last index = 59
  247         if(rowCells==null) return false;
  248         for(int col=0;col<rowCells.length;col++) {
  249           if(rowCells[col]!=null) return true;
  250         }
  251         return false;
  252       }
  253   
  254       /** Serializes the cells that are allocated to a certain row range*/
  255       public int serializeCellRow(final int row, int offset, byte [] data)
  256       {
  257         MyIterator itr = new MyIterator(row, row);
  258           int      pos = offset;
  259   
  260           while (itr.hasNext())
  261           {
  262               CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
  263               if (cell.getRow() != row)
  264                 break;
  265               pos += (( Record ) cell).serialize(pos, data);
  266           }
  267           return pos - offset;
  268       }
  269   
  270       
  271       /**
  272        * You never fill an aggregate
  273        */
  274       protected void fillFields(RecordInputStream in)
  275       {
  276       }
  277   
  278       /**
  279        * called by constructor, should throw runtime exception in the event of a
  280        * record passed with a differing ID.
  281        *
  282        * @param id alleged id for this record
  283        */
  284   
  285       protected void validateSid(short id)
  286       {
  287       }
  288   
  289       /**
  290        * return the non static version of the id for this record.
  291        */
  292   
  293       public short getSid()
  294       {
  295           return sid;
  296       }
  297   
  298       public int getRecordSize() {
  299       
  300           int size = 0;
  301       Iterator irecs = this.getIterator();
  302           
  303           while (irecs.hasNext()) {
  304                   size += (( Record ) irecs.next()).getRecordSize();
  305           }
  306   
  307           return size;
  308       }
  309   
  310       public Iterator getIterator()
  311       {
  312       return new MyIterator();
  313       }
  314   
  315       /** Performs a deep clone of the record*/
  316       public Object clone() {
  317         ValueRecordsAggregate rec = new ValueRecordsAggregate();
  318         for (Iterator valIter = getIterator(); valIter.hasNext();) {
  319           CellValueRecordInterface val = (CellValueRecordInterface)((CellValueRecordInterface)valIter.next()).clone();
  320           rec.insertCell(val);
  321         }
  322         return rec;
  323       }
  324     
  325     private final class MyIterator implements Iterator {
  326       short nextColumn=-1;
  327       int nextRow,lastRow;
  328   
  329       public MyIterator()
  330       {
  331         this.nextRow=0;
  332         this.lastRow=records.length-1;
  333         findNext();
  334       }
  335       
  336       public MyIterator(int firstRow,int lastRow)
  337       {
  338         this.nextRow=firstRow;
  339         this.lastRow=lastRow;
  340         findNext();
  341       }
  342   
  343       public boolean hasNext() {
  344         return nextRow<=lastRow;
  345       }
  346       public Object next() {
  347         Object o=records[nextRow][nextColumn];
  348         findNext();
  349         return o;
  350       }
  351       public void remove() {
  352         throw new UnsupportedOperationException("gibt's noch nicht");
  353       }
  354   
  355       private void findNext() {
  356         nextColumn++;
  357         for(;nextRow<=lastRow;nextRow++) {
  358                                              //previously this threw array out of bounds...
  359           CellValueRecordInterface[] rowCells=(nextRow < records.length) ? records[nextRow] : null;
  360           if(rowCells==null) { // This row is empty
  361             nextColumn=0;
  362             continue;
  363           }
  364           for(;nextColumn<rowCells.length;nextColumn++) {
  365             if(rowCells[nextColumn]!=null) return;
  366           }
  367           nextColumn=0;
  368         }
  369       }
  370   
  371     }
  372   }

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