diff --git a/src/xlsx/xlsxdocument.cpp b/src/xlsx/xlsxdocument.cpp index 2701a0e..b2a5cdb 100644 --- a/src/xlsx/xlsxdocument.cpp +++ b/src/xlsx/xlsxdocument.cpp @@ -515,50 +515,230 @@ bool Document::unmergeCells(const CellRange &range) } /*! - Sets the properties of \a row with the given \a height, \a format and \a hidden. - \a row is 1-indexed. + Sets width in characters of a range of columns. + Returns true on success. + */ +bool Document::setColumnWidth(const CellRange &range, double width) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnWidth(range, width); + return false; +} + +/*! + Sets format property of a range of columns. + Returns true on success. + */ +bool Document::setColumnFormat(const CellRange &range, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnFormat(range, format); + return false; +} + +/*! + Sets hidden property of a range of columns. Columns are 1-indexed. + Hidden columns are not visible. + Returns true on success. + */ +bool Document::setColumnHidden(const CellRange &range, bool hidden) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnWidth(range, hidden); + return false; +} + +/*! + Sets width in characters of a range of columns. Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnWidth(int column, double width) +{ + return setColumnWidth(column,column,width); +} + +/*! + Sets format property of a range of columns. Columns are 1-indexed. + */ +bool Document::setColumnFormat(int column, const Format &format) +{ + return setColumnFormat(column,column,format); +} - Returns false if failed. +/*! + Sets hidden property of a column. Columns are 1-indexed. + */ +bool Document::setColumnHidden(int column, bool hidden) +{ + return setColumnHidden(column,column,hidden); +} + +/*! + Sets width in characters of a range of columns. Columns are 1-indexed. + Returns true on success. */ -bool Document::setRow(int row, double height, const Format &format, bool hidden) +bool Document::setColumnWidth(int colFirst, int colLast, double width) { if (Worksheet *sheet = currentWorksheet()) - return sheet->setRow(row, height, format, hidden); + return sheet->setColumnWidth(colFirst, colLast, width); return false; } /*! - Sets the column properties for all columns from \a colFirst to \a colLast with - the given \a width, \a format and \a hidden. 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. - \a colFirst and \a colLast are all 1-indexed. + Sets format property of a range of columns. Columns are 1-indexed. + */ +bool Document::setColumnFormat(int colFirst, int colLast, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnFormat(colFirst, colLast, format); + return false; +} + - Return false if failed. +/*! + Sets hidden property of a range of columns. Columns are 1-indexed. */ -bool Document::setColumn(int colFirst, int colLast, double width, const Format &format, bool hidden) +bool Document::setColumnHidden(int colFirst, int colLast, bool hidden) { if (Worksheet *sheet = currentWorksheet()) - return sheet->setColumn(colFirst, colLast, width, format, hidden); + return sheet->setColumnHidden(colFirst, colLast, hidden); return false; } /*! - \overload + Returns width of the column in characters of the normal font. Columns are 1-indexed. + */ +double Document::columnWidth(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->columnWidth(column); + return 0.0; +} + +/*! + Returns formatting of the column. Columns are 1-indexed. + */ +Format Document::columnFormat(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->columnFormat(column); + return Format(); +} - Sets column width and format for all columns from \a colFirst to \a colLast with - the given \a width and \a format. Column - \a 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. - \a colFirst and \a colLast should be "A", "B", "C", ... +/*! + Returns true if column is hidden. Columns are 1-indexed. */ -bool Document::setColumn(const QString &colFirst, const QString &colLast, double width, const Format &format, bool hidden) +bool Document::isColumnHidden(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->isColumnHidden(column); + return false; +} + +/*! + Sets the \a format of the row \a row. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowFormat(int row, const Format &format) +{ + return setRowFormat(row,row, format); +} + +/*! + Sets the \a format of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowFormat(int rowFirst, int rowLast, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setRowFormat(rowFirst, rowLast, format); + return false; +} + +/*! + Sets the \a hidden property of the row \a row. + Rows are 1-indexed. If hidden is true rows will not be visible. + + Returns true if success. +*/ +bool Document::setRowHidden(int row, bool hidden) +{ + return setRowHidden(row,row,hidden); +} + +/*! + Sets the \a hidden property of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. If hidden is true rows will not be visible. + + Returns true if success. +*/ +bool Document::setRowHidden(int rowFirst, int rowLast, bool hidden) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setRowHidden(rowFirst, rowLast, hidden); + return false; +} + +/*! + Sets the \a height of the row \a row. + Row height measured in point size. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowHeight(int row, double height) +{ + return setRowHeight(row,row,height); +} + +/*! + Sets the \a height of the rows including and between \a rowFirst and \a rowLast. + Row height measured in point size. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowHeight(int rowFirst, int rowLast, double height) { if (Worksheet *sheet = currentWorksheet()) - return sheet->setColumn(colFirst, colLast, width, format, hidden); + return sheet->setRowHeight(rowFirst, rowLast, height); return false; } +/*! + Returns height of \a row in points. +*/ +double Document::rowHeight(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->rowHeight(row); + return 0.0; +} + +/*! + Returns format of \a row. +*/ +Format Document::rowFormat(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->rowFormat(row); + return Format(); +} + +/*! + Returns true if \a row is hidden. +*/ +bool Document::isRowHidden(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->isRowHidden(row); + return false; +} + /*! Groups rows from \a rowFirst to \a rowLast with the given \a collapsed. Returns false if error occurs. diff --git a/src/xlsx/xlsxdocument.h b/src/xlsx/xlsxdocument.h index 48e10c8..7770870 100644 --- a/src/xlsx/xlsxdocument.h +++ b/src/xlsx/xlsxdocument.h @@ -65,9 +65,31 @@ public: bool mergeCells(const QString &range, const Format &format=Format()); bool unmergeCells(const CellRange &range); bool unmergeCells(const QString &range); - bool setRow(int row, double height, const Format &format=Format(), bool hidden=false); - bool setColumn(int colFirst, int colLast, double width, const Format &format=Format(), bool hidden=false); - bool setColumn(const QString &colFirst, const QString &colLast, double width, const Format &format=Format(), bool hidden=false); + + bool setColumnWidth(const CellRange &range, double width); + bool setColumnFormat(const CellRange &range, const Format &format); + bool setColumnHidden(const CellRange &range, bool hidden); + bool setColumnWidth(int column, double width); + bool setColumnFormat(int column, const Format &format); + bool setColumnHidden(int column, bool hidden); + bool setColumnWidth(int colFirst, int colLast, double width); + bool setColumnFormat(int colFirst, int colLast, const Format &format); + bool setColumnHidden(int colFirst, int colLast, bool hidden); + double columnWidth(int column); + Format columnFormat(int column); + bool isColumnHidden(int column); + + bool setRowHeight(int row, double height); + bool setRowFormat(int row, const Format &format); + bool setRowHidden(int row, bool hidden); + bool setRowHeight(int rowFirst, int rowLast, double height); + bool setRowFormat(int rowFirst, int rowLast, const Format &format); + bool setRowHidden(int rowFirst, int rowLast, bool hidden); + + double rowHeight(int row); + Format rowFormat(int row); + bool isRowHidden(int row); + bool groupRows(int rowFirst, int rowLast, bool collapsed = true); bool groupColumns(int colFirst, int colLast, bool collapsed = true); bool addDataValidation(const DataValidation &validation); diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index 1b98fb8..dcab830 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/src/xlsx/xlsxworksheet.cpp @@ -1291,42 +1291,44 @@ void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const if (row_spans.contains(span_index)) span = row_spans[span_index]; - if (cellTable.contains(row_num)) { - writer.writeStartElement(QStringLiteral("row")); - writer.writeAttribute(QStringLiteral("r"), QString::number(row_num)); + writer.writeStartElement(QStringLiteral("row")); + writer.writeAttribute(QStringLiteral("r"), QString::number(row_num)); - if (!span.isEmpty()) - writer.writeAttribute(QStringLiteral("spans"), span); + if (!span.isEmpty()) + writer.writeAttribute(QStringLiteral("spans"), span); - if (rowsInfo.contains(row_num)) { - QSharedPointer rowInfo = rowsInfo[row_num]; - if (!rowInfo->format.isEmpty()) { - writer.writeAttribute(QStringLiteral("s"), QString::number(rowInfo->format.xfIndex())); - writer.writeAttribute(QStringLiteral("customFormat"), QStringLiteral("1")); - } - if (rowInfo->height != 15 && rowInfo->height != 0) { - writer.writeAttribute(QStringLiteral("ht"), QString::number(rowInfo->height)); - writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1")); - } - if (rowInfo->hidden) - writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1")); - if (rowInfo->outlineLevel > 0) - writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(rowInfo->outlineLevel)); - if (rowInfo->collapsed) - writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1")); + if (rowsInfo.contains(row_num)) { + QSharedPointer rowInfo = rowsInfo[row_num]; + if (!rowInfo->format.isEmpty()) { + writer.writeAttribute(QStringLiteral("s"), QString::number(rowInfo->format.xfIndex())); + writer.writeAttribute(QStringLiteral("customFormat"), QStringLiteral("1")); } + //!Todo: support customHeight from info struct + //!Todo: where does this magic number '15' come from? + if (rowInfo->customHeight) { + writer.writeAttribute(QStringLiteral("ht"), QString::number(rowInfo->height)); + writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1")); + } else { + writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("0")); + } + + if (rowInfo->hidden) + writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1")); + if (rowInfo->outlineLevel > 0) + writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(rowInfo->outlineLevel)); + if (rowInfo->collapsed) + writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1")); + } + //Write cell data if row contains filled cells + if (cellTable.contains(row_num)) { for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) { if (cellTable[row_num].contains(col_num)) { saveXmlCellData(writer, row_num, col_num, cellTable[row_num][col_num]); } } - writer.writeEndElement(); //row - } else if (comments.contains(row_num)){ - - } else { - } + writer.writeEndElement(); //row } } @@ -1491,26 +1493,6 @@ void WorksheetPrivate::saveXmlDrawings(QXmlStreamWriter &writer) const writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(relationships->count())); } -/*! - Sets the \a height and \a format of the row \a row. Row height measured in point size. If format - equals 0 then format is ignored. \a row is 1-indexed. - Hides the row if \a hidden is true. - - Returns true if success. - */ -bool Worksheet::setRow(int row, double height, const Format &format, bool hidden) -{ - Q_D(Worksheet); - int min_col = d->dimension.firstColumn() < 1 ? 1 : d->dimension.firstColumn(); - - if (d->checkDimensions(row, min_col, false, true)) - return false; - - d->rowsInfo[row] = QSharedPointer(new XlsxRowInfo(height, format, hidden)); - d->workbook->styles()->addXfFormat(format); - return true; -} - void WorksheetPrivate::splitColsInfo(int colFirst, int colLast) { // Split current columnInfo, for example, if "A:H" has been set, @@ -1553,78 +1535,280 @@ void WorksheetPrivate::splitColsInfo(int colFirst, int colLast) } } -/*! - Sets column \a width and \a format for all columns from \a colFirst to \a 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. Both \a colFirst and \a colLast are all 1-indexed. - Hides the column if \a hidden is true. - - Return true if success. - */ -bool Worksheet::setColumn(int colFirst, int colLast, double width, const Format &format, bool hidden) +bool WorksheetPrivate::isColumnRangeValid(int colFirst, int colLast) { - Q_D(Worksheet); bool ignore_row = true; - bool ignore_col = (format.isValid() || (width && hidden)) ? false : true; + bool ignore_col = false; if (colFirst > colLast) return false; - if (d->checkDimensions(1, colLast, ignore_row, ignore_col)) + if (checkDimensions(1, colLast, ignore_row, ignore_col)) return false; - if (d->checkDimensions(1, colFirst, ignore_row, ignore_col)) + if (checkDimensions(1, colFirst, ignore_row, ignore_col)) return false; - d->splitColsInfo(colFirst, colLast); + return true; +} + +QList WorksheetPrivate ::getColumnIndexes(int colFirst, int colLast) +{ + splitColsInfo(colFirst, colLast); QList nodes; nodes.append(colFirst); for (int col = colFirst; col <= colLast; ++col) { - if (d->colsInfo.contains(col)) { + if (colsInfo.contains(col)) { if (nodes.last() != col) nodes.append(col); - int nextCol = d->colsInfo[col]->lastColumn + 1; + int nextCol = colsInfo[col]->lastColumn + 1; if (nextCol <= colLast) nodes.append(nextCol); } } - for (int idx = 0; idx < nodes.size(); ++idx) { - int colStart = nodes[idx]; - if (d->colsInfo.contains(colStart)) { - QSharedPointer info = d->colsInfo[colStart]; - info->width = width; - info->format = format; - info->hidden = hidden; - } else { - int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1; - QSharedPointer info(new XlsxColumnInfo(colStart, colEnd, width, format, hidden)); - d->colsInfo.insert(colFirst, info); - for (int c = colStart; c <= colEnd; ++c) - d->colsInfoHelper[c] = info; - } - } - d->workbook->styles()->addXfFormat(format); + return nodes; +} - return true; +/*! + Sets width in characters of a range of columns. + Returns true on success. + */ +bool Worksheet::setColumnWidth(const CellRange &range, double width) +{ + int col1 = range.firstColumn(); + int col2 = range.lastColumn(); + if (col1 < 0|| col2 < 0) + return false; + + return setColumnWidth(col1, col2, width); } /*! - 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. \a colFirst and \a colLast should be "A", "B", "C", ... + Sets format property of a range of columns. Columns are 1-indexed. + Returns true on success. */ -bool Worksheet::setColumn(const QString &colFirst, const QString &colLast, double width, const Format &format, bool hidden) +bool Worksheet::setColumnFormat(const CellRange& range, const Format &format) { - int col1 = xl_col_name_to_value(colFirst); - int col2 = xl_col_name_to_value(colLast); + int col1 = range.firstColumn(); + int col2 = range.lastColumn(); + if (col1 < 0|| col2 < 0) + return false; - if (col1 == -1 || col2 == -1) + return setColumnFormat(col1, col2, format); +} + +/*! + Sets hidden property of a range of columns. Columns are 1-indexed. + Hidden columns are not visible. + Returns true on success. + */ +bool Worksheet::setColumnHidden(const CellRange &range, bool hidden) +{ + int col1 = range.firstColumn(); + int col2 = range.lastColumn(); + if (col1 < 0|| col2 < 0) return false; - return setColumn(col1, col2, width, format, hidden); + return setColumnHidden(col1, col2, hidden); +} + +/*! + Sets width in characters of a range of columns. Columns are 1-indexed. + Returns true on success. + */ +bool Worksheet::setColumnWidth(int colFirst, int colLast, double width) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(colFirst, colLast); + foreach(QSharedPointer columnInfo, columnInfoList) { + columnInfo->width = width; + } + + return (columnInfoList.count() > 0); +} + +/*! + Sets format property of a range of columns. Columns are 1-indexed. + */ +bool Worksheet::setColumnFormat(int colFirst, int colLast, const Format &format) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(colFirst, colLast); + foreach(QSharedPointer columnInfo, columnInfoList) { + columnInfo->format = format; + } + + if(columnInfoList.count() > 0) { + d->workbook->styles()->addXfFormat(format); + return true; + } + + return false; +} + +/*! + Sets hidden property of a range of columns. Columns are 1-indexed. + */ +bool Worksheet::setColumnHidden(int colFirst, int colLast, bool hidden) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(colFirst, colLast); + foreach(QSharedPointer columnInfo, columnInfoList) { + columnInfo->hidden = hidden; + } + + return (columnInfoList.count() > 0); +} + +/*! + Returns width of the column in characters of the normal font. Columns are 1-indexed. + */ +double Worksheet::columnWidth(int column) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(column, column); + if (columnInfoList.count() == 1) { + return columnInfoList.at(0)->width ; + } + + return d->sheetFormatProps.defaultColWidth; +} + +/*! + Returns formatting of the column. Columns are 1-indexed. + */ +Format Worksheet::columnFormat(int column) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(column, column); + if (columnInfoList.count() == 1) { + return columnInfoList.at(0)->format; + } + + return Format(); +} + +/*! + Returns true if column is hidden. Columns are 1-indexed. + */ +bool Worksheet::isColumnHidden(int column) +{ + Q_D(Worksheet); + + QList > columnInfoList = d->getColumnInfoList(column, column); + if (columnInfoList.count() == 1) { + return columnInfoList.at(0)->hidden; + } + + return false; +} + +/*! + Sets the \a height of the rows including and between \a rowFirst and \a rowLast. + Row height measured in point size. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Worksheet::setRowHeight(int rowFirst,int rowLast, double height) +{ + Q_D(Worksheet); + + QList > rowInfoList = d->getRowInfoList(rowFirst,rowLast); + + foreach(QSharedPointer rowInfo, rowInfoList) { + rowInfo->height = height; + rowInfo->customHeight = true; + } + + return rowInfoList.count() > 0; +} + +/*! + Sets the \a format of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Worksheet::setRowFormat(int rowFirst,int rowLast, const Format &format) +{ + Q_D(Worksheet); + + QList > rowInfoList = d->getRowInfoList(rowFirst,rowLast); + + foreach(QSharedPointer rowInfo, rowInfoList) { + rowInfo->format = format; + } + + d->workbook->styles()->addXfFormat(format); + return rowInfoList.count() > 0; +} + +/*! + Sets the \a hidden proeprty of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. If hidden is true rows will not be visible. + + Returns true if success. +*/ +bool Worksheet::setRowHidden(int rowFirst,int rowLast, bool hidden) +{ + Q_D(Worksheet); + + QList > rowInfoList = d->getRowInfoList(rowFirst,rowLast); + + foreach(QSharedPointer rowInfo, rowInfoList) { + rowInfo->hidden = hidden; + } + + return rowInfoList.count() > 0; +} + +/*! + Returns height of \a row in points. +*/ +double Worksheet::rowHeight(int row) +{ + Q_D(Worksheet); + int min_col = d->dimension.firstColumn() < 0 ? 0 : d->dimension.firstColumn(); + + if (d->checkDimensions(row, min_col, false, true)) + return d->sheetFormatProps.defaultRowHeight; //return default on invalid row? + + return d->rowsInfo[row]->height; +} + +/*! + Returns format of \a row. +*/ +Format Worksheet::rowFormat(int row) +{ + Q_D(Worksheet); + int min_col = d->dimension.firstColumn() < 0 ? 0 : d->dimension.firstColumn(); + + if (d->checkDimensions(row, min_col, false, true)) + return Format(); //return default on invalid row? + + return d->rowsInfo[row]->format; +} + +/*! + Returns true if \a row is hidden. +*/ +bool Worksheet::isRowHidden(int row) +{ + Q_D(Worksheet); + int min_col = d->dimension.firstColumn() < 0 ? 0 : d->dimension.firstColumn(); + + if (d->checkDimensions(row, min_col, false, true)) + return false; //return default on invalid row? + + return d->rowsInfo[row]->hidden; } /*! @@ -1837,9 +2021,15 @@ void WorksheetPrivate::loadXmlSheetData(QXmlStreamReader &reader) int idx = attributes.value(QLatin1String("s")).toString().toInt(); info->format = workbook->styles()->xfFormat(idx); } - if (attributes.hasAttribute(QLatin1String("customHeight")) && attributes.hasAttribute(QLatin1String("ht"))) { - info->height = attributes.value(QLatin1String("ht")).toString().toDouble(); + + if (attributes.hasAttribute(QLatin1String("customHeight"))) { + info->customHeight = attributes.value(QLatin1String("customHeight")) == QLatin1String("1"); + //Row height is only specified when customHeight is set + if(attributes.hasAttribute(QLatin1String("ht"))) { + info->height = attributes.value(QLatin1String("ht")).toString().toDouble(); + } } + //both "hidden" and "collapsed" default are false info->hidden = attributes.value(QLatin1String("hidden")) == QLatin1String("1"); info->collapsed = attributes.value(QLatin1String("collapsed")) == QLatin1String("1"); @@ -1961,7 +2151,11 @@ void WorksheetPrivate::loadXmlColumnsInfo(QXmlStreamReader &reader) info->firstColumn = min; info->lastColumn = max; - //!Todo, customWidth support. + //Flag indicating that the column width for the affected column(s) is different from the + // default or has been manually set + if(colAttrs.hasAttribute(QLatin1String("customWidth"))) { + info->customWidth = colAttrs.value(QLatin1String("customWidth")) == QLatin1String("1"); + } //Note, node may have "width" without "customWidth" if (colAttrs.hasAttribute(QLatin1String("width"))) { double width = colAttrs.value(QLatin1String("width")).toString().toDouble(); @@ -2060,6 +2254,47 @@ void WorksheetPrivate::loadXmlSheetViews(QXmlStreamReader &reader) } } +void WorksheetPrivate::loadXmlSheetFormatProps(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("sheetFormatPr")); + QXmlStreamAttributes attributes = reader.attributes(); + XlsxSheetFormatProps formatProps; + + //Retain default values + foreach (QXmlStreamAttribute attrib, attributes) { + if(attrib.name() == QLatin1String("baseColWidth") ) { + formatProps.baseColWidth = attrib.value().toString().toInt(); + } else if(attrib.name() == QLatin1String("customHeight")) { + formatProps.customHeight = attrib.value() == QLatin1String("1"); + } else if(attrib.name() == QLatin1String("defaultColWidth")) { + formatProps.defaultColWidth = attrib.value().toString().toDouble(); + } else if(attrib.name() == QLatin1String("defaultRowHeight")) { + formatProps.defaultRowHeight = attrib.value().toString().toDouble(); + } else if(attrib.name() == QLatin1String("outlineLevelCol")) { + formatProps.outlineLevelCol = attrib.value().toString().toInt(); + } else if(attrib.name() == QLatin1String("outlineLevelRow")) { + formatProps.outlineLevelRow = attrib.value().toString().toInt(); + } else if(attrib.name() == QLatin1String("thickBottom")) { + formatProps.thickBottom = attrib.value() == QLatin1String("1"); + } else if(attrib.name() == QLatin1String("thickTop")) { + formatProps.thickTop = attrib.value() == QLatin1String("1"); + } else if(attrib.name() == QLatin1String("zeroHeight")) { + formatProps.zeroHeight = attrib.value() == QLatin1String("1"); + } + } + + if(formatProps.defaultColWidth == 0.0) { //not set + formatProps.defaultColWidth = WorksheetPrivate::calculateColWidth(formatProps.baseColWidth); + } + +} +double WorksheetPrivate::calculateColWidth(int characters) +{ + //!Todo + //Take normal style' font maximum width and add padding and margin pixels + return characters + 0.5; +} + void WorksheetPrivate::loadXmlHyperlinks(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("hyperlinks")); @@ -2090,6 +2325,52 @@ void WorksheetPrivate::loadXmlHyperlinks(QXmlStreamReader &reader) } } +QList > WorksheetPrivate::getColumnInfoList(int colFirst, int colLast) +{ + QList > columnsInfoList; + if(isColumnRangeValid(colFirst,colLast)) + { + QList nodes = getColumnIndexes(colFirst, colLast); + + for (int idx = 0; idx < nodes.size(); ++idx) { + int colStart = nodes[idx]; + if (colsInfo.contains(colStart)) { + QSharedPointer info = colsInfo[colStart]; + columnsInfoList.append(info); + } else { + int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1; + QSharedPointer info(new XlsxColumnInfo(colStart, colEnd)); + colsInfo.insert(colFirst, info); + columnsInfoList.append(info); + for (int c = colStart; c <= colEnd; ++c) + colsInfoHelper[c] = info; + } + } + } + + return columnsInfoList; +} + +QList > WorksheetPrivate::getRowInfoList(int rowFirst, int rowLast) +{ + QList > rowInfoList; + + int min_col = dimension.firstColumn() < 0 ? 0 : dimension.firstColumn(); + + for(int row = rowFirst; row <= rowLast; ++row) { + if (checkDimensions(row, min_col, false, true)) + continue; + + QSharedPointer rowInfo; + if ((rowsInfo[row]).isNull()){ + rowsInfo[row] = QSharedPointer(new XlsxRowInfo()); + } + rowInfoList.append(rowsInfo[row]); + } + + return rowInfoList; +} + bool Worksheet::loadFromXmlFile(QIODevice *device) { Q_D(Worksheet); @@ -2097,7 +2378,7 @@ bool Worksheet::loadFromXmlFile(QIODevice *device) QXmlStreamReader reader(device); while (!reader.atEnd()) { reader.readNextStartElement(); - if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("dimension")) { QXmlStreamAttributes attributes = reader.attributes(); QString range = attributes.value(QLatin1String("ref")).toString(); @@ -2105,7 +2386,7 @@ bool Worksheet::loadFromXmlFile(QIODevice *device) } else if (reader.name() == QLatin1String("sheetViews")) { d->loadXmlSheetViews(reader); } else if (reader.name() == QLatin1String("sheetFormatPr")) { - + d->loadXmlSheetFormatProps(reader); } else if (reader.name() == QLatin1String("cols")) { d->loadXmlColumnsInfo(reader); } else if (reader.name() == QLatin1String("sheetData")) { diff --git a/src/xlsx/xlsxworksheet.h b/src/xlsx/xlsxworksheet.h index 59a04d6..8f92a5b 100755 --- a/src/xlsx/xlsxworksheet.h +++ b/src/xlsx/xlsxworksheet.h @@ -99,9 +99,24 @@ public: bool unmergeCells(const CellRange &range); QList mergedCells() const; - bool setRow(int row, double height, const Format &format=Format(), bool hidden=false); - bool setColumn(int colFirst, int colLast, double width, const Format &format=Format(), bool hidden=false); - bool setColumn(const QString &colFirst, const QString &colLast, double width, const Format &format=Format(), bool hidden=false); + bool setColumnWidth(const CellRange& range, double width); + bool setColumnFormat(const CellRange& range, const Format &format); + bool setColumnHidden(const CellRange& range, bool hidden); + bool setColumnWidth(int colFirst, int colLast, double width); + bool setColumnFormat(int colFirst, int colLast, const Format &format); + bool setColumnHidden(int colFirst, int colLast, bool hidden); + double columnWidth(int column); + Format columnFormat(int column); + bool isColumnHidden(int column); + + bool setRowHeight(int rowFirst,int rowLast, double height); + bool setRowFormat(int rowFirst,int rowLast, const Format &format); + bool setRowHidden(int rowFirst,int rowLast, bool hidden); + + double rowHeight(int row); + Format rowFormat(int row); + bool isRowHidden(int row); + bool groupRows(int rowFirst, int rowLast, bool collapsed = true); bool groupColumns(int colFirst, int colLast, bool collapsed = true); bool groupColumns(const QString &colFirst, const QString &colLast, bool collapsed = true); @@ -129,6 +144,8 @@ public: void setWhiteSpaceVisible(bool visible); ~Worksheet(); + + private: friend class DocumentPrivate; friend class Workbook; diff --git a/src/xlsx/xlsxworksheet_p.h b/src/xlsx/xlsxworksheet_p.h index 1817ee3..69655fb 100644 --- a/src/xlsx/xlsxworksheet_p.h +++ b/src/xlsx/xlsxworksheet_p.h @@ -79,15 +79,50 @@ struct XlsxHyperlinkData QString tooltip; }; +// ECMA-376 Part1 18.3.1.81 +struct XlsxSheetFormatProps +{ + XlsxSheetFormatProps(int baseColWidth = 8, + bool customHeight = false, + double defaultColWidth = 0.0, + double defaultRowHeight = 15, + quint8 outlineLevelCol = 0, + quint8 outlineLevelRow = 0, + bool thickBottom = false, + bool thickTop = false, + bool zeroHeight = false) : + baseColWidth(baseColWidth), + customHeight(customHeight), + defaultColWidth(defaultColWidth), + defaultRowHeight(defaultRowHeight), + outlineLevelCol(outlineLevelCol), + outlineLevelRow(outlineLevelRow), + thickBottom(thickBottom), + thickTop(thickTop), + zeroHeight(zeroHeight) { + } + + int baseColWidth; + bool customHeight; + double defaultColWidth; + double defaultRowHeight; + quint8 outlineLevelCol; + quint8 outlineLevelRow; + bool thickBottom; + bool thickTop; + bool zeroHeight; +}; + struct XlsxRowInfo { XlsxRowInfo(double height=0, const Format &format=Format(), bool hidden=false) : - height(height), format(format), hidden(hidden), outlineLevel(0) + customHeight(false), height(height), format(format), hidden(hidden), outlineLevel(0) , collapsed(false) { } + bool customHeight; double height; Format format; bool hidden; @@ -98,14 +133,15 @@ struct XlsxRowInfo struct XlsxColumnInfo { XlsxColumnInfo(int firstColumn=0, int lastColumn=1, double width=0, const Format &format=Format(), bool hidden=false) : - firstColumn(firstColumn), lastColumn(lastColumn), width(width), format(format), hidden(hidden) + firstColumn(firstColumn), lastColumn(lastColumn), customWidth(false), width(width), format(format), hidden(hidden) , outlineLevel(0), collapsed(false) { } int firstColumn; int lastColumn; - double width; + bool customWidth; + double width; Format format; bool hidden; int outlineLevel; @@ -138,9 +174,15 @@ public: void loadXmlColumnsInfo(QXmlStreamReader &reader); void loadXmlMergeCells(QXmlStreamReader &reader); void loadXmlDataValidations(QXmlStreamReader &reader); + void loadXmlSheetFormatProps(QXmlStreamReader &reader); void loadXmlSheetViews(QXmlStreamReader &reader); void loadXmlHyperlinks(QXmlStreamReader &reader); + QList > getRowInfoList(int rowFirst, int rowLast); + QList > getColumnInfoList(int colFirst, int colLast); + QList getColumnIndexes(int colFirst, int colLast); + bool isColumnRangeValid(int colFirst, int colLast); + SharedStrings *sharedStrings() const; QMap > > cellTable; @@ -167,6 +209,8 @@ public: int default_row_height; bool default_row_zeroed; + XlsxSheetFormatProps sheetFormatProps; + bool windowProtection; bool showFormulas; bool showGridLines; @@ -179,6 +223,8 @@ public: bool showWhiteSpace; QRegularExpression urlPattern; +private: + static double calculateColWidth(int characters); }; } diff --git a/tests/auto/worksheet/tst_worksheet.cpp b/tests/auto/worksheet/tst_worksheet.cpp index 0f8cdae..e6aa54c 100644 --- a/tests/auto/worksheet/tst_worksheet.cpp +++ b/tests/auto/worksheet/tst_worksheet.cpp @@ -82,10 +82,10 @@ void WorksheetTest::testSheetView() void WorksheetTest::testSetColumn() { QXlsx::Worksheet sheet("", 1, 0, QXlsx::Worksheet::F_NewFromScratch); - sheet.setColumn(1, 11, 20.0); //"A:K" - sheet.setColumn(4, 8, 10.0); //"D:H" - sheet.setColumn(6, 6, 15.0); //"F:F" - sheet.setColumn(1, 9, 8.8); //"A:H" + sheet.setColumnWidth(1, 11, 20.0); //"A:K" + sheet.setColumnWidth(4, 8, 10.0); //"D:H" + sheet.setColumnWidth(6, 6, 15.0); //"F:F" + sheet.setColumnWidth(1, 9, 8.8); //"A:H" QByteArray xmldata = sheet.saveToXmlData();