org.ttzero.excel.reader.BIFF8Sheet Maven / Gradle / Ivy
/*
* Copyright (c) 2019-2020, [email protected] All Rights Reserved.
*
* Licensed 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.ttzero.excel.reader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ttzero.excel.entity.e3.Block;
import org.ttzero.excel.entity.e3.MergedSheetSubStream;
import org.ttzero.excel.entity.e3.SheetInfo;
import org.ttzero.excel.entity.e3.SheetSubStream;
import org.ttzero.excel.entity.e3.ShortBlock;
import java.util.Iterator;
import java.util.List;
import static org.ttzero.excel.reader.ExcelReader.COPY_ON_MERGED;
/**
* BIFF8 format Worksheet
*
* @author guanquan.wang at 2019-04-16 16:55
*/
public class BIFF8Sheet implements Sheet {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
public BIFF8Sheet() { }
public BIFF8Sheet(BIFF8Sheet sheet) {
this.name = sheet.name;
this.index = sheet.index;
this.header = sheet.header;
this.hidden = sheet.hidden;
this.dimension = sheet.dimension;
this.reader = sheet.reader;
this.sheetInfo = sheet.sheetInfo;
this.standard_sector = sheet.standard_sector;
this.loaded = sheet.loaded;
this.stream = sheet.stream;
}
protected String name;
protected int index; // per sheet index of workbook
// , size = -1; // size of rows per sheet
protected HeaderRow header;
protected boolean hidden; // state hidden
protected BIFF8Reader reader;
protected SheetSubStream stream;
protected SheetInfo sheetInfo;
protected Dimension dimension;
/**
* Mark the workbook in standard sector or short-sector
*/
protected boolean standard_sector = true;
/**
* Mark loaded flag
*/
protected boolean loaded;
protected void setReader(BIFF8Reader reader) {
this.reader = reader;
}
protected void setName(String name) {
this.name = name;
}
/**
* The worksheet name
*
* @return the sheet name
*/
@Override
public String getName() {
return name;
}
/**
* The index of worksheet located at the workbook
*
* @return the index(zero base)
*/
@Override
public int getIndex() {
return index;
}
/**
* The worksheet id, I don't know how to get it, return index temporarily
*
* @return id of worksheet
*/
@Override
public int getId() {
return index;
}
protected void setIndex(int index) {
this.index = index;
}
/**
* size of rows.
*
* @return size of rows
* -1: unknown size
* @deprecated use {@link #getDimension()} to getting full range address
*/
@Deprecated
@Override
public int getSize() {
return dimension != null ? dimension.lastRow - dimension.firstRow + 1 : -1;
}
/**
* Returns The range address of the used area in
* the current sheet
*
* NOTE: This method can only guarantee accurate row ranges
*
* @return worksheet {@link Dimension} ranges
*/
@Override
public Dimension getDimension() {
return dimension;
}
/**
* Test Worksheet is hidden
*/
@Override
public boolean isHidden() {
return hidden;
}
/**
* Returns the header of the list.
* The first non-empty line defaults to the header information.
*
* @return the HeaderRow
*/
@Override
public Row getHeader() {
// Find the first row as header
if (header == null) {
BIFF8Row row = stream.firstRow();
if (row != null) {
header = row.asHeader();
row.setHr(header);
}
}
return header;
}
/**
* Set the binding type
*
* @param clazz the binding type
* @return sheet
*/
@Override
public Sheet bind(Class> clazz) {
if (getHeader() != null) {
try {
header.setClassOnce(clazz);
} catch (IllegalAccessException | InstantiationException e) {
throw new ExcelReadException(e);
}
}
return this;
}
/**
* Parse Sheet-Sub-Stream
*
* @return Sheet
*/
@Override
public BIFF8Sheet load() {
if (!loaded) {
loaded = true;
if (reader.gs == null) {
reader.gs = reader.parseGlobalSetting();
if (reader.gs == null) {
throw new ExcelReadException("Miss the GlobalSetting. Maybe the file has be corrupted.");
}
}
LOGGER.debug("Loading Worksheet: {}", sheetInfo.toString());
stream = getStream();
stream.setRowSupplier(this::createRow);
stream.get(standard_sector ? new Block(reader.context, reader.gs.getFirstSid()).init()
: new ShortBlock(reader.context, reader.gs.getFirstSid()).init());
dimension = stream.getRange();
}
return this;
}
/**
* Returns a {@link ShareStringParser}
*
* @return SheetSubStream
*/
protected SheetSubStream getStream() {
SheetSubStream stream;
switch (reader.option) {
case COPY_ON_MERGED:
stream = new MergedSheetSubStream(reader.gs, sheetInfo);
break;
default:
stream = new SheetSubStream(reader.gs, sheetInfo);
}
return stream;
}
/**
* Iterating each row of data contains header information and blank lines
*
* @return a row iterator
*/
@Override
public Iterator iterator() {
return new RowSetIterator(stream::nextRow, false);
}
/**
* Iterating over data rows without header information and blank lines
*
* @return a row iterator
*/
@Override
public Iterator dataIterator() {
Iterator nIter = new RowSetIterator(stream::nextRow, true);
if (nIter.hasNext()) {
Row row = nIter.next();
if (header == null) header = row.asHeader();
row.setHr(header);
}
return nIter;
}
/**
* List all pictures in workbook
*
* @return picture list or null if not exists.
*/
@Override
public List listPictures() {
if (reader.drawings == null && reader.gs.getMsoDrawingGroupBlockIndex() != null) {
reader.drawings = new BIFF8Drawings(Block.loadWithIndex(reader.gs.getMsoDrawingGroupBlockIndex()), reader.all());
}
return reader.drawings != null ? reader.drawings.listPictures(this) : null;
}
@Override
public BIFF8Row createRow() {
return new BIFF8Row();
}
/**
* Close resource
*/
@Override
public void close() {
// Nothing
}
@Override
public BIFF8Sheet asSheet() {
return (this instanceof BIFF8CalcSheet || this instanceof BIFF8MergeSheet) ? new BIFF8Sheet(this) : this;
}
@Override
public BIFF8CalcSheet asCalcSheet() {
return !(this instanceof BIFF8CalcSheet) ? new BIFF8CalcSheet(this) : (BIFF8CalcSheet) this;
}
@Override
public BIFF8MergeSheet asMergeSheet() {
return !(this instanceof BIFF8MergeSheet) ? new BIFF8MergeSheet(this) : (BIFF8MergeSheet) this;
}
@Override
public String toString() {
return "Sheet name: " + name + " has " + getDimension();
}
@Override
public Sheet reset() {
loaded = false;
load();
return this;
}
}
/**
* A sub {@link BIFF8Sheet} to parse cell calc
*/
class BIFF8CalcSheet extends BIFF8Sheet implements CalcSheet {
BIFF8CalcSheet(BIFF8Sheet sheet) {
this.name = sheet.name;
this.index = sheet.index;
this.header = sheet.header;
this.hidden = sheet.hidden;
this.dimension = sheet.dimension;
this.reader = sheet.reader;
this.sheetInfo = sheet.sheetInfo;
this.standard_sector = sheet.standard_sector;
this.loaded = sheet.loaded;
this.stream = sheet.stream;
}
}
/**
* A sub {@link BIFF8Sheet} to copy value on merge cells
*/
class BIFF8MergeSheet extends BIFF8Sheet implements MergeSheet {
BIFF8MergeSheet(BIFF8Sheet sheet) {
this.name = sheet.name;
this.index = sheet.index;
this.header = sheet.header;
this.hidden = sheet.hidden;
this.dimension = sheet.dimension;
this.reader = sheet.reader;
this.sheetInfo = sheet.sheetInfo;
this.standard_sector = sheet.standard_sector;
if (sheet.loaded) {
if (sheet.stream == null) this.stream = getStream();
else if (!(sheet.stream instanceof MergedSheetSubStream))
this.stream = MergedSheetSubStream.of(sheet.stream);
else this.stream = sheet.stream;
}
}
/**
* Returns a {@link MergedSheetSubStream}
*
* @return MergedSheetSubStream
*/
@Override
protected SheetSubStream getStream() {
return new MergedSheetSubStream(reader.gs, sheetInfo);
}
@Override
public Grid getMergeGrid() {
return stream != null ? ((MergedSheetSubStream) stream).getMergeCells(): null;
}
}