From 2273a967a978cbfef3602b554361655648ae27f3 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Sat, 23 Nov 2013 21:45:54 +0800 Subject: [PATCH] Add internal support for dxf format test needed. --- src/xlsx/xlsxformat.cpp | 25 +- src/xlsx/xlsxformat.h | 5 +- src/xlsx/xlsxstyles.cpp | 607 ++++++++++++++++----------- src/xlsx/xlsxstyles_p.h | 18 +- src/xlsx/xlsxworksheet.cpp | 26 +- tests/auto/styles/tst_stylestest.cpp | 18 +- 6 files changed, 418 insertions(+), 281 deletions(-) diff --git a/src/xlsx/xlsxformat.cpp b/src/xlsx/xlsxformat.cpp index 5455890..c88ec81 100755 --- a/src/xlsx/xlsxformat.cpp +++ b/src/xlsx/xlsxformat.cpp @@ -283,6 +283,16 @@ void Format::setNumberFormat(int id, const QString &format) setProperty(FormatPrivate::P_NumFmt_FormatCode, format); } +/*! + \internal + Called by styles to fix the numFmt + */ +void Format::fixNumberFormat(int id, const QString &format) +{ + setProperty(FormatPrivate::P_NumFmt_Id, id, false); + setProperty(FormatPrivate::P_NumFmt_FormatCode, format, false); +} + /*! \internal Return true if the format has number format. @@ -1170,13 +1180,6 @@ bool Format::operator !=(const Format &format) const return this->formatKey() != format.formatKey(); } -bool Format::isDxfFormat() const -{ - if (!d) - return false; - return d->is_dxf_fomat; -} - int Format::theme() const { return d->theme; @@ -1195,7 +1198,7 @@ QVariant Format::property(int propertyId) const /*! * \internal */ -void Format::setProperty(int propertyId, const QVariant &value) +void Format::setProperty(int propertyId, const QVariant &value, bool detach) { if (!d) d = new FormatPrivate; @@ -1203,12 +1206,14 @@ void Format::setProperty(int propertyId, const QVariant &value) if (value.isValid()) { if (d->property.contains(propertyId) && d->property[propertyId] == value) return; - d.detach(); + if (detach) + d.detach(); d->property[propertyId] = value; } else { if (!d->property.contains(propertyId)) return; - d.detach(); + if (detach) + d.detach(); d->property.remove(propertyId); } diff --git a/src/xlsx/xlsxformat.h b/src/xlsx/xlsxformat.h index 843a0f0..2aed024 100755 --- a/src/xlsx/xlsxformat.h +++ b/src/xlsx/xlsxformat.h @@ -220,7 +220,7 @@ public: bool operator != (const Format &format) const; QVariant property(int propertyId) const; - void setProperty(int propertyId, const QVariant &value); + void setProperty(int propertyId, const QVariant &value, bool detach=true); void clearProperty(int propertyId); bool hasProperty(int propertyId) const; @@ -239,6 +239,8 @@ private: friend class ::FormatTest; friend Q_XLSX_EXPORT QDebug operator<<(QDebug, const Format &f); + void fixNumberFormat(int id, const QString &format); + bool fontIndexValid() const; int fontIndex() const; void setFontIndex(int index); @@ -265,7 +267,6 @@ private: bool xfIndexValid() const; int xfIndex() const; void setXfIndex(int index); - bool isDxfFormat() const; bool dxfIndexValid() const; int dxfIndex() const; void setDxfIndex(int index); diff --git a/src/xlsx/xlsxstyles.cpp b/src/xlsx/xlsxstyles.cpp index d072f62..6328e78 100755 --- a/src/xlsx/xlsxstyles.cpp +++ b/src/xlsx/xlsxstyles.cpp @@ -48,7 +48,7 @@ Styles::Styles(bool createEmpty) if (!createEmpty) { //Add default Format Format defaultFmt; - addFormat(defaultFmt); + addXfFormat(defaultFmt); //Add another fill format Format fillFmt; @@ -70,72 +70,74 @@ Format Styles::xfFormat(int idx) const return m_xf_formatsList[idx]; } -/* - Assign index to Font/Fill/Border and Format +Format Styles::dxfFormat(int idx) const +{ + if (idx <0 || idx >= m_dxf_formatsList.size()) + return Format(); - When \a force is true, add the format to the format list, even other format has - the same key have been in. - This is useful when reading existing .xlsx files which may contains duplicated formats. -*/ -void Styles::addFormat(const Format &format, bool force) + return m_dxf_formatsList[idx]; +} + +void Styles::fixNumFmt(const Format &format) { - if (format.isEmpty()) { - //Try do something for empty Format. - if (m_emptyFormatAdded) - return; - m_emptyFormatAdded = true; + if (!format.hasNumFmtData()) + return; + + if (format.hasProperty(FormatPrivate::P_NumFmt_Id) + && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty()) { + return; } - //numFmt - if (format.hasNumFmtData() && !format.hasProperty(FormatPrivate::P_NumFmt_Id)) { - if (m_builtinNumFmtsHash.isEmpty()) { - m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0); - m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1); - m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2); - m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3); - m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4); + if (m_builtinNumFmtsHash.isEmpty()) { + m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0); + m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1); + m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2); + m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3); + m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8); - m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9); - m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10); - m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11); - m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12); - m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?" - m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14); - m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15); - m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16); - m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17); - m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18); - m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19); - m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20); - m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21); - m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22); - - m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37); - m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38); - m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39); - m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40); + m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9); + m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10); + m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11); + m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12); + m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?" + m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14); + m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15); + m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16); + m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17); + m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18); + m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19); + m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20); + m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21); + m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22); + + m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37); + m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38); + m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39); + m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40); // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41); // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42); // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43); // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44); - m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45); - m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46); - m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47); - m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48); - m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49); - } - const QString str = format.numberFormat(); + m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45); + m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46); + m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47); + m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48); + m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49); + } + + const QString str = format.numberFormat(); + if (!str.isEmpty()) { //Assign proper number format index if (m_builtinNumFmtsHash.contains(str)) { - const_cast(&format)->setNumberFormat(m_builtinNumFmtsHash[str], str); + const_cast(&format)->fixNumberFormat(m_builtinNumFmtsHash[str], str); } else if (m_customNumFmtsHash.contains(str)) { - const_cast(&format)->setNumberFormat(m_customNumFmtsHash[str]->formatIndex, str); + const_cast(&format)->fixNumberFormat(m_customNumFmtsHash[str]->formatIndex, str); } else { //Assign a new fmt Id. - const_cast(&format)->setNumberFormat(m_nextCustomNumFmtId, str); + const_cast(&format)->fixNumberFormat(m_nextCustomNumFmtId, str); QSharedPointer fmt(new XlsxFormatNumberData); fmt->formatIndex = m_nextCustomNumFmtId; @@ -145,8 +147,50 @@ void Styles::addFormat(const Format &format, bool force) m_nextCustomNumFmtId += 1; } + } else { + int id = format.numberFormatIndex(); + //Assign proper format code, this is needed by dxf format + if (m_customNumFmtIdMap.contains(id)) { + const_cast(&format)->fixNumberFormat(id, m_customNumFmtIdMap[id]->formatString); + } else { + QHashIterator it(m_builtinNumFmtsHash); + bool find=false; + while(it.hasNext()) { + it.next(); + if (it.value() == id) + const_cast(&format)->fixNumberFormat(id, it.key()); + find = true; + break; + } + + if (!find) { + //Wrong numFmt + const_cast(&format)->fixNumberFormat(id, QStringLiteral("General")); + } + } + } +} + +/* + Assign index to Font/Fill/Border and Format + + When \a force is true, add the format to the format list, even other format has + the same key have been in. + This is useful when reading existing .xlsx files which may contains duplicated formats. +*/ +void Styles::addXfFormat(const Format &format, bool force) +{ + if (format.isEmpty()) { + //Try do something for empty Format. + if (m_emptyFormatAdded) + return; + m_emptyFormatAdded = true; } + //numFmt + if (format.hasNumFmtData() && !format.hasProperty(FormatPrivate::P_NumFmt_Id)) + fixNumFmt(format); + //Font if (format.hasFontData() && !format.fontIndexValid()) { //Assign proper font index, if has font data. @@ -190,17 +234,6 @@ void Styles::addFormat(const Format &format, bool force) } //Format -// if (format.isDxfFormat()) { -// if (!format.dxfIndexValid()) { -// if (!m_dxf_formatsHash.contains(format.formatKey())) { -// const_cast(&format)->setDxfIndex(m_dxf_formatsList.size()); -// m_dxf_formatsList.append(format); -// m_dxf_formatsHash[format.formatKey()] = format; -// } else { -// const_cast(&format)->setDxfIndex(m_dxf_formatsHash[format.formatKey()].dxfIndex()); -// } -// } -// } else { if (!format.isEmpty() && !format.xfIndexValid()) { if (m_xf_formatsHash.contains(format.formatKey())) const_cast(&format)->setXfIndex(m_xf_formatsHash[format.formatKey()].xfIndex()); @@ -211,7 +244,24 @@ void Styles::addFormat(const Format &format, bool force) m_xf_formatsList.append(format); m_xf_formatsHash[format.formatKey()] = format; } -// } +} + +void Styles::addDxfFormat(const Format &format, bool force) +{ + //numFmt + if (format.hasNumFmtData()) + fixNumFmt(format); + + if (!format.isEmpty() && !format.dxfIndexValid()) { + if (m_dxf_formatsHash.contains(format.formatKey())) + const_cast(&format)->setDxfIndex(m_dxf_formatsHash[format.formatKey()].dxfIndex()); + else + const_cast(&format)->setDxfIndex(m_dxf_formatsList.size()); + } + if (!m_dxf_formatsHash.contains(format.formatKey()) || force) { + m_dxf_formatsList.append(format); + m_dxf_formatsHash[format.formatKey()] = format; + } } QByteArray Styles::saveToXmlData() @@ -289,66 +339,83 @@ void Styles::writeNumFmts(XmlStreamWriter &writer) } /* - not consider dxf format. */ void Styles::writeFonts(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("fonts")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count())); - for (int i=0; i patternStrings; if (patternStrings.isEmpty()) { @@ -451,37 +502,44 @@ void Styles::writeBorders(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("borders")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count())); - for (int i=0; isharedStrings()->addSharedString(value); Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); QSharedPointer cell = QSharedPointer(new Cell(QString(), Cell::String, fmt, this)); cell->d_ptr->richString = value; d->cellTable[row][column] = cell; @@ -613,7 +613,7 @@ int Worksheet::writeString(int row, int column, const QString &value, const Form d->sharedStrings()->addSharedString(content); Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); d->cellTable[row][column] = QSharedPointer(new Cell(content, Cell::String, fmt, this)); return error; } @@ -648,7 +648,7 @@ int Worksheet::writeInlineString(int row, int column, const QString &value, cons } Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); d->cellTable[row][column] = QSharedPointer(new Cell(value, Cell::InlineString, fmt, this)); return error; } @@ -676,7 +676,7 @@ int Worksheet::writeNumeric(int row, int column, double value, const Format &for return -1; Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); d->cellTable[row][column] = QSharedPointer(new Cell(value, Cell::Numeric, fmt, this)); return 0; } @@ -710,7 +710,7 @@ int Worksheet::writeFormula(int row, int column, const QString &formula, const F _formula.remove(0,1); Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); Cell *data = new Cell(result, Cell::Formula, fmt, this); data->d_ptr->formula = _formula; d->cellTable[row][column] = QSharedPointer(data); @@ -740,7 +740,7 @@ int Worksheet::writeArrayFormula(const CellRange &range, const QString &formula, for (int row=range.firstRow(); row<=range.lastRow(); ++row) { for (int column=range.firstColumn(); column<=range.lastColumn(); ++column) { Format _format = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(_format); + d->workbook->styles()->addXfFormat(_format); if (row == range.firstRow() && column == range.firstColumn()) { QSharedPointer data(new Cell(0, Cell::ArrayFormula, _format, this)); data->d_ptr->formula = _formula; @@ -786,7 +786,7 @@ int Worksheet::writeBlank(int row, int column, const Format &format) return -1; Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); d->cellTable[row][column] = QSharedPointer(new Cell(QVariant(), Cell::Blank, fmt, this)); @@ -815,7 +815,7 @@ int Worksheet::writeBool(int row, int column, bool value, const Format &format) return -1; Format fmt = format.isValid() ? format : d->cellFormat(row, column); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); d->cellTable[row][column] = QSharedPointer(new Cell(value, Cell::Boolean, fmt, this)); return 0; @@ -845,7 +845,7 @@ int Worksheet::writeDateTime(int row, int column, const QDateTime &dt, const For Format fmt = format; if (!fmt.isValid()) fmt.setNumberFormat(d->workbook->defaultDateFormat()); - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); double value = datetimeToNumber(dt, d->workbook->isDate1904()); @@ -909,7 +909,7 @@ int Worksheet::writeHyperlink(int row, int column, const QUrl &url, const Format fmt.setFontColor(Qt::blue); fmt.setFontUnderline(Format::FontUnderlineSingle); } - d->workbook->styles()->addFormat(fmt); + d->workbook->styles()->addXfFormat(fmt); //Write the hyperlink string as normal string. d->sharedStrings()->addSharedString(displayString); @@ -955,7 +955,7 @@ int Worksheet::mergeCells(const CellRange &range, const Format &format) return -1; if (format.isValid()) - d->workbook->styles()->addFormat(format); + d->workbook->styles()->addXfFormat(format); for (int row = range.firstRow(); row <= range.lastRow(); ++row) { for (int col = range.firstColumn(); col <= range.lastColumn(); ++col) { @@ -1415,7 +1415,7 @@ bool Worksheet::setRow(int row, double height, const Format &format, bool hidden return false; d->rowsInfo[row] = QSharedPointer(new XlsxRowInfo(height, format, hidden)); - d->workbook->styles()->addFormat(format); + d->workbook->styles()->addXfFormat(format); return true; } @@ -1510,7 +1510,7 @@ bool Worksheet::setColumn(int colFirst, int colLast, double width, const Format d->colsInfoHelper[c] = info; } } - d->workbook->styles()->addFormat(format); + d->workbook->styles()->addXfFormat(format); return true; } diff --git a/tests/auto/styles/tst_stylestest.cpp b/tests/auto/styles/tst_stylestest.cpp index 2ff69bc..a6e964b 100644 --- a/tests/auto/styles/tst_stylestest.cpp +++ b/tests/auto/styles/tst_stylestest.cpp @@ -14,8 +14,8 @@ public: private Q_SLOTS: void testEmptyStyle(); - void testAddFormat(); - void testAddFormat2(); + void testAddXfFormat(); + void testAddXfFormat2(); void testSolidFillBackgroundColor(); void testWriteBorders(); @@ -39,33 +39,33 @@ void StylesTest::testEmptyStyle() QVERIFY2(xmlData.contains(""), "Must have one cell style"); } -void StylesTest::testAddFormat() +void StylesTest::testAddXfFormat() { QXlsx::Styles styles; for (int i=0; i<10; ++i) { QXlsx::Format format; format.setFontBold(true); - styles.addFormat(format); + styles.addXfFormat(format); } QByteArray xmlData = styles.saveToXmlData(); QVERIFY2(xmlData.contains(""), ""); //Note we have a default one } -void StylesTest::testAddFormat2() +void StylesTest::testAddXfFormat2() { QXlsx::Styles styles; QXlsx::Format format; format.setNumberFormat("h:mm:ss AM/PM"); //builtin 19 - styles.addFormat(format); + styles.addXfFormat(format); QCOMPARE(format.numberFormatIndex(), 19); QXlsx::Format format2; format2.setNumberFormat("aaaaa h:mm:ss AM/PM"); //custom - styles.addFormat(format2); + styles.addXfFormat(format2); QCOMPARE(format2.numberFormatIndex(), 176); } @@ -76,7 +76,7 @@ void StylesTest::testSolidFillBackgroundColor() QXlsx::Styles styles; QXlsx::Format format; format.setPatternBackgroundColor(QColor(Qt::red)); - styles.addFormat(format); + styles.addXfFormat(format); QByteArray xmlData = styles.saveToXmlData(); @@ -88,7 +88,7 @@ void StylesTest::testWriteBorders() QXlsx::Styles styles; QXlsx::Format format; format.setRightBorderStyle(QXlsx::Format::BorderThin); - styles.addFormat(format); + styles.addXfFormat(format); QByteArray xmlData = styles.saveToXmlData();