diff --git a/src/xlsx/xlsxdocument.cpp b/src/xlsx/xlsxdocument.cpp index 88720bc..de0ab60 100644 --- a/src/xlsx/xlsxdocument.cpp +++ b/src/xlsx/xlsxdocument.cpp @@ -63,7 +63,7 @@ Document::Document(QIODevice *device, QObject *parent) : Format *Document::createFormat() { Q_D(Document); - return d->workbook->addFormat(); + return d->workbook->createFormat(); } int Document::write(const QString row_column, const QVariant &value, Format *format) diff --git a/src/xlsx/xlsxformat.cpp b/src/xlsx/xlsxformat.cpp index df89df4..33c838d 100755 --- a/src/xlsx/xlsxformat.cpp +++ b/src/xlsx/xlsxformat.cpp @@ -29,9 +29,6 @@ namespace QXlsx { -QList FormatPrivate::s_xfFormats; -QList FormatPrivate::s_dxfFormats; - FormatPrivate::FormatPrivate(Format *p) : q_ptr(p) { @@ -40,6 +37,8 @@ FormatPrivate::FormatPrivate(Format *p) : is_dxf_fomat = false; xf_index = -1; dxf_index = -1; + xf_indexValid = false; + dxf_indexValid = false; theme = 0; color_indexed = 0; @@ -186,16 +185,10 @@ void Format::setFontName(const QString &name) d->fontData._dirty = true; } -bool Format::hasFont() const +bool Format::fontIndexValid() const { Q_D(const Format); - return !d->fontData._redundant; -} - -void Format::setFontRedundant(bool redundant) -{ - Q_D(Format); - d->fontData._redundant = redundant; + return !d->fontData._dirty && d->fontData._indexValid; } int Format::fontIndex() const @@ -208,6 +201,7 @@ void Format::setFontIndex(int index) { Q_D(Format); d->fontData._index = index; + d->fontData._indexValid = true; } int Format::fontFamily() const @@ -243,6 +237,7 @@ QByteArray Format::fontKey() const const_cast(d)->fontData._key = key; const_cast(d)->fontData._dirty = false; + const_cast(d)->fontData._indexValid = false; //must re-assign a new index const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } @@ -579,16 +574,10 @@ void Format::setDiagonalBorderColor(const QColor &color) d->borderData._dirty = true; } -bool Format::hasBorders() const +bool Format::borderIndexValid() const { Q_D(const Format); - return !d->borderData._redundant; -} - -void Format::setBorderRedundant(bool redundant) -{ - Q_D(Format); - d->borderData._redundant = redundant; + return !d->borderData._dirty && d->borderData._indexValid; } int Format::borderIndex() const @@ -601,6 +590,7 @@ void Format::setBorderIndex(int index) { Q_D(Format); d->borderData._index = index; + d->borderData._indexValid = true; } /* Internal @@ -618,6 +608,7 @@ QByteArray Format::borderKey() const <borderData.top<borderData.topColor; const_cast(d)->borderData._key = key; const_cast(d)->borderData._dirty = false; + const_cast(d)->borderData._indexValid = false; const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } @@ -667,16 +658,10 @@ void Format::setPatternBackgroundColor(const QColor &color) d->fillData._dirty = true; } -bool Format::hasFill() const +bool Format::fillIndexValid() const { Q_D(const Format); - return !d->fillData._redundant; -} - -void Format::setFillRedundant(bool redundant) -{ - Q_D(Format); - d->fillData._redundant = redundant; + return !d->fillData._dirty && d->fillData._indexValid; } int Format::fillIndex() const @@ -689,6 +674,7 @@ void Format::setFillIndex(int index) { Q_D(Format); d->fillData._index = index; + d->fillData._indexValid = true; } /* Internal @@ -702,6 +688,7 @@ QByteArray Format::fillKey() const stream<fillData.bgColor<fillData.fgColor<fillData.pattern; const_cast(d)->fillData._key = key; const_cast(d)->fillData._dirty = false; + const_cast(d)->fillData._indexValid = false; const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } @@ -747,83 +734,77 @@ QByteArray Format::formatKey() const <protectionData.hidden<protectionData.locked; const_cast(d)->formatKey = key; const_cast(d)->dirty = false; + const_cast(d)->xf_indexValid = false; + const_cast(d)->dxf_indexValid = false; } return d->formatKey; } -bool Format::operator ==(const Format &format) const +void Format::setXfIndex(int index) { - return this->formatKey() == format.formatKey(); + Q_D(Format); + d->xf_index = index; + d->xf_indexValid = true; } -bool Format::operator !=(const Format &format) const +int Format::xfIndex() const { - return this->formatKey() != format.formatKey(); + Q_D(const Format); + return d->xf_index; } -/* Internal - * - * This function will be called when wirte the cell contents of worksheet to xml files. - * Depending on the order of the Format used instead of the Format created, we assign a - * index to it. - */ -int Format::xfIndex(bool generateIfNotValid) -{ - Q_D(Format); - if (d->xf_index == -1 && generateIfNotValid) { //Generate a valid xf_index for this format - int index = -1; - for (int i=0; is_xfFormats.size(); ++i) { - if (*d->s_xfFormats[i] == *this) { - index = i; - break; - } - } - if (index != -1) { - d->xf_index = index; - } else { - d->xf_index = d->s_xfFormats.size(); - d->s_xfFormats.append(this); - } - } - return d->xf_index; +bool Format::xfIndexValid() const +{ + Q_D(const Format); + return !d->dirty && d->xf_indexValid; } -void Format::clearExtraInfos() +void Format::setDxfIndex(int index) { Q_D(Format); - d->xf_index = -1; - d->dxf_index = -1; - d->s_xfFormats.clear(); - d->s_dxfFormats.clear(); + d->dxf_index = index; + d->dxf_indexValid = true; } -bool Format::isDxfFormat() const +int Format::dxfIndex() const { Q_D(const Format); - return d->is_dxf_fomat; + return d->dxf_index; } -int Format::theme() const +bool Format::dxfIndexValid() const { Q_D(const Format); - return d->theme; + return !d->dirty && d->dxf_indexValid; } -int Format::colorIndexed() const +bool Format::operator ==(const Format &format) const +{ + return this->formatKey() == format.formatKey(); +} + +bool Format::operator !=(const Format &format) const +{ + return this->formatKey() != format.formatKey(); +} + +bool Format::isDxfFormat() const { Q_D(const Format); - return d->color_indexed; + return d->is_dxf_fomat; } -QList Format::xfFormats() +int Format::theme() const { - return FormatPrivate::s_xfFormats; + Q_D(const Format); + return d->theme; } -QList Format::dxfFormats() +int Format::colorIndexed() const { - return FormatPrivate::s_dxfFormats; + Q_D(const Format); + return d->color_indexed; } } // namespace QXlsx diff --git a/src/xlsx/xlsxformat.h b/src/xlsx/xlsxformat.h index e1af588..1d3ec32 100755 --- a/src/xlsx/xlsxformat.h +++ b/src/xlsx/xlsxformat.h @@ -210,8 +210,7 @@ private: friend class WorksheetPrivate; Format(); - bool hasFont() const; - void setFontRedundant(bool redundant); + bool fontIndexValid() const; int fontIndex() const; void setFontIndex(int index); QByteArray fontKey() const; @@ -223,26 +222,24 @@ private: QString horizontalAlignmentString() const; QString verticalAlignmentString() const; + bool borderIndexValid() const; QByteArray borderKey() const; - bool hasBorders() const; - void setBorderRedundant(bool redundant); int borderIndex() const; void setBorderIndex(int index); + bool fillIndexValid() const; QByteArray fillKey() const; - bool hasFill() const; - void setFillRedundant(bool redundant); int fillIndex() const; void setFillIndex(int index); QByteArray formatKey() const; - - static QList xfFormats(); - static QList dxfFormats(); - int xfIndex(bool generateIfNotValid=true); //Generate index when first called. - void clearExtraInfos(); - + bool xfIndexValid() const; + int xfIndex() const; + void setXfIndex(int index); bool isDxfFormat() const; + bool dxfIndexValid() const; + int dxfIndex() const; + void setDxfIndex(int index); int theme() const; int colorIndexed() const; diff --git a/src/xlsx/xlsxformat_p.h b/src/xlsx/xlsxformat_p.h index 9c38e21..3adb919 100644 --- a/src/xlsx/xlsxformat_p.h +++ b/src/xlsx/xlsxformat_p.h @@ -42,7 +42,7 @@ struct FontData , scirpt(Format::FontScriptNormal), underline(Format::FontUnderlineNone) , outline(false), shadow(false), name(QStringLiteral("Calibri")), family(2), charset(0) , scheme(QStringLiteral("minor")), condense(0), extend(0) - , _dirty(true), _redundant(false), _index(-1) + , _dirty(true), _indexValid(false), _index(-1) {} @@ -65,7 +65,7 @@ struct FontData //helper member bool _dirty; //key re-generated is need. QByteArray _key; - bool _redundant; //same font already used by some other Formats + bool _indexValid; //has a valid index, so no need to assign a new one int _index; //index in the Font list }; @@ -90,7 +90,7 @@ struct BorderData left(Format::BorderNone), right(Format::BorderNone), top(Format::BorderNone) ,bottom(Format::BorderNone), diagonal(Format::BorderNone) ,diagonalType(Format::DiagonalBorderNone) - ,_dirty(true), _redundant(false), _index(-1) + ,_dirty(true), _indexValid(false), _index(-1) {} Format::BorderStyle left; @@ -108,14 +108,14 @@ struct BorderData //helper member bool _dirty; //key re-generated is need. QByteArray _key; - bool _redundant; //same border already used by some other Formats + bool _indexValid; //has a valid index, so no need to assign a new one int _index; //index in the border list }; struct FillData { FillData() : pattern(Format::PatternNone) - ,_dirty(true), _redundant(false), _index(-1) + ,_dirty(true), _indexValid(false), _index(-1) {} Format::FillPattern pattern; @@ -125,7 +125,7 @@ struct FillData { //helper member bool _dirty; //key re-generated is need. QByteArray _key; - bool _redundant; //same border already used by some other Formats + bool _indexValid; //has a valid index, so no need to assign a new one int _index; //index in the border list }; @@ -156,10 +156,12 @@ public: static QList s_xfFormats; int xf_index; + bool xf_indexValid; static QList s_dxfFormats; bool is_dxf_fomat; int dxf_index; + bool dxf_indexValid; int theme; int color_indexed; diff --git a/src/xlsx/xlsxpackage.cpp b/src/xlsx/xlsxpackage.cpp index 6958c2c..b0d278f 100644 --- a/src/xlsx/xlsxpackage.cpp +++ b/src/xlsx/xlsxpackage.cpp @@ -143,7 +143,6 @@ bool Package::createPackage(QIODevice *package) if (zipWriter.error()) return false; - m_workbook->styles()->clearExtraFormatInfo(); //These info will be generated when write the worksheet data. m_workbook->prepareDrawings(); writeWorksheetFiles(zipWriter); @@ -158,7 +157,6 @@ bool Package::createPackage(QIODevice *package) writeDocPropsAppFile(zipWriter); writeDocPropsCoreFile(zipWriter); writeContentTypesFile(zipWriter); - m_workbook->styles()->prepareStyles(); writeStylesFiles(zipWriter); writeThemeFile(zipWriter); writeRootRelsFile(zipWriter); @@ -280,11 +278,7 @@ void Package::writeSharedStringsFile(ZipWriter &zipWriter) void Package::writeStylesFiles(ZipWriter &zipWriter) { - QByteArray data; - QBuffer buffer(&data); - buffer.open(QIODevice::WriteOnly); - m_workbook->styles()->saveToXmlFile(&buffer); - zipWriter.addFile(QStringLiteral("xl/styles.xml"), data); + zipWriter.addFile(QStringLiteral("xl/styles.xml"), m_workbook->styles()->saveToXmlData()); } void Package::writeThemeFile(ZipWriter &zipWriter) diff --git a/src/xlsx/xlsxstyles.cpp b/src/xlsx/xlsxstyles.cpp index bf13fde..0218d5b 100755 --- a/src/xlsx/xlsxstyles.cpp +++ b/src/xlsx/xlsxstyles.cpp @@ -23,118 +23,113 @@ ** ****************************************************************************/ #include "xlsxstyles_p.h" -#include "xlsxformat.h" #include "xlsxxmlwriter_p.h" +#include "xlsxformat_p.h" #include #include #include #include +#include namespace QXlsx { -Styles::Styles(QObject *parent) : - QObject(parent) +Styles::Styles() { - m_fill_count = 0; - m_borders_count = 0; - m_font_count = 0; + //Add default Format + addFormat(createFormat()); + //Add another fill format + QSharedPointer fill = QSharedPointer(new FillData); + fill->pattern = Format::PatternGray125; + m_fillsList.append(fill); + m_fillsHash[fill->_key] = fill; } Styles::~Styles() { - qDeleteAll(m_formats); } -Format *Styles::addFormat() +Format *Styles::createFormat() { Format *format = new Format(); + m_createdFormatsList.append(QSharedPointer(format)); - m_formats.append(format); return format; } /* - * This function should be called after worksheet written finished, - * which means the order of the Formats used have been known to us. - */ -void Styles::prepareStyles() + Assign index to Font/Fill/Border and Format +*/ +void Styles::addFormat(Format *format) { - m_xf_formats = Format::xfFormats(); - m_dxf_formats = Format::dxfFormats(); - - if (m_xf_formats.isEmpty()) - m_xf_formats.append(this->addFormat()); - //fonts - QMap fontsKeyCache; - foreach (Format *format, m_xf_formats) { - const QByteArray &key = format->fontKey(); - if (fontsKeyCache.contains(key)) { - //Font has already been used. - format->setFontIndex(fontsKeyCache[key]); - format->setFontRedundant(true); - } else { - int index = fontsKeyCache.size(); - fontsKeyCache[key] = index; - format->setFontIndex(index); - format->setFontRedundant(false); - } - } - m_font_count = fontsKeyCache.size(); - - //borders - QMap bordersKeyCache; - foreach (Format *format, m_xf_formats) { - const QByteArray &key = format->borderKey(); - if (bordersKeyCache.contains(key)) { - //Border has already been used. - format->setBorderIndex(bordersKeyCache[key]); - format->setBorderRedundant(true); - } else { - int index = bordersKeyCache.size(); - bordersKeyCache[key] = index; - format->setBorderIndex(index); - format->setBorderRedundant(false); - } + if (!format) + return; + + //Font + if (!format->fontIndexValid()) { + if (!m_fontsHash.contains(format->fontKey())) { + QSharedPointer font = QSharedPointer(new FontData(format->d_func()->fontData)); + font->_index = m_fontsList.size(); //Assign proper index + m_fontsList.append(font); + m_fontsHash[font->_key] = font; + } + format->setFontIndex(m_fontsHash[format->fontKey()]->_index); } - m_borders_count = bordersKeyCache.size(); - - //fills - QMap fillsKeyCache; - // The user defined fill properties start from 2 since there are 2 - // default fills: patternType="none" and patternType="gray125". - { - QByteArray key; - QDataStream stream(&key, QIODevice::WriteOnly); - stream<fillIndexValid()) { + if (!m_fillsHash.contains(format->fillKey())) { + QSharedPointer fill = QSharedPointer(new FillData(format->d_func()->fillData)); + fill->_index = m_fillsList.size(); //Assign proper index + m_fillsList.append(fill); + m_fillsHash[fill->_key] = fill; + } + format->setFillIndex(m_fillsHash[format->fillKey()]->_index); } - { - QByteArray key; - QDataStream stream(&key, QIODevice::WriteOnly); - stream<borderIndexValid()) { + if (!m_bordersHash.contains(format->borderKey())) { + QSharedPointer border = QSharedPointer(new BorderData(format->d_func()->borderData)); + border->_index = m_bordersList.size(); //Assign proper index + m_bordersList.append(border); + m_bordersHash[border->_key] = border; + } + format->setBorderIndex(m_bordersHash[format->borderKey()]->_index); } - foreach (Format *format, m_xf_formats) { - const QByteArray &key = format->fillKey(); - if (fillsKeyCache.contains(key)) { - //Border has already been used. - format->setFillIndex(fillsKeyCache[key]); - format->setFillRedundant(true); - } else { - int index = fillsKeyCache.size(); - fillsKeyCache[key] = index; - format->setFillIndex(index); - format->setFillRedundant(false); - } + + //Format + if (format->isDxfFormat()) { + if (!format->dxfIndexValid()) { + if (!m_dxf_formatsHash.contains(format->formatKey())) { + format->setDxfIndex(m_dxf_formatsList.size()); + m_dxf_formatsList.append(format); + m_dxf_formatsHash[format->formatKey()] = format; + } else { + format->setDxfIndex(m_dxf_formatsHash[format->formatKey()]->dxfIndex()); + } + } + } else { + if (!format->xfIndexValid()) { + if (!m_xf_formatsHash.contains(format->formatKey())) { + format->setXfIndex(m_xf_formatsList.size()); + m_xf_formatsList.append(format); + m_xf_formatsHash[format->formatKey()] = format; + } else { + format->setXfIndex(m_xf_formatsHash[format->formatKey()]->xfIndex()); + } + } } - m_fill_count = fillsKeyCache.size(); } -void Styles::clearExtraFormatInfo() +QByteArray Styles::saveToXmlData() { - foreach (Format *format, m_formats) - format->clearExtraInfos(); + QByteArray data; + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + saveToXmlFile(&buffer); + + return data; } void Styles::saveToXmlFile(QIODevice *device) @@ -185,75 +180,94 @@ void Styles::saveToXmlFile(QIODevice *device) writer.writeEndDocument(); } +/* + not consider dxf format. +*/ void Styles::writeFonts(XmlStreamWriter &writer) { - writer.writeStartElement(QStringLiteral("fonts")); - writer.writeAttribute(QStringLiteral("count"), QString::number(m_font_count)); - foreach (Format *format, m_xf_formats) { - if (format->hasFont()) { - writer.writeStartElement(QStringLiteral("font")); - if (format->fontBold()) - writer.writeEmptyElement(QStringLiteral("b")); - if (format->fontItalic()) - writer.writeEmptyElement(QStringLiteral("i")); - if (format->fontStrikeOut()) - writer.writeEmptyElement(QStringLiteral("strike")); - if (format->fontOutline()) - writer.writeEmptyElement(QStringLiteral("outline")); - if (format->fontShadow()) - writer.writeEmptyElement(QStringLiteral("shadow")); - if (format->fontUnderline() != Format::FontUnderlineNone) { - writer.writeEmptyElement(QStringLiteral("u")); - if (format->fontUnderline() == Format::FontUnderlineDouble) - writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double")); - else if (format->fontUnderline() == Format::FontUnderlineSingleAccounting) - writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting")); - else if (format->fontUnderline() == Format::FontUnderlineDoubleAccounting) - writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting")); - } - if (format->fontScript() != Format::FontScriptNormal) { - writer.writeEmptyElement(QStringLiteral("vertAligh")); - if (format->fontScript() == Format::FontScriptSuper) - writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript")); - else - writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript")); - } + writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count())); + for (int i=0; i font = m_fontsList[i]; + + writer.writeStartElement(QStringLiteral("font")); + if (font->bold) + writer.writeEmptyElement(QStringLiteral("b")); + if (font->italic) + writer.writeEmptyElement(QStringLiteral("i")); + if (font->strikeOut) + writer.writeEmptyElement(QStringLiteral("strike")); + if (font->outline) + writer.writeEmptyElement(QStringLiteral("outline")); + if (font->shadow) + writer.writeEmptyElement(QStringLiteral("shadow")); + if (font->underline != Format::FontUnderlineNone) { + writer.writeEmptyElement(QStringLiteral("u")); + if (font->underline == Format::FontUnderlineDouble) + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double")); + else if (font->underline == Format::FontUnderlineSingleAccounting) + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting")); + else if (font->underline == Format::FontUnderlineDoubleAccounting) + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting")); + } + if (font->scirpt != Format::FontScriptNormal) { + writer.writeEmptyElement(QStringLiteral("vertAligh")); + if (font->scirpt == Format::FontScriptSuper) + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript")); + else + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript")); + } - if (!format->isDxfFormat()) { - writer.writeEmptyElement(QStringLiteral("sz")); - writer.writeAttribute(QStringLiteral("val"), QString::number(format->fontSize())); - } + writer.writeEmptyElement(QStringLiteral("sz")); + writer.writeAttribute(QStringLiteral("val"), QString::number(font->size)); - //font color - if (format->theme()) { - writer.writeEmptyElement(QStringLiteral("color")); - writer.writeAttribute(QStringLiteral("theme"), QString::number(format->theme())); - } else if (format->colorIndexed()) { - writer.writeEmptyElement(QStringLiteral("color")); - writer.writeAttribute(QStringLiteral("indexed"), QString::number(format->colorIndexed())); - } else if (format->fontColor().isValid()) { - writer.writeEmptyElement(QStringLiteral("color")); - QString color = format->fontColor().name(); - writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+color.mid(1));//remove # - } else if (!format->isDxfFormat()) { - writer.writeEmptyElement(QStringLiteral("color")); - writer.writeAttribute(QStringLiteral("theme"), QStringLiteral("1")); - } - - if (!format->isDxfFormat()) { - writer.writeEmptyElement(QStringLiteral("name")); - writer.writeAttribute(QStringLiteral("val"), format->fontName()); - writer.writeEmptyElement(QStringLiteral("family")); - writer.writeAttribute(QStringLiteral("val"), QString::number(format->fontFamily())); - if (format->fontName() == QLatin1String("Calibri")) { - writer.writeEmptyElement(QStringLiteral("scheme")); - writer.writeAttribute(QStringLiteral("val"), format->fontScheme()); - } - } + if (font->color.isValid()) { + writer.writeEmptyElement(QStringLiteral("color")); + QString color = font->color.name(); + writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+color.mid(1));//remove # + } - writer.writeEndElement(); //font + writer.writeEmptyElement(QStringLiteral("name")); + writer.writeAttribute(QStringLiteral("val"), font->name); + writer.writeEmptyElement(QStringLiteral("family")); + writer.writeAttribute(QStringLiteral("val"), QString::number(font->family)); + if (font->name == QLatin1String("Calibri")) { + writer.writeEmptyElement(QStringLiteral("scheme")); + writer.writeAttribute(QStringLiteral("val"), font->scheme); } + +// if (!format->isDxfFormat()) { +// writer.writeEmptyElement(QStringLiteral("sz")); +// writer.writeAttribute(QStringLiteral("val"), QString::number(format->fontSize())); +// } +// +// //font color +// if (format->theme()) { +// writer.writeEmptyElement(QStringLiteral("color")); +// writer.writeAttribute(QStringLiteral("theme"), QString::number(format->theme())); +// } else if (format->colorIndexed()) { +// writer.writeEmptyElement(QStringLiteral("color")); +// writer.writeAttribute(QStringLiteral("indexed"), QString::number(format->colorIndexed())); +// } else if (format->fontColor().isValid()) { +// writer.writeEmptyElement(QStringLiteral("color")); +// QString color = format->fontColor().name(); +// writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+color.mid(1));//remove # +// } else if (!format->isDxfFormat()) { +// writer.writeEmptyElement(QStringLiteral("color")); +// writer.writeAttribute(QStringLiteral("theme"), QStringLiteral("1")); +// } + +// if (!format->isDxfFormat()) { +// writer.writeEmptyElement(QStringLiteral("name")); +// writer.writeAttribute(QStringLiteral("val"), format->fontName()); +// writer.writeEmptyElement(QStringLiteral("family")); +// writer.writeAttribute(QStringLiteral("val"), QString::number(format->fontFamily())); +// if (format->fontName() == QLatin1String("Calibri")) { +// writer.writeEmptyElement(QStringLiteral("scheme")); +// writer.writeAttribute(QStringLiteral("val"), format->fontScheme()); +// } +// } + writer.writeEndElement(); //font } writer.writeEndElement();//fonts } @@ -261,25 +275,16 @@ void Styles::writeFonts(XmlStreamWriter &writer) void Styles::writeFills(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("fills")); - writer.writeAttribute(QStringLiteral("count"), QString::number(m_fill_count)); - //wirte two default fill first - writer.writeStartElement(QStringLiteral("fill")); - writer.writeEmptyElement(QStringLiteral("patternFill")); - writer.writeAttribute(QStringLiteral("patternType"), QStringLiteral("none")); - writer.writeEndElement();//fill - writer.writeStartElement(QStringLiteral("fill")); - writer.writeEmptyElement(QStringLiteral("patternFill")); - writer.writeAttribute(QStringLiteral("patternType"), QStringLiteral("gray125")); - writer.writeEndElement();//fill - foreach (Format *format, m_xf_formats) { - if (format->hasFill()) { - writeFill(writer, format); - } + writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size())); + + for (int i=0; i fill = m_fillsList[i]; + writeFill(writer, fill.data()); } writer.writeEndElement(); //fills } -void Styles::writeFill(XmlStreamWriter &writer, Format *format) +void Styles::writeFill(XmlStreamWriter &writer, FillData *fill) { static QMap patternStrings; if (patternStrings.isEmpty()) { @@ -305,14 +310,14 @@ void Styles::writeFill(XmlStreamWriter &writer, Format *format) writer.writeStartElement(QStringLiteral("fill")); writer.writeStartElement(QStringLiteral("patternFill")); - writer.writeAttribute(QStringLiteral("patternType"), patternStrings[format->fillPattern()]); - if (format->patternForegroundColor().isValid()) { + writer.writeAttribute(QStringLiteral("patternType"), patternStrings[fill->pattern]); + if (fill->fgColor.isValid()) { writer.writeEmptyElement(QStringLiteral("fgColor")); - writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+format->patternForegroundColor().name().mid(1)); + writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+fill->fgColor.name().mid(1)); } - if (format->patternBackgroundColor().isValid()) { + if (fill->bgColor.isValid()) { writer.writeEmptyElement(QStringLiteral("bgColor")); - writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+format->patternBackgroundColor().name().mid(1)); + writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+fill->bgColor.name().mid(1)); } writer.writeEndElement();//patternFill @@ -322,28 +327,28 @@ void Styles::writeFill(XmlStreamWriter &writer, Format *format) void Styles::writeBorders(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("borders")); - writer.writeAttribute(QStringLiteral("count"), QString::number(m_borders_count)); - foreach (Format *format, m_xf_formats) { - if (format->hasBorders()) { - writer.writeStartElement(QStringLiteral("border")); - if (format->diagonalBorderType() == Format::DiagonalBorderUp) { - writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); - } else if (format->diagonalBorderType() == Format::DiagonalBorderDown) { - writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); - } else if (format->DiagnoalBorderBoth) { - writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); - writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); - } - writeSubBorder(writer, QStringLiteral("left"), format->leftBorderStyle(), format->leftBorderColor()); - writeSubBorder(writer, QStringLiteral("right"), format->rightBorderStyle(), format->rightBorderColor()); - writeSubBorder(writer, QStringLiteral("top"), format->topBorderStyle(), format->topBorderColor()); - writeSubBorder(writer, QStringLiteral("bottom"), format->bottomBorderStyle(), format->bottomBorderColor()); - - if (!format->isDxfFormat()) { - writeSubBorder(writer, QStringLiteral("diagonal"), format->diagonalBorderStyle(), format->diagonalBorderColor()); - } - writer.writeEndElement();//border + writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count())); + for (int i=0; i border = m_bordersList[i]; + + writer.writeStartElement(QStringLiteral("border")); + if (border->diagonalType == Format::DiagonalBorderUp) { + writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); + } else if (border->diagonalType == Format::DiagonalBorderDown) { + writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); + } else if (border->diagonalType == Format::DiagnoalBorderBoth) { + writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); + writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); } + writeSubBorder(writer, QStringLiteral("left"), border->left, border->leftColor); + writeSubBorder(writer, QStringLiteral("right"), border->right, border->rightColor); + writeSubBorder(writer, QStringLiteral("top"), border->top, border->topColor); + writeSubBorder(writer, QStringLiteral("bottom"), border->bottom, border->bottomColor); + +// if (!format->isDxfFormat()) { + writeSubBorder(writer, QStringLiteral("diagonal"), border->diagonal, border->diagonalColor); +// } + writer.writeEndElement();//border } writer.writeEndElement();//borders } @@ -386,8 +391,8 @@ void Styles::writeSubBorder(XmlStreamWriter &writer, const QString &type, int st void Styles::writeCellXfs(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("cellXfs")); - writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formats.size())); - foreach (Format *format, m_xf_formats) { + writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size())); + foreach (Format *format, m_xf_formatsList) { int num_fmt_id = format->numberFormat(); int font_id = format->fontIndex(); int fill_id = format->fillIndex(); @@ -436,12 +441,27 @@ void Styles::writeCellXfs(XmlStreamWriter &writer) void Styles::writeDxfs(XmlStreamWriter &writer) { writer.writeStartElement(QStringLiteral("dxfs")); - writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formats.size())); - foreach (Format *format, m_dxf_formats) { + writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size())); + foreach (Format *format, m_dxf_formatsList) { writer.writeStartElement(QStringLiteral("dxf")); writer.writeEndElement();//dxf } writer.writeEndElement(); //dxfs } +QSharedPointer Styles::loadFromXmlFile(QIODevice *device) +{ + + return QSharedPointer(new Styles); +} + +QSharedPointer Styles::loadFromXmlData(const QByteArray &data) +{ + QBuffer buffer; + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + return loadFromXmlFile(&buffer); +} + } //namespace QXlsx diff --git a/src/xlsx/xlsxstyles_p.h b/src/xlsx/xlsxstyles_p.h index 47dd95f..7ec65f9 100755 --- a/src/xlsx/xlsxstyles_p.h +++ b/src/xlsx/xlsxstyles_p.h @@ -25,42 +25,59 @@ #ifndef XLSXSTYLES_H #define XLSXSTYLES_H -#include +#include "xlsxglobal.h" +#include +#include +#include class QIODevice; namespace QXlsx { class Format; +struct FontData; +struct FillData; +struct BorderData; class XmlStreamWriter; -class Styles : public QObject +class XLSX_AUTOTEST_EXPORT Styles : public QObject { public: - explicit Styles(QObject *parent=0); + Styles(); ~Styles(); - Format *addFormat(); + Format *createFormat(); + void addFormat(Format *format); - void prepareStyles(); - void clearExtraFormatInfo(); + QByteArray saveToXmlData(); void saveToXmlFile(QIODevice *device); + static QSharedPointer loadFromXmlFile(QIODevice *device); + static QSharedPointer loadFromXmlData(const QByteArray &data); private: + friend class Format; + void writeFonts(XmlStreamWriter &writer); void writeFills(XmlStreamWriter &writer); - void writeFill(XmlStreamWriter &writer, Format *format); + void writeFill(XmlStreamWriter &writer, FillData *fill); void writeBorders(XmlStreamWriter &writer); void writeSubBorder(XmlStreamWriter &writer, const QString &type, int style, const QColor &color); void writeCellXfs(XmlStreamWriter &writer); void writeDxfs(XmlStreamWriter &writer); - QList m_formats; - QList m_xf_formats; - QList m_dxf_formats; + QList > m_fontsList; //Keep a copy of unique fonts + QList > m_fillsList; //Keep a copy of unique fills + QList > m_bordersList; //Keep a copy of unique borders + QHash > m_fontsHash; + QHash > m_fillsHash; + QHash > m_bordersHash; + + QList > m_createdFormatsList; //All created formats + + QList m_xf_formatsList; + QHash m_xf_formatsHash; - int m_font_count; - int m_fill_count; - int m_borders_count; + QList m_dxf_formatsList; + QHash m_dxf_formatsHash; }; } diff --git a/src/xlsx/xlsxworkbook.cpp b/src/xlsx/xlsxworkbook.cpp index ed6cd07..73676ac 100755 --- a/src/xlsx/xlsxworkbook.cpp +++ b/src/xlsx/xlsxworkbook.cpp @@ -41,7 +41,7 @@ WorkbookPrivate::WorkbookPrivate(Workbook *q) : q_ptr(q) { sharedStrings = QSharedPointer (new SharedStrings); - styles = new Styles(q); + styles = QSharedPointer(new Styles); x_window = 240; y_window = 15; @@ -161,10 +161,10 @@ void Workbook::setActivedWorksheet(int index) d->activesheet = index; } -Format *Workbook::addFormat() +Format *Workbook::createFormat() { Q_D(Workbook); - return d->styles->addFormat(); + return d->styles->createFormat(); } QList Workbook::worksheets() const @@ -182,7 +182,7 @@ SharedStrings *Workbook::sharedStrings() Styles *Workbook::styles() { Q_D(Workbook); - return d->styles; + return d->styles.data(); } QList Workbook::images() diff --git a/src/xlsx/xlsxworkbook.h b/src/xlsx/xlsxworkbook.h index cdd5959..d56fd90 100755 --- a/src/xlsx/xlsxworkbook.h +++ b/src/xlsx/xlsxworkbook.h @@ -58,7 +58,7 @@ public: int activedWorksheet() const; void setActivedWorksheet(int index); - Format *addFormat(); + Format *createFormat(); // void addChart(); void defineName(const QString &name, const QString &formula); bool isDate1904() const; diff --git a/src/xlsx/xlsxworkbook_p.h b/src/xlsx/xlsxworkbook_p.h index 6d81d96..dceee14 100644 --- a/src/xlsx/xlsxworkbook_p.h +++ b/src/xlsx/xlsxworkbook_p.h @@ -39,7 +39,7 @@ public: QSharedPointer sharedStrings; QList worksheets; - Styles *styles; + QSharedPointer styles; QList images; QList drawings; diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index b1ad808..4e035e0 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/src/xlsx/xlsxworksheet.cpp @@ -30,6 +30,7 @@ #include "xlsxsharedstrings_p.h" #include "xlsxxmlwriter_p.h" #include "xlsxdrawing_p.h" +#include "xlsxstyles_p.h" #include #include @@ -354,6 +355,7 @@ int Worksheet::writeString(int row, int column, const QString &value, Format *fo int index = sharedStrings->addSharedString(content); d->cellTable[row][column] = new XlsxCellData(index, XlsxCellData::String, format); + d->workbook->styles()->addFormat(format); return error; } @@ -364,6 +366,7 @@ int Worksheet::writeNumber(int row, int column, double value, Format *format) return -1; d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format); + d->workbook->styles()->addFormat(format); return 0; } @@ -382,6 +385,7 @@ int Worksheet::writeFormula(int row, int column, const QString &content, Format XlsxCellData *data = new XlsxCellData(result, XlsxCellData::Formula, format); data->formula = formula; d->cellTable[row][column] = data; + d->workbook->styles()->addFormat(format); return error; } @@ -393,6 +397,8 @@ int Worksheet::writeBlank(int row, int column, Format *format) return -1; d->cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format); + d->workbook->styles()->addFormat(format); + return 0; } @@ -403,6 +409,8 @@ int Worksheet::writeBool(int row, int column, bool value, Format *format) return -1; d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format); + d->workbook->styles()->addFormat(format); + return 0; } @@ -413,6 +421,8 @@ int Worksheet::writeDateTime(int row, int column, const QDateTime &dt, Format *f return -1; d->cellTable[row][column] = new XlsxCellData(dt, XlsxCellData::DateTime, format); + d->workbook->styles()->addFormat(format); + return 0; } @@ -476,6 +486,7 @@ int Worksheet::writeUrl(int row, int column, const QUrl &url, Format *format, co //Store the hyperlink data in sa separate table d->urlTable[row][column] = new XlsxUrlData(link_type, urlString, locationString, tip); + d->workbook->styles()->addFormat(format); return error; } @@ -825,6 +836,7 @@ bool Worksheet::setRow(int row, double height, Format *format, bool hidden) } else { d->rowsInfo[row] = new XlsxRowInfo(height, format, hidden); } + d->workbook->styles()->addFormat(format); return true; } @@ -851,6 +863,8 @@ bool Worksheet::setColumn(int colFirst, int colLast, double width, Format *forma for (int col=colFirst; col<=colLast; ++col) d->colsInfoHelper[col] = info; + d->workbook->styles()->addFormat(format); + return true; } diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index b86ac2b..fdd383d 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -7,4 +7,5 @@ SUBDIRS=\ propscore \ propsapp \ readdocument \ - sharedstrings + sharedstrings \ + styles diff --git a/tests/auto/styles/styles.pro b/tests/auto/styles/styles.pro new file mode 100644 index 0000000..2ffcf31 --- /dev/null +++ b/tests/auto/styles/styles.pro @@ -0,0 +1,13 @@ +QT += testlib xlsx xlsx-private +CONFIG += testcase +DEFINES += XLSX_TEST + +TARGET = tst_stylestest +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + + +SOURCES += tst_stylestest.cpp +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/styles/tst_stylestest.cpp b/tests/auto/styles/tst_stylestest.cpp new file mode 100644 index 0000000..ce81891 --- /dev/null +++ b/tests/auto/styles/tst_stylestest.cpp @@ -0,0 +1,46 @@ +#include "private/xlsxstyles_p.h" +#include "xlsxformat.h" +#include +#include + +class StylesTest : public QObject +{ + Q_OBJECT + +public: + StylesTest(); + +private Q_SLOTS: + void testEmptyStyle(); + void testAddFormat(); +}; + +StylesTest::StylesTest() +{ +} + +void StylesTest::testEmptyStyle() +{ + QXlsx::Styles styles; + QByteArray xmlData = styles.saveToXmlData(); + + QVERIFY2(xmlData.contains(""), "Must have one cell style"); +} + +void StylesTest::testAddFormat() +{ + QXlsx::Styles styles; + + for (int i=0; i<10; ++i) { + QXlsx::Format *format = styles.createFormat(); + format->setFontBold(true); + styles.addFormat(format); + } + + QByteArray xmlData = styles.saveToXmlData(); + QVERIFY2(xmlData.contains(""), ""); //Note we have a default one +} + +QTEST_APPLESS_MAIN(StylesTest) + +#include "tst_stylestest.moc"