|
|
@ -38,6 +38,55 @@ |
|
|
|
|
|
|
|
namespace QXlsx { |
|
|
|
|
|
|
|
struct XlsxCellData |
|
|
|
{ |
|
|
|
enum CellDataType { |
|
|
|
Blank, |
|
|
|
String, |
|
|
|
Number, |
|
|
|
Formula, |
|
|
|
ArrayFormula, |
|
|
|
Boolean |
|
|
|
}; |
|
|
|
XlsxCellData(const QVariant &data=QVariant(), CellDataType type=Blank, Format *format=0) : |
|
|
|
value(data), dataType(type), format(format) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
QVariant value; |
|
|
|
QString formula; |
|
|
|
CellDataType dataType; |
|
|
|
Format *format; |
|
|
|
}; |
|
|
|
|
|
|
|
struct XlsxRowInfo |
|
|
|
{ |
|
|
|
XlsxRowInfo(double height, Format *format, bool hidden) : |
|
|
|
height(height), format(format), hidden(hidden) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
double height; |
|
|
|
Format *format; |
|
|
|
bool hidden; |
|
|
|
}; |
|
|
|
|
|
|
|
struct XlsxColumnInfo |
|
|
|
{ |
|
|
|
XlsxColumnInfo(int column_min, int column_max, double width, Format *format, bool hidden) : |
|
|
|
column_min(column_min), column_max(column_max), width(width), format(format), hidden(hidden) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
int column_min; |
|
|
|
int column_max; |
|
|
|
double width; |
|
|
|
Format *format; |
|
|
|
bool hidden; |
|
|
|
}; |
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Worksheet::Worksheet |
|
|
|
* \param name Name of the worksheet |
|
|
@ -70,6 +119,21 @@ Worksheet::Worksheet(const QString &name, int index, Workbook *parent) : |
|
|
|
m_show_zeros = true; |
|
|
|
} |
|
|
|
|
|
|
|
Worksheet::~Worksheet() |
|
|
|
{ |
|
|
|
typedef QMap<int, XlsxCellData *> RowMap; |
|
|
|
foreach (RowMap row, m_cellTable) { |
|
|
|
foreach (XlsxCellData *item, row) |
|
|
|
delete item; |
|
|
|
} |
|
|
|
|
|
|
|
foreach (XlsxRowInfo *row, m_rowsInfo) |
|
|
|
delete row; |
|
|
|
|
|
|
|
foreach (XlsxColumnInfo *col, m_colsInfo) |
|
|
|
delete col; |
|
|
|
} |
|
|
|
|
|
|
|
bool Worksheet::isChartsheet() const |
|
|
|
{ |
|
|
|
return false; |
|
|
@ -187,7 +251,7 @@ int Worksheet::writeString(int row, int column, const QString &value, Format *fo |
|
|
|
SharedStrings *sharedStrings = m_workbook->sharedStrings(); |
|
|
|
int index = sharedStrings->addSharedString(content); |
|
|
|
|
|
|
|
m_table[row][column] = XlsxCellData(index, XlsxCellData::String, format); |
|
|
|
m_cellTable[row][column] = new XlsxCellData(index, XlsxCellData::String, format); |
|
|
|
return error; |
|
|
|
} |
|
|
|
|
|
|
@ -196,7 +260,7 @@ int Worksheet::writeNumber(int row, int column, double value, Format *format) |
|
|
|
if (checkDimensions(row, column)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
m_table[row][column] = XlsxCellData(value, XlsxCellData::Number, format); |
|
|
|
m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -211,9 +275,9 @@ int Worksheet::writeFormula(int row, int column, const QString &content, Format |
|
|
|
if (formula.startsWith("=")) |
|
|
|
formula.remove(0,1); |
|
|
|
|
|
|
|
XlsxCellData data(result, XlsxCellData::Formula, format); |
|
|
|
data.formula = formula; |
|
|
|
m_table[row][column] = data; |
|
|
|
XlsxCellData *data = new XlsxCellData(result, XlsxCellData::Formula, format); |
|
|
|
data->formula = formula; |
|
|
|
m_cellTable[row][column] = data; |
|
|
|
|
|
|
|
return error; |
|
|
|
} |
|
|
@ -223,7 +287,7 @@ int Worksheet::writeBlank(int row, int column, Format *format) |
|
|
|
if (checkDimensions(row, column)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
m_table[row][column] = XlsxCellData(QVariant(), XlsxCellData::Blank, format); |
|
|
|
m_cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -232,7 +296,7 @@ int Worksheet::writeBool(int row, int column, bool value, Format *format) |
|
|
|
if (checkDimensions(row, column)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
m_table[row][column] = XlsxCellData(value, XlsxCellData::Boolean, format); |
|
|
|
m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -304,6 +368,22 @@ void Worksheet::saveToXmlFile(QIODevice *device) |
|
|
|
// writer.writeAttribute("x14ac:dyDescent", "0.25");
|
|
|
|
writer.writeEndElement();//sheetFormatPr
|
|
|
|
|
|
|
|
writer.writeStartElement("cols"); |
|
|
|
foreach (XlsxColumnInfo *col_info, m_colsInfo) { |
|
|
|
writer.writeStartElement("col"); |
|
|
|
writer.writeAttribute("min", QString::number(col_info->column_min)); |
|
|
|
writer.writeAttribute("max", QString::number(col_info->column_max)); |
|
|
|
writer.writeAttribute("width", QString::number(col_info->width, 'g', 15)); |
|
|
|
if (col_info->format) |
|
|
|
writer.writeAttribute("style", QString::number(col_info->format->xfIndex())); |
|
|
|
if (col_info->hidden) |
|
|
|
writer.writeAttribute("hidden", "1"); |
|
|
|
if (col_info->width) |
|
|
|
writer.writeAttribute("customWidth", "1"); |
|
|
|
writer.writeEndElement();//col
|
|
|
|
} |
|
|
|
writer.writeEndElement();//cols
|
|
|
|
|
|
|
|
writer.writeStartElement("sheetData"); |
|
|
|
if (m_dim_rowmax == INT32_MIN) { |
|
|
|
//If the max dimensions are equal to INT32_MIN, then there is no data to write
|
|
|
@ -350,7 +430,7 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer) |
|
|
|
{ |
|
|
|
calculateSpans(); |
|
|
|
for (int row_num = m_dim_rowmin; row_num <= m_dim_rowmax; row_num++) { |
|
|
|
if (!(m_table.contains(row_num) || m_comments.contains(row_num))) { |
|
|
|
if (!(m_cellTable.contains(row_num) || m_comments.contains(row_num) || m_rowsInfo.contains(row_num))) { |
|
|
|
//Only process rows with cell data / comments / formatting
|
|
|
|
continue; |
|
|
|
} |
|
|
@ -360,14 +440,30 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer) |
|
|
|
if (m_row_spans.contains(span_index)) |
|
|
|
span = m_row_spans[span_index]; |
|
|
|
|
|
|
|
if (m_table.contains(row_num)) { |
|
|
|
if (m_cellTable.contains(row_num)) { |
|
|
|
writer.writeStartElement("row"); |
|
|
|
writer.writeAttribute("r", QString::number(row_num + 1)); |
|
|
|
|
|
|
|
if (!span.isEmpty()) |
|
|
|
writer.writeAttribute("spans", span); |
|
|
|
|
|
|
|
if (m_rowsInfo.contains(row_num)) { |
|
|
|
XlsxRowInfo *rowInfo = m_rowsInfo[row_num]; |
|
|
|
if (rowInfo->format) { |
|
|
|
writer.writeAttribute("s", QString::number(rowInfo->format->xfIndex())); |
|
|
|
writer.writeAttribute("customFormat", "1"); |
|
|
|
} |
|
|
|
if (rowInfo->height != 15) { |
|
|
|
writer.writeAttribute("ht", QString::number(rowInfo->height)); |
|
|
|
writer.writeAttribute("customHeight", "1"); |
|
|
|
} |
|
|
|
if (rowInfo->hidden) |
|
|
|
writer.writeAttribute("hidden", "1"); |
|
|
|
} |
|
|
|
|
|
|
|
for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { |
|
|
|
if (m_table[row_num].contains(col_num)) { |
|
|
|
writeCellData(writer, row_num, col_num, m_table[row_num][col_num]); |
|
|
|
if (m_cellTable[row_num].contains(col_num)) { |
|
|
|
writeCellData(writer, row_num, col_num, m_cellTable[row_num][col_num]); |
|
|
|
} |
|
|
|
} |
|
|
|
writer.writeEndElement(); //row
|
|
|
@ -376,11 +472,10 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer) |
|
|
|
} else { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, const XlsxCellData &data) |
|
|
|
void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell) |
|
|
|
{ |
|
|
|
//This is the innermost loop so efficiency is important.
|
|
|
|
QString cell_range = xl_rowcol_to_cell_fast(row, col); |
|
|
@ -389,28 +484,32 @@ void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, const X |
|
|
|
writer.writeAttribute("r", cell_range); |
|
|
|
|
|
|
|
//Style used by the cell, row or col
|
|
|
|
if (data.format) |
|
|
|
writer.writeAttribute("s", QString::number(data.format->xfIndex())); |
|
|
|
|
|
|
|
if (data.dataType == XlsxCellData::String) { |
|
|
|
//data.data: Index of the string in sharedStringTable
|
|
|
|
if (cell->format) |
|
|
|
writer.writeAttribute("s", QString::number(cell->format->xfIndex())); |
|
|
|
else if (m_rowsInfo.contains(row) && m_rowsInfo[row]->format) |
|
|
|
writer.writeAttribute("s", QString::number(m_rowsInfo[row]->format->xfIndex())); |
|
|
|
else if (m_colsInfoHelper.contains(col) && m_colsInfoHelper[col]->format) |
|
|
|
writer.writeAttribute("s", QString::number(m_colsInfoHelper[col]->format->xfIndex())); |
|
|
|
|
|
|
|
if (cell->dataType == XlsxCellData::String) { |
|
|
|
//cell->data: Index of the string in sharedStringTable
|
|
|
|
writer.writeAttribute("t", "s"); |
|
|
|
writer.writeTextElement("v", data.value.toString()); |
|
|
|
} else if (data.dataType == XlsxCellData::Number){ |
|
|
|
writer.writeTextElement("v", data.value.toString()); |
|
|
|
} else if (data.dataType == XlsxCellData::Formula) { |
|
|
|
writer.writeTextElement("v", cell->value.toString()); |
|
|
|
} else if (cell->dataType == XlsxCellData::Number){ |
|
|
|
writer.writeTextElement("v", cell->value.toString()); |
|
|
|
} else if (cell->dataType == XlsxCellData::Formula) { |
|
|
|
bool ok = true; |
|
|
|
data.formula.toDouble(&ok); |
|
|
|
cell->formula.toDouble(&ok); |
|
|
|
if (!ok) //is string
|
|
|
|
writer.writeAttribute("t", "str"); |
|
|
|
writer.writeTextElement("f", data.formula); |
|
|
|
writer.writeTextElement("v", data.value.toString()); |
|
|
|
} else if (data.dataType == XlsxCellData::ArrayFormula) { |
|
|
|
writer.writeTextElement("f", cell->formula); |
|
|
|
writer.writeTextElement("v", cell->value.toString()); |
|
|
|
} else if (cell->dataType == XlsxCellData::ArrayFormula) { |
|
|
|
|
|
|
|
} else if (data.dataType == XlsxCellData::Boolean) { |
|
|
|
} else if (cell->dataType == XlsxCellData::Boolean) { |
|
|
|
writer.writeAttribute("t", "b"); |
|
|
|
writer.writeTextElement("v", data.value.toBool() ? "1" : "0"); |
|
|
|
} else if (data.dataType == XlsxCellData::Blank) { |
|
|
|
writer.writeTextElement("v", cell->value.toBool() ? "1" : "0"); |
|
|
|
} else if (cell->dataType == XlsxCellData::Blank) { |
|
|
|
//Ok, empty here.
|
|
|
|
} |
|
|
|
writer.writeEndElement(); //c
|
|
|
@ -429,9 +528,9 @@ void Worksheet::calculateSpans() |
|
|
|
int span_max = INT32_MIN; |
|
|
|
|
|
|
|
for (int row_num = m_dim_rowmin; row_num <= m_dim_rowmax; row_num++) { |
|
|
|
if (m_table.contains(row_num)) { |
|
|
|
if (m_cellTable.contains(row_num)) { |
|
|
|
for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { |
|
|
|
if (m_table[row_num].contains(col_num)) { |
|
|
|
if (m_cellTable[row_num].contains(col_num)) { |
|
|
|
if (span_max == INT32_MIN) { |
|
|
|
span_min = col_num; |
|
|
|
span_max = col_num; |
|
|
@ -472,4 +571,50 @@ void Worksheet::calculateSpans() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
Sets row height and format. Row height measured in point size. If format |
|
|
|
equals 0 then format is ignored. |
|
|
|
*/ |
|
|
|
bool Worksheet::setRow(int row, double height, Format *format, bool hidden) |
|
|
|
{ |
|
|
|
int min_col = m_dim_colmax == INT32_MIN ? 0 : m_dim_colmin; |
|
|
|
|
|
|
|
if (checkDimensions(row, min_col)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (m_rowsInfo.contains(row)) { |
|
|
|
m_rowsInfo[row]->height = height; |
|
|
|
m_rowsInfo[row]->format = format; |
|
|
|
m_rowsInfo[row]->hidden = hidden; |
|
|
|
} else { |
|
|
|
m_rowsInfo[row] = new XlsxRowInfo(height, format, hidden); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
Sets column width and format for all columns from colFirst to colLast. Column |
|
|
|
width measured as the number of characters of the maximum digit width of the |
|
|
|
numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. If format |
|
|
|
equals 0 then format is ignored. |
|
|
|
*/ |
|
|
|
bool Worksheet::setColumn(int colFirst, int colLast, double width, Format *format, bool hidden) |
|
|
|
{ |
|
|
|
bool ignore_row = true; |
|
|
|
bool ignore_col = (format || (width && hidden)) ? false : true; |
|
|
|
|
|
|
|
if (checkDimensions(0, colLast, ignore_row, ignore_col)) |
|
|
|
return false; |
|
|
|
if (checkDimensions(0, colFirst, ignore_row, ignore_col)) |
|
|
|
return false; |
|
|
|
|
|
|
|
XlsxColumnInfo *info = new XlsxColumnInfo(colFirst, colLast, width, format, hidden); |
|
|
|
m_colsInfo.append(info); |
|
|
|
|
|
|
|
for (int col=colFirst; col<=colLast; ++col) |
|
|
|
m_colsInfoHelper[col] = info; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
} //namespace
|
|
|
|