123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-
- package org.apache.poi.hssf.eventusermodel;
-
- import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
- import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
- import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord;
- import org.apache.poi.hssf.record.BOFRecord;
- import org.apache.poi.hssf.record.CellValueRecordInterface;
- import org.apache.poi.hssf.record.MulBlankRecord;
- import org.apache.poi.hssf.record.MulRKRecord;
- import org.apache.poi.hssf.record.NoteRecord;
- import org.apache.poi.hssf.record.Record;
- import org.apache.poi.hssf.record.RecordFactory;
- import org.apache.poi.hssf.record.RowRecord;
- import org.apache.poi.hssf.record.SharedFormulaRecord;
- import org.apache.poi.hssf.record.StringRecord;
-
- /**
- * <p>A HSSFListener which tracks rows and columns, and will
- * trigger your HSSFListener for all rows and cells,
- * even the ones that aren't actually stored in the file.</p>
- * <p>This allows your code to have a more "Excel" like
- * view of the data in the file, and not have to worry
- * (as much) about if a particular row/cell is in the
- * file, or was skipped from being written as it was
- * blank.
- */
- public final class MissingRecordAwareHSSFListener implements HSSFListener {
- private HSSFListener childListener;
-
- // Need to have different counters for cell rows and
- // row rows, as you sometimes get a RowRecord in the
- // middle of some cells, and that'd break everything
- private int lastRowRow;
-
- private int lastCellRow;
- private int lastCellColumn;
-
- /**
- * Constructs a new MissingRecordAwareHSSFListener, which
- * will fire processRecord on the supplied child
- * HSSFListener for all Records, and missing records.
- * @param listener The HSSFListener to pass records on to
- */
- public MissingRecordAwareHSSFListener(HSSFListener listener) {
- resetCounts();
- childListener = listener;
- }
-
- public void processRecord(Record record) {
- int thisRow;
- int thisColumn;
- CellValueRecordInterface[] expandedRecords = null;
-
- if (record instanceof CellValueRecordInterface) {
- CellValueRecordInterface valueRec = (CellValueRecordInterface) record;
- thisRow = valueRec.getRow();
- thisColumn = valueRec.getColumn();
- } else {
- if (record instanceof StringRecord){
- //it contains only cashed result of the previous FormulaRecord evaluation
- childListener.processRecord(record);
- return;
- }
- thisRow = -1;
- thisColumn = -1;
-
- switch (record.getSid()) {
- // the BOFRecord can represent either the beginning of a sheet or
- // the workbook
- case BOFRecord.sid:
- BOFRecord bof = (BOFRecord) record;
- if (bof.getType() == bof.TYPE_WORKBOOK || bof.getType() == bof.TYPE_WORKSHEET) {
- // Reset the row and column counts - new workbook / worksheet
- resetCounts();
- }
- break;
- case RowRecord.sid:
- RowRecord rowrec = (RowRecord) record;
- //System.out.println("Row " + rowrec.getRowNumber() + " found, first column at "
- // + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
-
- // If there's a jump in rows, fire off missing row records
- if (lastRowRow + 1 < rowrec.getRowNumber()) {
- for (int i = (lastRowRow + 1); i < rowrec.getRowNumber(); i++) {
- MissingRowDummyRecord dr = new MissingRowDummyRecord(i);
- childListener.processRecord(dr);
- }
- }
-
- // Record this as the last row we saw
- lastRowRow = rowrec.getRowNumber();
- break;
-
- case SharedFormulaRecord.sid:
- // SharedFormulaRecord occurs after the first FormulaRecord of the cell range.
- // There are probably (but not always) more cell records after this
- // - so don't fire off the LastCellOfRowDummyRecord yet
- childListener.processRecord(record);
- return;
- case MulBlankRecord.sid:
- // These appear in the middle of the cell records, to
- // specify that the next bunch are empty but styled
- // Expand this out into multiple blank cells
- MulBlankRecord mbr = (MulBlankRecord)record;
- expandedRecords = RecordFactory.convertBlankRecords(mbr);
- break;
- case MulRKRecord.sid:
- // This is multiple consecutive number cells in one record
- // Exand this out into multiple regular number cells
- MulRKRecord mrk = (MulRKRecord)record;
- expandedRecords = RecordFactory.convertRKRecords(mrk);
- break;
- case NoteRecord.sid:
- NoteRecord nrec = (NoteRecord) record;
- thisRow = nrec.getRow();
- thisColumn = nrec.getColumn();
- break;
- }
- }
-
- // First part of expanded record handling
- if(expandedRecords != null && expandedRecords.length > 0) {
- thisRow = expandedRecords[0].getRow();
- thisColumn = expandedRecords[0].getColumn();
- }
-
- // If we're on cells, and this cell isn't in the same
- // row as the last one, then fire the
- // dummy end-of-row records
- if(thisRow != lastCellRow && lastCellRow > -1) {
- for(int i=lastCellRow; i<thisRow; i++) {
- int cols = -1;
- if(i == lastCellRow) {
- cols = lastCellColumn;
- }
- childListener.processRecord(new LastCellOfRowDummyRecord(i, cols));
- }
- }
-
- // If we've just finished with the cells, then fire the
- // final dummy end-of-row record
- if(lastCellRow != -1 && lastCellColumn != -1 && thisRow == -1) {
- childListener.processRecord(new LastCellOfRowDummyRecord(lastCellRow, lastCellColumn));
-
- lastCellRow = -1;
- lastCellColumn = -1;
- }
-
- // If we've moved onto a new row, the ensure we re-set
- // the column counter
- if(thisRow != lastCellRow) {
- lastCellColumn = -1;
- }
-
- // If there's a gap in the cells, then fire
- // the dummy cell records
- if(lastCellColumn != thisColumn-1) {
- for(int i=lastCellColumn+1; i<thisColumn; i++) {
- childListener.processRecord(new MissingCellDummyRecord(thisRow, i));
- }
- }
-
- // Next part of expanded record handling
- if(expandedRecords != null && expandedRecords.length > 0) {
- thisColumn = expandedRecords[expandedRecords.length-1].getColumn();
- }
-
-
- // Update cell and row counts as needed
- if(thisColumn != -1) {
- lastCellColumn = thisColumn;
- lastCellRow = thisRow;
- }
-
- // Pass along the record(s)
- if(expandedRecords != null && expandedRecords.length > 0) {
- for(CellValueRecordInterface r : expandedRecords) {
- childListener.processRecord((Record)r);
- }
- } else {
- childListener.processRecord(record);
- }
- }
-
- private void resetCounts() {
- lastRowRow = -1;
- lastCellRow = -1;
- lastCellColumn = -1;
- }
- }
|