diff --git a/examples/style/main.cpp b/examples/style/main.cpp index 7ada464..57dd580 100644 --- a/examples/style/main.cpp +++ b/examples/style/main.cpp @@ -26,7 +26,22 @@ int main() sheet->write("C5", "=44+33", format2); sheet->write("D7", true, format2); + QXlsx::Format *format3 = workbook.addFormat(); + format3->setFontBold(true); + format3->setFontColor(QColor(Qt::blue)); + format3->setFontSize(20); + sheet->write(10, 0, "Hello Row Style"); + sheet->write(10, 5, "Blue Color"); + sheet->setRow(10, 40, format3); + + QXlsx::Format *format4 = workbook.addFormat(); + format4->setFontBold(true); + format4->setFontColor(QColor(Qt::magenta)); + for (int row=20; row<40; row++) + for (int col=8; col<15; col++) + sheet->write(row, col, row+col); + sheet->setColumn(8, 15, 5.0, format4); + workbook.save(DATA_PATH"TestStyle.xlsx"); - workbook.save(DATA_PATH"TestStyle.zip"); return 0; } diff --git a/src/xlsxworksheet.cpp b/src/xlsxworksheet.cpp index f9d147d..bb4f8f5 100755 --- a/src/xlsxworksheet.cpp +++ b/src/xlsxworksheet.cpp @@ -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 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 diff --git a/src/xlsxworksheet.h b/src/xlsxworksheet.h index 0deee22..c43f935 100755 --- a/src/xlsxworksheet.h +++ b/src/xlsxworksheet.h @@ -37,27 +37,9 @@ class Workbook; class XmlStreamWriter; class Format; -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 XlsxCellData; +struct XlsxRowInfo; +struct XlsxColumnInfo; class Worksheet : public QObject { @@ -71,13 +53,18 @@ public: int writeBlank(int row, int column, Format *format=0); int writeBool(int row, int column, bool value, Format *format=0); + bool setRow(int row, double height, Format* format=0, bool hidden=false); + bool setColumn(int colFirst, int colLast, double width, Format* format=0, bool hidden=false); + void setRightToLeft(bool enable); void setZeroValuesHidden(bool enable); private: friend class Package; friend class Workbook; - explicit Worksheet(const QString &sheetName, int sheetIndex, Workbook *parent=0); + Worksheet(const QString &sheetName, int sheetIndex, Workbook *parent=0); + ~Worksheet(); + virtual bool isChartsheet() const; QString name() const; int index() const; @@ -91,12 +78,16 @@ private: int checkDimensions(int row, int col, bool ignore_row=false, bool ignore_col=false); QString generateDimensionString(); void writeSheetData(XmlStreamWriter &writer); - void writeCellData(XmlStreamWriter &writer, int row, int col, const XlsxCellData &data); + void writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell); void calculateSpans(); Workbook *m_workbook; - QMap > m_table; + QMap > m_cellTable; QMap > m_comments; + QMap m_rowsInfo; + QList m_colsInfo; + QMap m_colsInfoHelper;//Not owns the XlsxColumnInfo + int m_xls_rowmax; int m_xls_colmax; @@ -126,6 +117,4 @@ private: } //QXlsx -Q_DECLARE_TYPEINFO(QXlsx::XlsxCellData, Q_MOVABLE_TYPE); - #endif // XLSXWORKSHEET_H