/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.read.biff;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Pattern;
import jxl.common.Logger;
import jxl.common.Assert;
import jxl.Cell;
import jxl.CellType;
import jxl.CellView;
import jxl.Hyperlink;
import jxl.Image;
import jxl.LabelCell;
import jxl.Range;
import jxl.Sheet;
import jxl.SheetSettings;
import jxl.WorkbookSettings;
import jxl.biff.BuiltInName;
import jxl.biff.AutoFilter;
import jxl.biff.CellFinder;
import jxl.biff.CellReferenceHelper;
import jxl.biff.ConditionalFormat;
import jxl.biff.DataValidation;
import jxl.biff.EmptyCell;
import jxl.biff.FormattingRecords;
import jxl.biff.Type;
import jxl.biff.WorkspaceInformationRecord;
import jxl.biff.drawing.Chart;
import jxl.biff.drawing.Drawing;
import jxl.biff.drawing.DrawingData;
import jxl.biff.drawing.DrawingGroupObject;
import jxl.format.CellFormat;
/**
* Represents a sheet within a workbook. Provides a handle to the individual
* cells, or lines of cells (grouped by Row or Column)
* In order to simplify this class due to code bloat, the actual reading
* logic has been delegated to the SheetReaderClass. This class' main
* responsibility is now to implement the API methods declared in the
* Sheet interface
*/
public class SheetImpl implements Sheet
{
/**
* The logger
*/
private static Logger logger = Logger.getLogger(SheetImpl.class);
/**
* The excel file
*/
private File excelFile;
/**
* A handle to the shared string table
*/
private SSTRecord sharedStrings;
/**
* A handle to the sheet BOF record, which indicates the stream type
*/
private BOFRecord sheetBof;
/**
* A handle to the workbook BOF record, which indicates the stream type
*/
private BOFRecord workbookBof;
/**
* A handle to the formatting records
*/
private FormattingRecords formattingRecords;
/**
* The name of this sheet
*/
private String name;
/**
* The number of rows
*/
private int numRows;
/**
* The number of columns
*/
private int numCols;
/**
* The cells
*/
private Cell[][] cells;
/**
* The start position in the stream of this sheet
*/
private int startPosition;
/**
* The list of specified (ie. non default) column widths
*/
private ColumnInfoRecord[] columnInfos;
/**
* The array of row records
*/
private RowRecord[] rowRecords;
/**
* The list of non-default row properties
*/
private ArrayList rowProperties;
/**
* An array of column info records. They are held this way before
* they are transferred to the more convenient array
*/
private ArrayList columnInfosArray;
/**
* A list of shared formula groups
*/
private ArrayList sharedFormulas;
/**
* A list of hyperlinks on this page
*/
private ArrayList hyperlinks;
/**
* A list of charts on this page
*/
private ArrayList charts;
/**
* A list of drawings on this page
*/
private ArrayList drawings;
/**
* A list of drawings (as opposed to comments/validation/charts) on this
* page
*/
private ArrayList images;
/**
* A list of data validations on this page
*/
private DataValidation dataValidation;
/**
* A list of merged cells on this page
*/
private Range[] mergedCells;
/**
* Indicates whether the columnInfos array has been initialized
*/
private boolean columnInfosInitialized;
/**
* Indicates whether the rowRecords array has been initialized
*/
private boolean rowRecordsInitialized;
/**
* Indicates whether or not the dates are based around the 1904 date system
*/
private boolean nineteenFour;
/**
* The workspace options
*/
private WorkspaceInformationRecord workspaceOptions;
/**
* The hidden flag
*/
private boolean hidden;
/**
* The environment specific print record
*/
private PLSRecord plsRecord;
/**
* The property set record associated with this workbook
*/
private ButtonPropertySetRecord buttonPropertySet;
/**
* The sheet settings
*/
private SheetSettings settings;
/**
* The horizontal page breaks contained on this sheet
*/
private int[] rowBreaks;
/**
* The vertical page breaks contained on this sheet
*/
private int[] columnBreaks;
/**
* The maximum row outline level
*/
private int maxRowOutlineLevel;
/**
* The maximum column outline level
*/
private int maxColumnOutlineLevel;
/**
* The list of local names for this sheet
*/
private ArrayList localNames;
/**
* The list of conditional formats for this sheet
*/
private ArrayList conditionalFormats;
/**
* The autofilter information
*/
private AutoFilter autoFilter;
/**
* A handle to the workbook which contains this sheet. Some of the records
* need this in order to reference external sheets
*/
private WorkbookParser workbook;
/**
* A handle to the workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* Constructor
*
* @param f the excel file
* @param sst the shared string table
* @param fr formatting records
* @param sb the bof record which indicates the start of the sheet
* @param wb the bof record which indicates the start of the sheet
* @param nf the 1904 flag
* @param wp the workbook which this sheet belongs to
* @exception BiffException
*/
SheetImpl(File f,
SSTRecord sst,
FormattingRecords fr,
BOFRecord sb,
BOFRecord wb,
boolean nf,
WorkbookParser wp)
throws BiffException
{
excelFile = f;
sharedStrings = sst;
formattingRecords = fr;
sheetBof = sb;
workbookBof = wb;
columnInfosArray = new ArrayList();
sharedFormulas = new ArrayList();
hyperlinks = new ArrayList();
rowProperties = new ArrayList(10);
columnInfosInitialized = false;
rowRecordsInitialized = false;
nineteenFour = nf;
workbook = wp;
workbookSettings = workbook.getSettings();
// Mark the position in the stream, and then skip on until the end
startPosition = f.getPos();
if (sheetBof.isChart())
{
// Set the start pos to include the bof so the sheet reader can handle it
startPosition -= (sheetBof.getLength() + 4);
}
Record r = null;
int bofs = 1;
while (bofs >= 1)
{
r = f.next();
// use this form for quick performance
if (r.getCode() == Type.EOF.value)
{
bofs--;
}
if (r.getCode() == Type.BOF.value)
{
bofs++;
}
}
}
/**
* Returns the cell for the specified location eg. "A4", using the
* CellReferenceHelper
*
* @param loc the cell reference
* @return the cell at the specified co-ordinates
*/
public Cell getCell(String loc)
{
return getCell(CellReferenceHelper.getColumn(loc),
CellReferenceHelper.getRow(loc));
}
/**
* Returns the cell specified at this row and at this column
*
* @param row the row number
* @param column the column number
* @return the cell at the specified co-ordinates
*/
public Cell getCell(int column, int row)
{
// just in case this has been cleared, but something else holds
// a reference to it
if (cells == null)
{
readSheet();
}
Cell c = cells[row][column];
if (c == null)
{
c = new EmptyCell(column, row);
cells[row][column] = c;
}
return c;
}
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param contents the string to match
* @return the Cell whose contents match the paramter, null if not found
*/
public Cell findCell(String contents)
{
CellFinder cellFinder = new CellFinder(this);
return cellFinder.findCell(contents);
}
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param contents the string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the range
* @param lastCol the last column within the range
* @param lastRow the last row within the range
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
public Cell findCell(String contents,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse)
{
CellFinder cellFinder = new CellFinder(this);
return cellFinder.findCell(contents,
firstCol,
firstRow,
lastCol,
lastRow,
reverse);
}
/**
* Gets the cell whose contents match the regular expressionstring passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param pattern the regular expression string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the range
* @param lastRow the last row within the range
* @param lastCol the last column within the ranage
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
public Cell findCell(Pattern pattern,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse)
{
CellFinder cellFinder = new CellFinder(this);
return cellFinder.findCell(pattern,
firstCol,
firstRow,
lastCol,
lastRow,
reverse);
}
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform. This method differs
* from the findCell methods in that only cells with labels are
* queried - all numerical cells are ignored. This should therefore
* improve performance.
*
* @param contents the string to match
* @return the Cell whose contents match the paramter, null if not found
*/
public LabelCell findLabelCell(String contents)
{
CellFinder cellFinder = new CellFinder(this);
return cellFinder.findLabelCell(contents);
}
/**
* Returns the number of rows in this sheet
*
* @return the number of rows in this sheet
*/
public int getRows()
{
// just in case this has been cleared, but something else holds
// a reference to it
if (cells == null)
{
readSheet();
}
return numRows;
}
/**
* Returns the number of columns in this sheet
*
* @return the number of columns in this sheet
*/
public int getColumns()
{
// just in case this has been cleared, but something else holds
// a reference to it
if (cells == null)
{
readSheet();
}
return numCols;
}
/**
* Gets all the cells on the specified row. The returned array will
* be stripped of all trailing empty cells
*
* @param row the rows whose cells are to be returned
* @return the cells on the given row
*/
public Cell[] getRow(int row)
{
// just in case this has been cleared, but something else holds
// a reference to it
if (cells == null)
{
readSheet();
}
// Find the last non-null cell
boolean found = false;
int col = numCols - 1;
while (col >= 0 && !found)
{
if (cells[row][col] != null)
{
found = true;
}
else
{
col--;
}
}
// Only create entries for non-null cells
Cell[] c = new Cell[col + 1];
for (int i = 0; i <= col; i++)
{
c[i] = getCell(i, row);
}
return c;
}
/**
* Gets all the cells on the specified column. The returned array
* will be stripped of all trailing empty cells
*
* @param col the column whose cells are to be returned
* @return the cells on the specified column
*/
public Cell[] getColumn(int col)
{
// just in case this has been cleared, but something else holds
// a reference to it
if (cells == null)
{
readSheet();
}
// Find the last non-null cell
boolean found = false;
int row = numRows - 1;
while (row >= 0 && !found)
{
if (cells[row][col] != null)
{
found = true;
}
else
{
row--;
}
}
// Only create entries for non-null cells
Cell[] c = new Cell[row + 1];
for (int i = 0; i <= row; i++)
{
c[i] = getCell(col, i);
}
return c;
}
/**
* Gets the name of this sheet
*
* @return the name of the sheet
*/
public String getName()
{
return name;
}
/**
* Sets the name of this sheet
*
* @param s the sheet name
*/
final void setName(String s)
{
name = s;
}
/**
* Determines whether the sheet is hidden
*
* @return whether or not the sheet is hidden
* @deprecated in favour of the getSettings function
*/
public boolean isHidden()
{
return hidden;
}
/**
* Gets the column info record for the specified column. If no
* column is specified, null is returned
*
* @param col the column
* @return the ColumnInfoRecord if specified, NULL otherwise
*/
public ColumnInfoRecord getColumnInfo(int col)
{
if (!columnInfosInitialized)
{
// Initialize the array
Iterator i = columnInfosArray.iterator();
ColumnInfoRecord cir = null;
while (i.hasNext())
{
cir = (ColumnInfoRecord) i.next();
int startcol = Math.max(0, cir.getStartColumn());
int endcol = Math.min(columnInfos.length - 1, cir.getEndColumn());
for (int c = startcol; c <= endcol; c++)
{
columnInfos[c] = cir;
}
if (endcol < startcol)
{
columnInfos[startcol] = cir;
}
}
columnInfosInitialized = true;
}
return col < columnInfos.length ? columnInfos[col] : null;
}
/**
* Gets all the column info records
*
* @return the ColumnInfoRecordArray
*/
public ColumnInfoRecord[] getColumnInfos()
{
// Just chuck all the column infos we have into an array
ColumnInfoRecord[] infos = new ColumnInfoRecord[columnInfosArray.size()];
for (int i = 0; i < columnInfosArray.size(); i++)
{
infos[i] = (ColumnInfoRecord) columnInfosArray.get(i);
}
return infos;
}
/**
* Sets the visibility of this sheet
*
* @param h hidden flag
*/
final void setHidden(boolean h)
{
hidden = h;
}
/**
* Clears out the array of cells. This is done for memory allocation
* reasons when reading very large sheets
*/
final void clear()
{
cells = null;
mergedCells = null;
columnInfosArray.clear();
sharedFormulas.clear();
hyperlinks.clear();
columnInfosInitialized = false;
if (!workbookSettings.getGCDisabled())
{
System.gc();
}
}
/**
* Reads in the contents of this sheet
*/
final void readSheet()
{
// If this sheet contains only a chart, then set everything to
// empty and do not bother parsing the sheet
// Thanks to steve.brophy for spotting this
if (!sheetBof.isWorksheet())
{
numRows = 0;
numCols = 0;
cells = new Cell[0][0];
// return;
}
SheetReader reader = new SheetReader(excelFile,
sharedStrings,
formattingRecords,
sheetBof,
workbookBof,
nineteenFour,
workbook,
startPosition,
this);
reader.read();
// Take stuff that was read in
numRows = reader.getNumRows();
numCols = reader.getNumCols();
cells = reader.getCells();
rowProperties = reader.getRowProperties();
columnInfosArray = reader.getColumnInfosArray();
hyperlinks = reader.getHyperlinks();
conditionalFormats = reader.getConditionalFormats();
autoFilter = reader.getAutoFilter();
charts = reader.getCharts();
drawings = reader.getDrawings();
dataValidation = reader.getDataValidation();
mergedCells = reader.getMergedCells();
settings = reader.getSettings();
settings.setHidden(hidden);
rowBreaks = reader.getRowBreaks();
columnBreaks = reader.getColumnBreaks();
workspaceOptions = reader.getWorkspaceOptions();
plsRecord = reader.getPLS();
buttonPropertySet = reader.getButtonPropertySet();
maxRowOutlineLevel = reader.getMaxRowOutlineLevel();
maxColumnOutlineLevel = reader.getMaxColumnOutlineLevel();
reader = null;
if (!workbookSettings.getGCDisabled())
{
System.gc();
}
if (columnInfosArray.size() > 0)
{
ColumnInfoRecord cir = (ColumnInfoRecord)
columnInfosArray.get(columnInfosArray.size() - 1);
columnInfos = new ColumnInfoRecord[cir.getEndColumn() + 1];
}
else
{
columnInfos = new ColumnInfoRecord[0];
}
// Add any local names
if (localNames != null)
{
for (Iterator it = localNames.iterator(); it.hasNext() ;)
{
NameRecord nr = (NameRecord) it.next();
if (nr.getBuiltInName() == BuiltInName.PRINT_AREA)
{
if(nr.getRanges().length > 0)
{
NameRecord.NameRange rng = nr.getRanges()[0];
settings.setPrintArea(rng.getFirstColumn(),
rng.getFirstRow(),
rng.getLastColumn(),
rng.getLastRow());
}
}
else if (nr.getBuiltInName() == BuiltInName.PRINT_TITLES)
{
// There can be 1 or 2 entries.
// Row entries have hardwired column entries (first and last
// possible column)
// Column entries have hardwired row entries (first and last
// possible row)
for (int i = 0 ; i < nr.getRanges().length ; i++)
{
NameRecord.NameRange rng = nr.getRanges()[i];
if (rng.getFirstColumn() == 0 && rng.getLastColumn() == 255)
{
settings.setPrintTitlesRow(rng.getFirstRow(),
rng.getLastRow());
}
else
{
settings.setPrintTitlesCol(rng.getFirstColumn(),
rng.getLastColumn());
}
}
}
}
}
}
/**
* Gets the hyperlinks on this sheet
*
* @return an array of hyperlinks
*/
public Hyperlink[] getHyperlinks()
{
Hyperlink[] hl = new Hyperlink[hyperlinks.size()];
for (int i = 0; i < hyperlinks.size(); i++)
{
hl[i] = (Hyperlink) hyperlinks.get(i);
}
return hl;
}
/**
* Gets the cells which have been merged on this sheet
*
* @return an array of range objects
*/
public Range[] getMergedCells()
{
if (mergedCells == null)
{
return new Range[0];
}
return mergedCells;
}
/**
* Gets the non-default rows. Used when copying spreadsheets
*
* @return an array of row properties
*/
public RowRecord[] getRowProperties()
{
RowRecord[] rp = new RowRecord[rowProperties.size()];
for (int i = 0; i < rp.length; i++)
{
rp[i] = (RowRecord) rowProperties.get(i);
}
return rp;
}
/**
* Gets the data validations. Used when copying sheets
*
* @return the data validations
*/
public DataValidation getDataValidation()
{
return dataValidation;
}
/**
* Gets the row record. Usually called by the cell in the specified
* row in order to determine its size
*
* @param r the row
* @return the RowRecord for the specified row
*/
RowRecord getRowInfo(int r)
{
if (!rowRecordsInitialized)
{
rowRecords = new RowRecord[getRows()];
Iterator i = rowProperties.iterator();
int rownum = 0;
RowRecord rr = null;
while (i.hasNext())
{
rr = (RowRecord) i.next();
rownum = rr.getRowNumber();
if (rownum < rowRecords.length)
{
rowRecords[rownum] = rr;
}
}
rowRecordsInitialized = true;
}
return r < rowRecords.length ? rowRecords[r] : null;
}
/**
* Gets the row breaks. Called when copying sheets
*
* @return the explicit row breaks
*/
public final int[] getRowPageBreaks()
{
return rowBreaks;
}
/**
* Gets the row breaks. Called when copying sheets
*
* @return the explicit row breaks
*/
public final int[] getColumnPageBreaks()
{
return columnBreaks;
}
/**
* Gets the charts. Called when copying sheets
*
* @return the charts on this page
*/
public final Chart[] getCharts()
{
Chart[] ch = new Chart[charts.size()];
for (int i = 0; i < ch.length; i++)
{
ch[i] = (Chart) charts.get(i);
}
return ch;
}
/**
* Gets the drawings. Called when copying sheets
*
* @return the drawings on this page
*/
public final DrawingGroupObject[] getDrawings()
{
DrawingGroupObject[] dr = new DrawingGroupObject[drawings.size()];
dr = (DrawingGroupObject[]) drawings.toArray(dr);
return dr;
}
/**
* Determines whether the sheet is protected
*
* @return whether or not the sheet is protected
* @deprecated in favour of the getSettings() api
*/
public boolean isProtected()
{
return settings.isProtected();
}
/**
* Gets the workspace options for this sheet. Called during the copy
* process
*
* @return the workspace options
*/
public WorkspaceInformationRecord getWorkspaceOptions()
{
return workspaceOptions;
}
/**
* Accessor for the sheet settings
*
* @return the settings for this sheet
*/
public SheetSettings getSettings()
{
return settings;
}
/**
* Accessor for the workbook. In addition to be being used by this package,
* it is also used during the importSheet process
*
* @return the workbook
*/
public WorkbookParser getWorkbook()
{
return workbook;
}
/**
* Gets the column format for the specified column
*
* @param col the column number
* @return the column format, or NULL if the column has no specific format
* @deprecated use getColumnView instead
*/
public CellFormat getColumnFormat(int col)
{
CellView cv = getColumnView(col);
return cv.getFormat();
}
/**
* Gets the column width for the specified column
*
* @param col the column number
* @return the column width, or the default width if the column has no
* specified format
*/
public int getColumnWidth(int col)
{
return getColumnView(col).getSize() / 256;
}
/**
* Gets the column width for the specified column
*
* @param col the column number
* @return the column format, or the default format if no override is
specified
*/
public CellView getColumnView(int col)
{
ColumnInfoRecord cir = getColumnInfo(col);
CellView cv = new CellView();
if (cir != null)
{
cv.setDimension(cir.getWidth() / 256); //deprecated
cv.setSize(cir.getWidth());
cv.setHidden(cir.getHidden());
cv.setFormat(formattingRecords.getXFRecord(cir.getXFIndex()));
}
else
{
cv.setDimension(settings.getDefaultColumnWidth()); //deprecated
cv.setSize(settings.getDefaultColumnWidth() * 256);
}
return cv;
}
/**
* Gets the row height for the specified column
*
* @param row the row number
* @return the row height, or the default height if the row has no
* specified format
* @deprecated use getRowView instead
*/
public int getRowHeight(int row)
{
return getRowView(row).getDimension();
}
/**
* Gets the row view for the specified row
*
* @param row the row number
* @return the row format, or the default format if no override is
specified
*/
public CellView getRowView(int row)
{
RowRecord rr = getRowInfo(row);
CellView cv = new CellView();
if (rr != null)
{
cv.setDimension(rr.getRowHeight()); //deprecated
cv.setSize(rr.getRowHeight());
cv.setHidden(rr.isCollapsed());
if (rr.hasDefaultFormat())
{
cv.setFormat(formattingRecords.getXFRecord(rr.getXFIndex()));
}
}
else
{
cv.setDimension(settings.getDefaultRowHeight());
cv.setSize(settings.getDefaultRowHeight()); //deprecated
}
return cv;
}
/**
* Used when copying sheets in order to determine the type of this sheet
*
* @return the BOF Record
*/
public BOFRecord getSheetBof()
{
return sheetBof;
}
/**
* Used when copying sheets in order to determine the type of the containing
* workboook
*
* @return the workbook BOF Record
*/
public BOFRecord getWorkbookBof()
{
return workbookBof;
}
/**
* Accessor for the environment specific print record, invoked when
* copying sheets
*
* @return the environment specific print record
*/
public PLSRecord getPLS()
{
return plsRecord;
}
/**
* Accessor for the button property set, used during copying
*
* @return the button property set
*/
public ButtonPropertySetRecord getButtonPropertySet()
{
return buttonPropertySet;
}
/**
* Accessor for the number of images on the sheet
*
* @return the number of images on this sheet
*/
public int getNumberOfImages()
{
if (images == null)
{
initializeImages();
}
return images.size();
}
/**
* Accessor for the image
*
* @param i the 0 based image number
* @return the image at the specified position
*/
public Image getDrawing(int i)
{
if (images == null)
{
initializeImages();
}
return (Image) images.get(i);
}
/**
* Initializes the images
*/
private void initializeImages()
{
if (images != null)
{
return;
}
images = new ArrayList();
DrawingGroupObject[] dgos = getDrawings();
for (int i = 0; i < dgos.length; i++)
{
if (dgos[i] instanceof Drawing)
{
images.add(dgos[i]);
}
}
}
/**
* Used by one of the demo programs for debugging purposes only
*/
public DrawingData getDrawingData()
{
SheetReader reader = new SheetReader(excelFile,
sharedStrings,
formattingRecords,
sheetBof,
workbookBof,
nineteenFour,
workbook,
startPosition,
this);
reader.read();
return reader.getDrawingData();
}
/**
* Adds a local name to this shate
*
* @param nr the local name to add
*/
void addLocalName(NameRecord nr)
{
if (localNames == null)
{
localNames = new ArrayList();
}
localNames.add(nr);
}
/**
* Gets the conditional formats
*
* @return the conditional formats
*/
public ConditionalFormat[] getConditionalFormats()
{
ConditionalFormat[] formats =
new ConditionalFormat[conditionalFormats.size()];
formats = (ConditionalFormat[]) conditionalFormats.toArray(formats);
return formats;
}
/**
* Returns the autofilter
*
* @return the autofilter
*/
public AutoFilter getAutoFilter()
{
return autoFilter;
}
/**
* Accessor for the maximum column outline level. Used during a copy
*
* @return the maximum column outline level, or 0 if no outlines/groups
*/
public int getMaxColumnOutlineLevel()
{
return maxColumnOutlineLevel;
}
/**
* Accessor for the maximum row outline level. Used during a copy
*
* @return the maximum row outline level, or 0 if no outlines/groups
*/
public int getMaxRowOutlineLevel()
{
return maxRowOutlineLevel;
}
}
|