From a563809f770d4149edfcb89da61d2f7d7bc24e41 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 29 Aug 2013 15:19:28 +0800 Subject: [PATCH] Refactor: D-Pointer used for public classes --- src/qtxlsxwriter.pri | 5 +- src/xlsxformat.cpp | 619 ++++++++++++++++++++++++++---------------- src/xlsxformat.h | 129 ++------- src/xlsxformat_p.h | 172 ++++++++++++ src/xlsxstyles.cpp | 4 +- src/xlsxworkbook.cpp | 100 ++++--- src/xlsxworkbook.h | 19 +- src/xlsxworkbook_p.h | 58 ++++ src/xlsxworksheet.cpp | 488 ++++++++++++++++----------------- src/xlsxworksheet.h | 44 +-- src/xlsxworksheet_p.h | 129 +++++++++ 11 files changed, 1078 insertions(+), 689 deletions(-) create mode 100644 src/xlsxformat_p.h create mode 100644 src/xlsxworkbook_p.h create mode 100644 src/xlsxworksheet_p.h diff --git a/src/qtxlsxwriter.pri b/src/qtxlsxwriter.pri index 85ec140..3d5e032 100755 --- a/src/qtxlsxwriter.pri +++ b/src/qtxlsxwriter.pri @@ -15,7 +15,10 @@ HEADERS += $$PWD/xlsxdocprops_p.h \ $$PWD/xlsxstyles_p.h \ $$PWD/xlsxworksheet.h \ $$PWD/zipwriter_p.h \ - $$PWD/xlsxpackage_p.h + $$PWD/xlsxpackage_p.h \ + $$PWD/xlsxworkbook_p.h \ + $$PWD/xlsxworksheet_p.h \ + $$PWD/xlsxformat_p.h SOURCES += $$PWD/xlsxdocprops.cpp \ $$PWD/xlsxrelationships.cpp \ diff --git a/src/xlsxformat.cpp b/src/xlsxformat.cpp index 98bec95..725d2b6 100755 --- a/src/xlsxformat.cpp +++ b/src/xlsxformat.cpp @@ -23,316 +23,353 @@ ** ****************************************************************************/ #include "xlsxformat.h" +#include "xlsxformat_p.h" #include #include namespace QXlsx { -QList Format::s_xfFormats; -QList Format::s_dxfFormats; - -Format::Format() -{ - m_number.formatIndex = 0; - - m_font.bold = false; - m_font.color = QColor(Qt::black); - m_font.italic = false; - m_font.name = "Calibri"; - m_font.scirpt = FontScriptNormal; - m_font.size = 11; - m_font.strikeOut = false; - m_font.underline = FontUnderlineNone; - m_font.shadow = false; - m_font.outline = false; - m_font.family = 2; - m_font.scheme = "minor"; - m_font.charset = 0; - m_font.condense = 0; - m_font.extend = 0; - m_font._dirty = true; - m_font._redundant = false; - m_font._index = -1; - - m_alignment.alignH = AlignHGeneral; - m_alignment.alignV = AlignBottom; - m_alignment.wrap = false; - m_alignment.rotation = 0; - m_alignment.indent = 0; - m_alignment.shinkToFit = false; - - m_border.left = BorderNone; - m_border.right = BorderNone; - m_border.top = BorderNone; - m_border.bottom = BorderNone; - m_border.diagonal = BorderNone; - m_border.diagonalType = DiagonalBorderNone; - m_border.leftColor = QColor(); - m_border.rightColor = QColor(); - m_border.topColor = QColor(); - m_border.bottomColor = QColor(); - m_border.diagonalColor = QColor(); - m_border._dirty = true; - m_border._redundant = false; - m_border._index = -1; - - m_fill.pattern = PatternNone; - m_fill.bgColor = QColor(); - m_fill.fgColor = QColor(); - m_fill._dirty = true; - m_fill._redundant = false; - m_fill._index = -1; - - m_protection.locked = false; - m_protection.hidden = false; - - m_dirty = true; - - m_is_dxf_fomat = false; - m_xf_index = -1; - m_dxf_index = -1; - - m_theme = 0; - m_color_indexed = 0; +QList FormatPrivate::s_xfFormats; +QList FormatPrivate::s_dxfFormats; + +FormatPrivate::FormatPrivate(Format *p) : + q_ptr(p) +{ + dirty = true; + + is_dxf_fomat = false; + xf_index = -1; + dxf_index = -1; + + theme = 0; + color_indexed = 0; +} + +Format::Format() : + d_ptr(new FormatPrivate(this)) +{ + +} + +Format::~Format() +{ + delete d_ptr; } int Format::numberFormat() const { - return m_number.formatIndex; + Q_D(const Format); + return d->numberData.formatIndex; } void Format::setNumberFormat(int format) { - m_dirty = true; - m_number.formatIndex = format; + Q_D(Format); + d->dirty = true; + d->numberData.formatIndex = format; } int Format::fontSize() const { - return m_font.size; + Q_D(const Format); + return d->fontData.size; } void Format::setFontSize(int size) { - m_font.size = size; - m_font._dirty = true; + Q_D(Format); + d->fontData.size = size; + d->fontData._dirty = true; } bool Format::fontItalic() const { - return m_font.italic; + Q_D(const Format); + return d->fontData.italic; } void Format::setFontItalic(bool italic) { - m_font.italic = italic; - m_font._dirty = true; + Q_D(Format); + d->fontData.italic = italic; + d->fontData._dirty = true; } bool Format::fontStrikeOut() const { - return m_font.strikeOut; + Q_D(const Format); + return d->fontData.strikeOut; } void Format::setFontStrikeOut(bool strikeOut) { - m_font.strikeOut = strikeOut; - m_font._dirty = true; + Q_D(Format); + d->fontData.strikeOut = strikeOut; + d->fontData._dirty = true; } QColor Format::fontColor() const { - return m_font.color; + Q_D(const Format); + return d->fontData.color; } void Format::setFontColor(const QColor &color) { - m_font.color = color; - m_font._dirty = true; + Q_D(Format); + d->fontData.color = color; + d->fontData._dirty = true; } bool Format::fontBold() const { - return m_font.bold; + Q_D(const Format); + return d->fontData.bold; } void Format::setFontBold(bool bold) { - m_font.bold = bold; - m_font._dirty = true; + Q_D(Format); + d->fontData.bold = bold; + d->fontData._dirty = true; } Format::FontScript Format::fontScript() const { - return m_font.scirpt; + Q_D(const Format); + return d->fontData.scirpt; } void Format::setFontScript(FontScript script) { - m_font.scirpt = script; - m_font._dirty = true; + Q_D(Format); + d->fontData.scirpt = script; + d->fontData._dirty = true; } Format::FontUnderline Format::fontUnderline() const { - return m_font.underline; + Q_D(const Format); + return d->fontData.underline; } void Format::setFontUnderline(FontUnderline underline) { - m_font.underline = underline; - m_font._dirty = true; + Q_D(Format); + d->fontData.underline = underline; + d->fontData._dirty = true; } bool Format::fontOutline() const { - return m_font.outline; + Q_D(const Format); + return d->fontData.outline; } void Format::setFontOutline(bool outline) { - m_font.outline = outline; - m_font._dirty = true; + Q_D(Format); + d->fontData.outline = outline; + d->fontData._dirty = true; } QString Format::fontName() const { - return m_font.name; + Q_D(const Format); + return d->fontData.name; } void Format::setFontName(const QString &name) { - m_font.name = name; - m_font._dirty = true; + Q_D(Format); + d->fontData.name = name; + d->fontData._dirty = true; +} + +bool Format::hasFont() const +{ + Q_D(const Format); + return !d->fontData._redundant; +} + +void Format::setFontRedundant(bool redundant) +{ + Q_D(Format); + d->fontData._redundant = redundant; +} + +int Format::fontIndex() const +{ + Q_D(const Format); + return d->fontData._index; +} + +void Format::setFontIndex(int index) +{ + Q_D(Format); + d->fontData._index = index; +} + +int Format::fontFamily() const +{ + Q_D(const Format); + return d->fontData.family; +} + +bool Format::fontShadow() const +{ + Q_D(const Format); + return d->fontData.shadow; +} + +QString Format::fontScheme() const +{ + Q_D(const Format); + return d->fontData.scheme; } /* Internal */ QByteArray Format::fontKey() const { - if (m_font._dirty) { + Q_D(const Format); + if (d->fontData._dirty) { QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); - stream<(this)->m_font._key = key; - const_cast(this)->m_font._dirty = false; - const_cast(this)->m_dirty = true; //Make sure formatKey() will be re-generated. + stream<fontData.bold<fontData.charset<fontData.color<fontData.condense + <fontData.extend<fontData.family<fontData.italic<fontData.name + <fontData.outline<fontData.scheme<fontData.scirpt<fontData.shadow + <fontData.size<fontData.strikeOut<fontData.underline; + + const_cast(d)->fontData._key = key; + const_cast(d)->fontData._dirty = false; + const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } - return m_font._key; + return d->fontData._key; } Format::HorizontalAlignment Format::horizontalAlignment() const { - return m_alignment.alignH; + Q_D(const Format); + return d->alignmentData.alignH; } void Format::setHorizontalAlignment(HorizontalAlignment align) { - if (m_alignment.indent &&(align != AlignHGeneral && align != AlignLeft && + Q_D(Format); + if (d->alignmentData.indent &&(align != AlignHGeneral && align != AlignLeft && align != AlignRight && align != AlignHDistributed)) { - m_alignment.indent = 0; + d->alignmentData.indent = 0; } - if (m_alignment.shinkToFit && (align == AlignHFill || align == AlignHJustify + if (d->alignmentData.shinkToFit && (align == AlignHFill || align == AlignHJustify || align == AlignHDistributed)) { - m_alignment.shinkToFit = false; + d->alignmentData.shinkToFit = false; } - m_alignment.alignH = align; - m_dirty = true; + d->alignmentData.alignH = align; + d->dirty = true; } Format::VerticalAlignment Format::verticalAlignment() const { - return m_alignment.alignV; + Q_D(const Format); + return d->alignmentData.alignV; } void Format::setVerticalAlignment(VerticalAlignment align) { - m_alignment.alignV = align; - m_dirty = true; + Q_D(Format); + d->alignmentData.alignV = align; + d->dirty = true; } bool Format::textWrap() const { - return m_alignment.wrap; + Q_D(const Format); + return d->alignmentData.wrap; } void Format::setTextWarp(bool wrap) { - if (wrap && m_alignment.shinkToFit) - m_alignment.shinkToFit = false; + Q_D(Format); + if (wrap && d->alignmentData.shinkToFit) + d->alignmentData.shinkToFit = false; - m_alignment.wrap = wrap; - m_dirty = true; + d->alignmentData.wrap = wrap; + d->dirty = true; } int Format::rotation() const { - return m_alignment.rotation; + Q_D(const Format); + return d->alignmentData.rotation; } void Format::setRotation(int rotation) { - m_alignment.rotation = rotation; - m_dirty = true; + Q_D(Format); + d->alignmentData.rotation = rotation; + d->dirty = true; } int Format::indent() const { - return m_alignment.indent; + Q_D(const Format); + return d->alignmentData.indent; } void Format::setIndent(int indent) { - if (indent && (m_alignment.alignH != AlignHGeneral - && m_alignment.alignH != AlignLeft - && m_alignment.alignH != AlignRight - && m_alignment.alignH != AlignHJustify)) { - m_alignment.alignH = AlignLeft; + Q_D(Format); + if (indent && (d->alignmentData.alignH != AlignHGeneral + && d->alignmentData.alignH != AlignLeft + && d->alignmentData.alignH != AlignRight + && d->alignmentData.alignH != AlignHJustify)) { + d->alignmentData.alignH = AlignLeft; } - m_alignment.indent = indent; - m_dirty = true; + d->alignmentData.indent = indent; + d->dirty = true; } bool Format::shrinkToFit() const { - return m_alignment.shinkToFit; + Q_D(const Format); + return d->alignmentData.shinkToFit; } void Format::setShrinkToFit(bool shink) { - if (shink && m_alignment.wrap) - m_alignment.wrap = false; - if (shink && (m_alignment.alignH == AlignHFill - || m_alignment.alignH == AlignHJustify - || m_alignment.alignH == AlignHDistributed)) { - m_alignment.alignH = AlignLeft; + Q_D(Format); + if (shink && d->alignmentData.wrap) + d->alignmentData.wrap = false; + if (shink && (d->alignmentData.alignH == AlignHFill + || d->alignmentData.alignH == AlignHJustify + || d->alignmentData.alignH == AlignHDistributed)) { + d->alignmentData.alignH = AlignLeft; } - m_alignment.shinkToFit = shink; - m_dirty = true; + d->alignmentData.shinkToFit = shink; + d->dirty = true; } bool Format::alignmentChanged() const { - return m_alignment.alignH != AlignHGeneral - || m_alignment.alignV != AlignBottom - || m_alignment.indent != 0 - || m_alignment.wrap - || m_alignment.rotation != 0 - || m_alignment.shinkToFit; + Q_D(const Format); + return d->alignmentData.alignH != AlignHGeneral + || d->alignmentData.alignV != AlignBottom + || d->alignmentData.indent != 0 + || d->alignmentData.wrap + || d->alignmentData.rotation != 0 + || d->alignmentData.shinkToFit; } QString Format::horizontalAlignmentString() const { + Q_D(const Format); QString alignH; - switch (m_alignment.alignH) { + switch (d->alignmentData.alignH) { case Format::AlignLeft: alignH = "left"; break; @@ -362,8 +399,9 @@ QString Format::horizontalAlignmentString() const QString Format::verticalAlignmentString() const { + Q_D(const Format); QString align; - switch (m_alignment.alignV) { + switch (d->alignmentData.alignV) { case AlignTop: align = "top"; break; @@ -400,236 +438,318 @@ void Format::setBorderColor(const QColor &color) Format::BorderStyle Format::leftBorderStyle() const { - return m_border.left; + Q_D(const Format); + return d->borderData.left; } void Format::setLeftBorderStyle(BorderStyle style) { - m_border.left = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.left = style; + d->borderData._dirty = true; } QColor Format::leftBorderColor() const { - return m_border.leftColor; + Q_D(const Format); + return d->borderData.leftColor; } void Format::setLeftBorderColor(const QColor &color) { - m_border.leftColor = color; - m_border._dirty = true; + Q_D(Format); + d->borderData.leftColor = color; + d->borderData._dirty = true; } Format::BorderStyle Format::rightBorderStyle() const { - return m_border.right; + Q_D(const Format); + return d->borderData.right; } void Format::setRightBorderStyle(BorderStyle style) { - m_border.right = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.right = style; + d->borderData._dirty = true; } QColor Format::rightBorderColor() const { - return m_border.rightColor; + Q_D(const Format); + return d->borderData.rightColor; } void Format::setRightBorderColor(const QColor &color) { - m_border.rightColor = color; - m_border._dirty = true; + Q_D(Format); + d->borderData.rightColor = color; + d->borderData._dirty = true; } Format::BorderStyle Format::topBorderStyle() const { - return m_border.top; + Q_D(const Format); + return d->borderData.top; } void Format::setTopBorderStyle(BorderStyle style) { - m_border.top = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.top = style; + d->borderData._dirty = true; } QColor Format::topBorderColor() const { - return m_border.topColor; + Q_D(const Format); + return d->borderData.topColor; } void Format::setTopBorderColor(const QColor &color) { - m_border.topColor = color; - m_border._dirty = true; + Q_D(Format); + d->borderData.topColor = color; + d->borderData._dirty = true; } Format::BorderStyle Format::bottomBorderStyle() const { - return m_border.bottom; + Q_D(const Format); + return d->borderData.bottom; } void Format::setBottomBorderStyle(BorderStyle style) { - m_border.bottom = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.bottom = style; + d->borderData._dirty = true; } QColor Format::bottomBorderColor() const { - return m_border.bottomColor; + Q_D(const Format); + return d->borderData.bottomColor; } void Format::setBottomBorderColor(const QColor &color) { - m_border.bottomColor = color; - m_border._dirty = true; + Q_D(Format); + d->borderData.bottomColor = color; + d->borderData._dirty = true; } Format::BorderStyle Format::diagonalBorderStyle() const { - return m_border.diagonal; + Q_D(const Format); + return d->borderData.diagonal; } void Format::setDiagonalBorderStyle(BorderStyle style) { - m_border.diagonal = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.diagonal = style; + d->borderData._dirty = true; } Format::DiagonalBorderType Format::diagonalBorderType() const { - return m_border.diagonalType; + Q_D(const Format); + return d->borderData.diagonalType; } void Format::setDiagonalBorderType(DiagonalBorderType style) { - m_border.diagonalType = style; - m_border._dirty = true; + Q_D(Format); + d->borderData.diagonalType = style; + d->borderData._dirty = true; } QColor Format::diagonalBorderColor() const { - return m_border.diagonalColor; + Q_D(const Format); + return d->borderData.diagonalColor; } void Format::setDiagonalBorderColor(const QColor &color) { - m_border.diagonalColor = color; - m_border._dirty = true; + Q_D(Format); + d->borderData.diagonalColor = color; + d->borderData._dirty = true; } +bool Format::hasBorders() const +{ + Q_D(const Format); + return !d->borderData._redundant; +} + +void Format::setBorderRedundant(bool redundant) +{ + Q_D(Format); + d->borderData._redundant = redundant; +} + +int Format::borderIndex() const +{ + Q_D(const Format); + return d->borderData._index; +} + +void Format::setBorderIndex(int index) +{ + Q_D(Format); + d->borderData._index = index; +} /* Internal */ QByteArray Format::borderKey() const { - if (m_border._dirty) { + Q_D(const Format); + if (d->borderData._dirty) { QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); - stream<(this)->m_border._key = key; - const_cast(this)->m_border._dirty = false; - const_cast(this)->m_dirty = true; //Make sure formatKey() will be re-generated. + stream<borderData.bottom<borderData.bottomColor + <borderData.diagonal<borderData.diagonalColor<borderData.diagonalType + <borderData.left<borderData.leftColor + <borderData.right<borderData.rightColor + <borderData.top<borderData.topColor; + const_cast(d)->borderData._key = key; + const_cast(d)->borderData._dirty = false; + const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } - return m_border._key; + return d->borderData._key; } Format::FillPattern Format::fillPattern() const { - return m_fill.pattern; + Q_D(const Format); + return d->fillData.pattern; } void Format::setFillPattern(FillPattern pattern) { - m_fill.pattern = pattern; - m_fill._dirty = true; + Q_D(Format); + d->fillData.pattern = pattern; + d->fillData._dirty = true; } QColor Format::patternForegroundColor() const { - return m_fill.fgColor; + Q_D(const Format); + return d->fillData.fgColor; } void Format::setPatternForegroundColor(const QColor &color) { - if (color.isValid() && m_fill.pattern == PatternNone) - m_fill.pattern = PatternSolid; - m_fill.fgColor = color; - m_fill._dirty = true; + Q_D(Format); + if (color.isValid() && d->fillData.pattern == PatternNone) + d->fillData.pattern = PatternSolid; + d->fillData.fgColor = color; + d->fillData._dirty = true; } QColor Format::patternBackgroundColor() const { - return m_fill.bgColor; + Q_D(const Format); + return d->fillData.bgColor; } void Format::setPatternBackgroundColor(const QColor &color) { - if (color.isValid() && m_fill.pattern == PatternNone) - m_fill.pattern = PatternSolid; - m_fill.bgColor = color; - m_fill._dirty = true; + Q_D(Format); + if (color.isValid() && d->fillData.pattern == PatternNone) + d->fillData.pattern = PatternSolid; + d->fillData.bgColor = color; + d->fillData._dirty = true; +} + +bool Format::hasFill() const +{ + Q_D(const Format); + return !d->fillData._redundant; +} + +void Format::setFillRedundant(bool redundant) +{ + Q_D(Format); + d->fillData._redundant = redundant; +} + +int Format::fillIndex() const +{ + Q_D(const Format); + return d->fillData._index; +} + +void Format::setFillIndex(int index) +{ + Q_D(Format); + d->fillData._index = index; } /* Internal */ QByteArray Format::fillKey() const { - if (m_fill._dirty) { + Q_D(const Format); + if (d->fillData._dirty) { QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); - stream<(this)->m_fill._key = key; - const_cast(this)->m_fill._dirty = false; - const_cast(this)->m_dirty = true; //Make sure formatKey() will be re-generated. + stream<fillData.bgColor<fillData.fgColor<fillData.pattern; + const_cast(d)->fillData._key = key; + const_cast(d)->fillData._dirty = false; + const_cast(d)->dirty = true; //Make sure formatKey() will be re-generated. } - return m_fill._key; + return d->fillData._key; } bool Format::hidden() const { - return m_protection.hidden; + Q_D(const Format); + return d->protectionData.hidden; } void Format::setHidden(bool hidden) { - m_protection.hidden = hidden; - m_dirty = true; + Q_D(Format); + d->protectionData.hidden = hidden; + d->dirty = true; } bool Format::locked() const { - return m_protection.locked; + Q_D(const Format); + return d->protectionData.locked; } void Format::setLocked(bool locked) { - m_protection.locked = locked; - m_dirty = true; + Q_D(Format); + d->protectionData.locked = locked; + d->dirty = true; } QByteArray Format::formatKey() const { - if (m_dirty || m_font._dirty || m_border._dirty || m_fill._dirty) { + Q_D(const Format); + if (d->dirty || d->fontData._dirty || d->borderData._dirty || d->fillData._dirty) { QByteArray key; QDataStream stream(&key, QIODevice::WriteOnly); stream<(this)->m_formatKey = key; - const_cast(this)->m_dirty = false; + <numberData.formatIndex + <alignmentData.alignH<alignmentData.alignV<alignmentData.indent + <alignmentData.rotation<alignmentData.shinkToFit<alignmentData.wrap + <protectionData.hidden<protectionData.locked; + const_cast(d)->formatKey = key; + const_cast(d)->dirty = false; } - return m_formatKey; + return d->formatKey; } bool Format::operator ==(const Format &format) const @@ -650,35 +770,60 @@ bool Format::operator !=(const Format &format) const */ int Format::xfIndex(bool generateIfNotValid) { - if (m_xf_index == -1 && generateIfNotValid) { //Generate a valid xf_index for this format + 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) { - m_xf_index = index; + d->xf_index = index; } else { - m_xf_index = s_xfFormats.size(); - s_xfFormats.append(this); + d->xf_index = d->s_xfFormats.size(); + d->s_xfFormats.append(this); } } - return m_xf_index; + return d->xf_index; } void Format::clearExtraInfos() { - m_xf_index = -1; - m_dxf_index = -1; - s_xfFormats.clear(); - s_dxfFormats.clear(); + Q_D(Format); + d->xf_index = -1; + d->dxf_index = -1; + d->s_xfFormats.clear(); + d->s_dxfFormats.clear(); } bool Format::isDxfFormat() const { - return m_is_dxf_fomat; + Q_D(const Format); + return d->is_dxf_fomat; +} + +int Format::theme() const +{ + Q_D(const Format); + return d->theme; +} + +int Format::colorIndexed() const +{ + Q_D(const Format); + return d->color_indexed; +} + +QList Format::xfFormats() +{ + return FormatPrivate::s_xfFormats; +} + +QList Format::dxfFormats() +{ + return FormatPrivate::s_dxfFormats; } } // namespace QXlsx diff --git a/src/xlsxformat.h b/src/xlsxformat.h index ae92ddc..ae646af 100755 --- a/src/xlsxformat.h +++ b/src/xlsxformat.h @@ -34,9 +34,12 @@ namespace QXlsx { class Styles; class Worksheet; +class WorksheetPrivate; +class FormatPrivate; class Format { + Q_DECLARE_PRIVATE(Format) public: enum FontScript { @@ -123,6 +126,8 @@ public: PatternGray0625 }; + ~Format(); + int numberFormat() const; void setNumberFormat(int format); @@ -201,129 +206,47 @@ public: private: friend class Styles; friend class Worksheet; + friend class WorksheetPrivate; Format(); - struct NumberData - { - int formatIndex; - } m_number; - - struct FontData - { - int size; - bool italic; - bool strikeOut; - QColor color; - bool bold; - FontScript scirpt; - FontUnderline underline; - bool outline; - bool shadow; - QString name; - int family; - int charset; - QString scheme; - int condense; - int extend; - - //helper member - bool _dirty; //key re-generated is need. - QByteArray _key; - bool _redundant; //same font already used by some other Formats - int _index; //index in the Font list - } m_font; - bool hasFont() const {return !m_font._redundant;} - void setFontRedundant(bool redundant) {m_font._redundant = redundant;} - int fontIndex() const {return m_font._index;} - void setFontIndex(int index) {m_font._index = index;} + bool hasFont() const; + void setFontRedundant(bool redundant); + int fontIndex() const; + void setFontIndex(int index); QByteArray fontKey() const; - int fontFamily() const{return m_font.family;} - bool fontShadow() const {return m_font.shadow;} - QString fontScheme() const {return m_font.scheme;} - - struct AlignmentData - { - HorizontalAlignment alignH; - VerticalAlignment alignV; - bool wrap; - int rotation; - int indent; - bool shinkToFit; - } m_alignment; + int fontFamily() const; + bool fontShadow() const; + QString fontScheme() const; bool alignmentChanged() const; QString horizontalAlignmentString() const; QString verticalAlignmentString() const; - struct BorderData - { - BorderStyle left; - BorderStyle right; - BorderStyle top; - BorderStyle bottom; - BorderStyle diagonal; - QColor leftColor; - QColor rightColor; - QColor topColor; - QColor bottomColor; - QColor diagonalColor; - DiagonalBorderType diagonalType; - - //helper member - bool _dirty; //key re-generated is need. - QByteArray _key; - bool _redundant; //same border already used by some other Formats - int _index; //index in the border list - } m_border; - QByteArray borderKey() const; - bool hasBorders() const {return !m_border._redundant;} - void setBorderRedundant(bool redundant) {m_border._redundant = redundant;} - int borderIndex() const {return m_border._index;} - void setBorderIndex(int index) {m_border._index = index;} - - struct FillData { - FillPattern pattern; - QColor bgColor; - QColor fgColor; - - //helper member - bool _dirty; //key re-generated is need. - QByteArray _key; - bool _redundant; //same border already used by some other Formats - int _index; //index in the border list - } m_fill; + bool hasBorders() const; + void setBorderRedundant(bool redundant); + int borderIndex() const; + void setBorderIndex(int index); QByteArray fillKey() const; - bool hasFill() const {return !m_fill._redundant;} - void setFillRedundant(bool redundant) {m_fill._redundant = redundant;} - int fillIndex() const {return m_fill._index;} - void setFillIndex(int index) {m_fill._index = index;} - - struct ProtectionData { - bool locked; - bool hidden; - } m_protection; + bool hasFill() const; + void setFillRedundant(bool redundant); + int fillIndex() const; + void setFillIndex(int index); - bool m_dirty; //The key re-generation is need. - QByteArray m_formatKey; QByteArray formatKey() const; - static QList s_xfFormats; - int m_xf_index; + static QList xfFormats(); + static QList dxfFormats(); int xfIndex(bool generateIfNotValid=true); //Generate index when first called. void clearExtraInfos(); - bool m_is_dxf_fomat; - int m_dxf_index; - static QList s_dxfFormats; bool isDxfFormat() const; - int m_theme; - int m_color_indexed; - int theme() const {return m_theme;} - int colorIndexed() const {return m_color_indexed;} + int theme() const; + int colorIndexed() const; + FormatPrivate * const d_ptr; }; } // namespace QXlsx diff --git a/src/xlsxformat_p.h b/src/xlsxformat_p.h new file mode 100644 index 0000000..d042b10 --- /dev/null +++ b/src/xlsxformat_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** Copyright (c) 2013 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXFORMAT_P_H +#define XLSXFORMAT_P_H +#include "xlsxformat.h" + +namespace QXlsx { + +struct NumberData +{ + NumberData() : formatIndex(0) {} + + int formatIndex; +}; + +struct FontData +{ + FontData() : + size(11), italic(false), strikeOut(false), color(QColor()), bold(false) + , scirpt(Format::FontScriptNormal), underline(Format::FontUnderlineNone) + , outline(false), shadow(false), name("Calibri"), family(2), charset(0) + , scheme("minor"), condense(0), extend(0) + , _dirty(true), _redundant(false), _index(-1) + + {} + + int size; + bool italic; + bool strikeOut; + QColor color; + bool bold; + Format::FontScript scirpt; + Format::FontUnderline underline; + bool outline; + bool shadow; + QString name; + int family; + int charset; + QString scheme; + int condense; + int extend; + + //helper member + bool _dirty; //key re-generated is need. + QByteArray _key; + bool _redundant; //same font already used by some other Formats + int _index; //index in the Font list +}; + +struct AlignmentData +{ + AlignmentData() : + alignH(Format::AlignHGeneral), alignV(Format::AlignBottom) + , wrap(false), rotation(0), indent(0), shinkToFit(false) + {} + + Format::HorizontalAlignment alignH; + Format::VerticalAlignment alignV; + bool wrap; + int rotation; + int indent; + bool shinkToFit; +}; + +struct BorderData +{ + 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) + {} + + Format::BorderStyle left; + Format::BorderStyle right; + Format::BorderStyle top; + Format::BorderStyle bottom; + Format::BorderStyle diagonal; + QColor leftColor; + QColor rightColor; + QColor topColor; + QColor bottomColor; + QColor diagonalColor; + Format::DiagonalBorderType diagonalType; + + //helper member + bool _dirty; //key re-generated is need. + QByteArray _key; + bool _redundant; //same border already used by some other Formats + int _index; //index in the border list +}; + +struct FillData { + FillData() : + pattern(Format::PatternNone) + ,_dirty(true), _redundant(false), _index(-1) + {} + + Format::FillPattern pattern; + QColor bgColor; + QColor fgColor; + + //helper member + bool _dirty; //key re-generated is need. + QByteArray _key; + bool _redundant; //same border already used by some other Formats + int _index; //index in the border list +}; + +struct ProtectionData { + ProtectionData() : + locked(false), hidden(false) + {} + + bool locked; + bool hidden; +}; + +class FormatPrivate +{ + Q_DECLARE_PUBLIC(Format) +public: + FormatPrivate(Format *p); + + NumberData numberData; + FontData fontData; + AlignmentData alignmentData; + BorderData borderData; + FillData fillData; + ProtectionData protectionData; + + bool dirty; //The key re-generation is need. + QByteArray formatKey; + + static QList s_xfFormats; + int xf_index; + + static QList s_dxfFormats; + bool is_dxf_fomat; + int dxf_index; + + int theme; + int color_indexed; + + Format *q_ptr; +}; + +} + +#endif // XLSXFORMAT_P_H diff --git a/src/xlsxstyles.cpp b/src/xlsxstyles.cpp index 943c079..4e37ed9 100755 --- a/src/xlsxstyles.cpp +++ b/src/xlsxstyles.cpp @@ -60,8 +60,8 @@ Format *Styles::addFormat() */ void Styles::prepareStyles() { - m_xf_formats = Format::s_xfFormats; - m_dxf_formats = Format::s_dxfFormats; + m_xf_formats = Format::xfFormats(); + m_dxf_formats = Format::dxfFormats(); if (m_xf_formats.isEmpty()) m_xf_formats.append(this->addFormat()); diff --git a/src/xlsxworkbook.cpp b/src/xlsxworkbook.cpp index 0930424..67fcbd4 100755 --- a/src/xlsxworkbook.cpp +++ b/src/xlsxworkbook.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ #include "xlsxworkbook.h" +#include "xlsxworkbook_p.h" #include "xlsxsharedstrings_p.h" #include "xlsxworksheet.h" #include "xlsxstyles_p.h" @@ -32,44 +33,52 @@ namespace QXlsx { -Workbook::Workbook(QObject *parent) : - QObject(parent) +WorkbookPrivate::WorkbookPrivate(Workbook *q) : + q_ptr(q) { - m_sharedStrings = new SharedStrings(this); - m_styles = new Styles(this); - + sharedStrings = new SharedStrings(q); + styles = new Styles(q); + + x_window = 240; + y_window = 15; + window_width = 16095; + window_height = 9660; + + strings_to_numbers_enabled = false; + date1904 = false; + activesheet = 0; + firstsheet = 0; + table_count = 0; +} - m_x_window = 240; - m_y_window = 15; - m_window_width = 16095; - m_window_height = 9660; +Workbook::Workbook(QObject *parent) : + QObject(parent), d_ptr(new WorkbookPrivate(this)) +{ - m_strings_to_numbers_enabled = false; - m_date1904 = false; - m_activesheet = 0; - m_firstsheet = 0; - m_table_count = 0; } Workbook::~Workbook() { + delete d_ptr; } void Workbook::save(const QString &name) { + Q_D(Workbook); + //Add a default worksheet if non have been added. - if (m_worksheets.size() == 0) + if (d->worksheets.size() == 0) addWorksheet(); //Ensure that at least one worksheet has been selected. - if (m_activesheet == 0) { - m_worksheets[0]->setHidden(false); - m_worksheets[0]->setSelected(true); + if (d->activesheet == 0) { + d->worksheets[0]->setHidden(false); + d->worksheets[0]->setSelected(true); } //Set the active sheet - foreach (Worksheet *sheet, m_worksheets) { - if (sheet->index() == m_activesheet) + foreach (Worksheet *sheet, d->worksheets) { + if (sheet->index() == d->activesheet) sheet->setActived(true); } @@ -80,7 +89,8 @@ void Workbook::save(const QString &name) bool Workbook::isDate1904() const { - return m_date1904; + Q_D(const Workbook); + return d->date1904; } /* @@ -92,7 +102,8 @@ bool Workbook::isDate1904() const */ void Workbook::setDate1904(bool date1904) { - m_date1904 = date1904; + Q_D(Workbook); + d->date1904 = date1904; } /* @@ -104,12 +115,14 @@ void Workbook::setDate1904(bool date1904) */ void Workbook::setStringsToNumbersEnabled(bool enable) { - m_strings_to_numbers_enabled = enable; + Q_D(Workbook); + d->strings_to_numbers_enabled = enable; } bool Workbook::isStringsToNumbersEnabled() const { - return m_strings_to_numbers_enabled; + Q_D(const Workbook); + return d->strings_to_numbers_enabled; } void Workbook::defineName(const QString &name, const QString &formula) @@ -119,38 +132,45 @@ void Workbook::defineName(const QString &name, const QString &formula) Worksheet *Workbook::addWorksheet(const QString &name) { + Q_D(Workbook); + QString worksheetName = name; - int index = m_worksheets.size()+1; + int index = d->worksheets.size()+1; if (name.isEmpty()) worksheetName = QString("Sheet%1").arg(index); Worksheet *sheet = new Worksheet(worksheetName, index, this); - m_worksheets.append(sheet); + d->worksheets.append(sheet); return sheet; } Format *Workbook::addFormat() { - return m_styles->addFormat(); + Q_D(Workbook); + return d->styles->addFormat(); } QList Workbook::worksheets() const { - return m_worksheets; + Q_D(const Workbook); + return d->worksheets; } SharedStrings *Workbook::sharedStrings() { - return m_sharedStrings; + Q_D(Workbook); + return d->sharedStrings; } Styles *Workbook::styles() { - return m_styles; + Q_D(Workbook); + return d->styles; } void Workbook::saveToXmlFile(QIODevice *device) { + Q_D(Workbook); XmlStreamWriter writer(device); writer.writeStartDocument("1.0", true); @@ -166,26 +186,26 @@ void Workbook::saveToXmlFile(QIODevice *device) // writer.writeAttribute("codeName", "{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}"); writer.writeEmptyElement("workbookPr"); - if (m_date1904) + if (d->date1904) writer.writeAttribute("date1904", "1"); writer.writeAttribute("defaultThemeVersion", "124226"); writer.writeStartElement("bookViews"); writer.writeEmptyElement("workbookView"); - writer.writeAttribute("xWindow", QString::number(m_x_window)); - writer.writeAttribute("yWindow", QString::number(m_y_window)); - writer.writeAttribute("windowWidth", QString::number(m_window_width)); - writer.writeAttribute("windowHeight", QString::number(m_window_height)); + writer.writeAttribute("xWindow", QString::number(d->x_window)); + writer.writeAttribute("yWindow", QString::number(d->y_window)); + writer.writeAttribute("windowWidth", QString::number(d->window_width)); + writer.writeAttribute("windowHeight", QString::number(d->window_height)); //Store the firstSheet when it isn't the default - if (m_firstsheet > 0) - writer.writeAttribute("firstSheet", QString::number(m_firstsheet + 1)); + if (d->firstsheet > 0) + writer.writeAttribute("firstSheet", QString::number(d->firstsheet + 1)); //Store the activeTab when it isn't the first sheet - if (m_activesheet > 0) - writer.writeAttribute("activeTab", QString::number(m_activesheet)); + if (d->activesheet > 0) + writer.writeAttribute("activeTab", QString::number(d->activesheet)); writer.writeEndElement();//bookviews writer.writeStartElement("sheets"); - foreach (Worksheet *sheet, m_worksheets) { + foreach (Worksheet *sheet, d->worksheets) { writer.writeEmptyElement("sheet"); writer.writeAttribute("name", sheet->name()); writer.writeAttribute("sheetId", QString::number(sheet->index())); diff --git a/src/xlsxworkbook.h b/src/xlsxworkbook.h index 4c727ed..d41f2d8 100755 --- a/src/xlsxworkbook.h +++ b/src/xlsxworkbook.h @@ -37,13 +37,16 @@ class SharedStrings; class Styles; class Package; +class WorkbookPrivate; class Workbook : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(Workbook) public: Workbook(QObject *parent=0); ~Workbook(); + QList worksheets() const; Worksheet *addWorksheet(const QString &name = QString()); Format *addFormat(); // void addChart(); @@ -59,25 +62,11 @@ private: friend class Package; friend class Worksheet; - QList worksheets() const; SharedStrings *sharedStrings(); Styles *styles(); void saveToXmlFile(QIODevice *device); - SharedStrings *m_sharedStrings; - QList m_worksheets; - Styles *m_styles; - bool m_strings_to_numbers_enabled; - bool m_date1904; - - int m_x_window; - int m_y_window; - int m_window_width; - int m_window_height; - - int m_activesheet; - int m_firstsheet; - int m_table_count; + WorkbookPrivate * const d_ptr; }; } //QXlsx diff --git a/src/xlsxworkbook_p.h b/src/xlsxworkbook_p.h new file mode 100644 index 0000000..81eb502 --- /dev/null +++ b/src/xlsxworkbook_p.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** Copyright (c) 2013 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXWORKBOOK_P_H +#define XLSXWORKBOOK_P_H +#include "xlsxworkbook.h" + +namespace QXlsx { + +class WorkbookPrivate +{ + Q_DECLARE_PUBLIC(Workbook) +public: + WorkbookPrivate(Workbook *q); + + Workbook *q_ptr; + + SharedStrings *sharedStrings; + QList worksheets; + Styles *styles; + + bool strings_to_numbers_enabled; + bool date1904; + + int x_window; + int y_window; + int window_width; + int window_height; + + int activesheet; + int firstsheet; + int table_count; +}; + +} + +#endif // XLSXWORKBOOK_P_H diff --git a/src/xlsxworksheet.cpp b/src/xlsxworksheet.cpp index 54d6bd0..2abcb7c 100755 --- a/src/xlsxworksheet.cpp +++ b/src/xlsxworksheet.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ #include "xlsxworksheet.h" +#include "xlsxworksheet_p.h" #include "xlsxworkbook.h" #include "xlsxformat.h" #include "xlsxutility_p.h" @@ -39,55 +40,157 @@ namespace QXlsx { -struct XlsxCellData +WorksheetPrivate::WorksheetPrivate(Worksheet *p) : + q_ptr(p) { - enum CellDataType { - Blank, - String, - Number, - Formula, - ArrayFormula, - Boolean, - DateTime - }; - XlsxCellData(const QVariant &data=QVariant(), CellDataType type=Blank, Format *format=0) : - value(data), dataType(type), format(format) - { + xls_rowmax = 1048576; + xls_colmax = 16384; + xls_strmax = 32767; + dim_rowmin = INT32_MAX; + dim_rowmax = INT32_MIN; + dim_colmin = INT32_MAX; + dim_colmax = INT32_MIN; + previous_row = 0; + + outline_row_level = 0; + outline_col_level = 0; + + default_row_height = 15; + default_row_zeroed = false; + + hidden = false; + selected = false; + actived = false; + right_to_left = false; + show_zeros = true; +} + +WorksheetPrivate::~WorksheetPrivate() +{ + typedef QMap RowMap; + foreach (RowMap row, cellTable) { + foreach (XlsxCellData *item, row) + delete item; + } + + foreach (XlsxRowInfo *row, rowsInfo) + delete row; + + foreach (XlsxColumnInfo *col, colsInfo) + delete col; +} + +/* + Calculate the "spans" attribute of the tag. This is an + XLSX optimisation and isn't strictly required. However, it + makes comparing files easier. The span is the same for each + block of 16 rows. + */ +void WorksheetPrivate::calculateSpans() +{ + row_spans.clear(); + int span_min = INT32_MAX; + int span_max = INT32_MIN; + + for (int row_num = dim_rowmin; row_num <= dim_rowmax; row_num++) { + if (cellTable.contains(row_num)) { + for (int col_num = dim_colmin; col_num <= dim_colmax; col_num++) { + if (cellTable[row_num].contains(col_num)) { + if (span_max == INT32_MIN) { + span_min = col_num; + span_max = col_num; + } else { + if (col_num < span_min) + span_min = col_num; + if (col_num > span_max) + span_max = col_num; + } + } + } + } + if (comments.contains(row_num)) { + for (int col_num = dim_colmin; col_num <= dim_colmax; col_num++) { + if (comments[row_num].contains(col_num)) { + if (span_max == INT32_MIN) { + span_min = col_num; + span_max = col_num; + } else { + if (col_num < span_min) + span_min = col_num; + if (col_num > span_max) + span_max = col_num; + } + } + } + } + + if ((row_num + 1)%16 == 0 || row_num == dim_rowmax) { + int span_index = row_num / 16; + if (span_max != INT32_MIN) { + span_min += 1; + span_max += 1; + row_spans[span_index] = QString("%1:%2").arg(span_min).arg(span_max); + span_max = INT32_MIN; + } + } } +} - QVariant value; - QString formula; - CellDataType dataType; - Format *format; -}; -struct XlsxRowInfo +QString WorksheetPrivate::generateDimensionString() { - XlsxRowInfo(double height, Format *format, bool hidden) : - height(height), format(format), hidden(hidden) - { + if (dim_rowmax == INT32_MIN && dim_colmax == INT32_MIN) { + //If the max dimensions are equal to INT32_MIN, then no dimension have been set + //and we use the default "A1" + return "A1"; + } + if (dim_rowmax == INT32_MIN) { + //row dimensions aren't set but the column dimensions are set + if (dim_colmin == dim_colmax) { + //The dimensions are a single cell and not a range + return xl_rowcol_to_cell(0, dim_colmin); + } else { + const QString cell_1 = xl_rowcol_to_cell(0, dim_colmin); + const QString cell_2 = xl_rowcol_to_cell(0, dim_colmax); + return cell_1 + ":" + cell_2; + } } - double height; - Format *format; - bool hidden; -}; + if (dim_rowmin == dim_rowmax && dim_colmin == dim_colmax) { + //Single cell + return xl_rowcol_to_cell(dim_rowmin, dim_rowmin); + } + + QString cell_1 = xl_rowcol_to_cell(dim_rowmin, dim_colmin); + QString cell_2 = xl_rowcol_to_cell(dim_rowmax, dim_colmax); + return cell_1 + ":" + cell_2; +} -struct XlsxColumnInfo +/* + Check that row and col are valid and store the max and min + values for use in other methods/elements. The ignore_row / + ignore_col flags is used to indicate that we wish to perform + the dimension check without storing the value. The ignore + flags are use by setRow() and dataValidate. +*/ +int WorksheetPrivate::checkDimensions(int row, int col, bool ignore_row, bool ignore_col) { - 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) - { + if (row >= xls_rowmax || col >= xls_colmax) + return -1; + if (!ignore_row) { + if (row < dim_rowmin) dim_rowmin = row; + if (row > dim_rowmax) dim_rowmax = row; + } + if (!ignore_col) { + if (col < dim_colmin) dim_colmin = col; + if (col > dim_colmax) dim_colmax = col; } - int column_min; - int column_max; - double width; - Format *format; - bool hidden; -}; + + return 0; +} /*! * \brief Worksheet::Worksheet @@ -96,44 +199,16 @@ struct XlsxColumnInfo * \param parent */ Worksheet::Worksheet(const QString &name, int index, Workbook *parent) : - QObject(parent), m_workbook(parent), m_name(name), m_index(index) + QObject(parent), d_ptr(new WorksheetPrivate(this)) { - m_xls_rowmax = 1048576; - m_xls_colmax = 16384; - m_xls_strmax = 32767; - m_dim_rowmin = INT32_MAX; - m_dim_rowmax = INT32_MIN; - m_dim_colmin = INT32_MAX; - m_dim_colmax = INT32_MIN; - - m_previous_row = 0; - - m_outline_row_level = 0; - m_outline_col_level = 0; - - m_default_row_height = 15; - m_default_row_zeroed = false; - - m_hidden = false; - m_selected = false; - m_actived = false; - m_right_to_left = false; - m_show_zeros = true; + d_ptr->name = name; + d_ptr->index = index; + d_ptr->workbook = parent; } 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; + delete d_ptr; } bool Worksheet::isChartsheet() const @@ -143,59 +218,73 @@ bool Worksheet::isChartsheet() const QString Worksheet::name() const { - return m_name; + Q_D(const Worksheet); + return d->name; } int Worksheet::index() const { - return m_index; + Q_D(const Worksheet); + return d->index; } bool Worksheet::isHidden() const { - return m_hidden; + Q_D(const Worksheet); + return d->hidden; } bool Worksheet::isSelected() const { - return m_selected; + Q_D(const Worksheet); + return d->selected; } bool Worksheet::isActived() const { - return m_actived; + Q_D(const Worksheet); + return d->actived; } void Worksheet::setHidden(bool hidden) { - m_hidden = hidden; + Q_D(Worksheet); + d->hidden = hidden; } void Worksheet::setSelected(bool select) { - m_selected = select; + Q_D(Worksheet); + d->selected = select; } void Worksheet::setActived(bool act) { - m_actived = act; + Q_D(Worksheet); + d->actived = act; } void Worksheet::setRightToLeft(bool enable) { - m_right_to_left = enable; + Q_D(Worksheet); + d->right_to_left = enable; } void Worksheet::setZeroValuesHidden(bool enable) { - m_show_zeros = !enable; + Q_D(Worksheet); + d->show_zeros = !enable; } int Worksheet::write(int row, int column, const QVariant &value, Format *format) { + Q_D(Worksheet); bool ok; int ret = 0; + if (d->checkDimensions(row, column)) + return -1; + if (value.isNull()) { //blank ret = writeBlank(row, column, format); } else if (value.type() == QMetaType::Bool) { //Bool @@ -203,7 +292,7 @@ int Worksheet::write(int row, int column, const QVariant &value, Format *format) } else if (value.toDateTime().isValid()) { //DateTime ret = writeDateTime(row, column, value.toDateTime(), format); } else if (value.toDouble(&ok), ok) { //Number - if (!m_workbook->isStringsToNumbersEnabled() && value.type() == QMetaType::QString) { + if (!d->workbook->isStringsToNumbersEnabled() && value.type() == QMetaType::QString) { //Don't convert string to number if the flag not enabled. ret = writeString(row, column, value.toString(), format); } else { @@ -240,37 +329,40 @@ int Worksheet::write(const QString row_column, const QVariant &value, Format *fo int Worksheet::writeString(int row, int column, const QString &value, Format *format) { + Q_D(Worksheet); int error = 0; QString content = value; - if (checkDimensions(row, column)) + if (d->checkDimensions(row, column)) return -1; - if (value.size() > m_xls_strmax) { - content = value.left(m_xls_strmax); + if (value.size() > d->xls_strmax) { + content = value.left(d->xls_strmax); error = -2; } - SharedStrings *sharedStrings = m_workbook->sharedStrings(); + SharedStrings *sharedStrings = d->workbook->sharedStrings(); int index = sharedStrings->addSharedString(content); - m_cellTable[row][column] = new XlsxCellData(index, XlsxCellData::String, format); + d->cellTable[row][column] = new XlsxCellData(index, XlsxCellData::String, format); return error; } int Worksheet::writeNumber(int row, int column, double value, Format *format) { - if (checkDimensions(row, column)) + Q_D(Worksheet); + if (d->checkDimensions(row, column)) return -1; - m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format); + d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format); return 0; } int Worksheet::writeFormula(int row, int column, const QString &content, Format *format, double result) { + Q_D(Worksheet); int error = 0; QString formula = content; - if (checkDimensions(row, column)) + if (d->checkDimensions(row, column)) return -1; //Remove the formula '=' sign if exists @@ -279,64 +371,44 @@ int Worksheet::writeFormula(int row, int column, const QString &content, Format XlsxCellData *data = new XlsxCellData(result, XlsxCellData::Formula, format); data->formula = formula; - m_cellTable[row][column] = data; + d->cellTable[row][column] = data; return error; } int Worksheet::writeBlank(int row, int column, Format *format) { - if (checkDimensions(row, column)) + Q_D(Worksheet); + if (d->checkDimensions(row, column)) return -1; - m_cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format); + d->cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format); return 0; } int Worksheet::writeBool(int row, int column, bool value, Format *format) { - if (checkDimensions(row, column)) + Q_D(Worksheet); + if (d->checkDimensions(row, column)) return -1; - m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format); + d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format); return 0; } int Worksheet::writeDateTime(int row, int column, const QDateTime &dt, Format *format) { - if (checkDimensions(row, column)) + Q_D(Worksheet); + if (d->checkDimensions(row, column)) return -1; - m_cellTable[row][column] = new XlsxCellData(dt, XlsxCellData::DateTime, format); - return 0; -} - -/* - Check that row and col are valid and store the max and min - values for use in other methods/elements. The ignore_row / - ignore_col flags is used to indicate that we wish to perform - the dimension check without storing the value. The ignore - flags are use by setRow() and dataValidate. -*/ -int Worksheet::checkDimensions(int row, int col, bool ignore_row, bool ignore_col) -{ - if (row >= m_xls_rowmax || col >= m_xls_colmax) - return -1; - - if (!ignore_row) { - if (row < m_dim_rowmin) m_dim_rowmin = row; - if (row > m_dim_rowmax) m_dim_rowmax = row; - } - if (!ignore_col) { - if (col < m_dim_colmin) m_dim_colmin = col; - if (col > m_dim_colmax) m_dim_colmax = col; - } - + d->cellTable[row][column] = new XlsxCellData(dt, XlsxCellData::DateTime, format); return 0; } void Worksheet::saveToXmlFile(QIODevice *device) { + Q_D(Worksheet); XmlStreamWriter writer(device); writer.writeStartDocument("1.0", true); @@ -350,38 +422,38 @@ void Worksheet::saveToXmlFile(QIODevice *device) // writer.writeAttribute("mc:Ignorable", "x14ac"); writer.writeStartElement("dimension"); - writer.writeAttribute("ref", generateDimensionString()); + writer.writeAttribute("ref", d->generateDimensionString()); writer.writeEndElement();//dimension writer.writeStartElement("sheetViews"); writer.writeStartElement("sheetView"); - if (!m_show_zeros) + if (!d->show_zeros) writer.writeAttribute("showZeros", "0"); - if (m_right_to_left) + if (d->right_to_left) writer.writeAttribute("rightToLeft", "1"); - if (m_selected) + if (d->selected) writer.writeAttribute("tabSelected", "1"); writer.writeAttribute("workbookViewId", "0"); writer.writeEndElement();//sheetView writer.writeEndElement();//sheetViews writer.writeStartElement("sheetFormatPr"); - writer.writeAttribute("defaultRowHeight", QString::number(m_default_row_height)); - if (m_default_row_height != 15) + writer.writeAttribute("defaultRowHeight", QString::number(d->default_row_height)); + if (d->default_row_height != 15) writer.writeAttribute("customHeight", "1"); - if (m_default_row_zeroed) + if (d->default_row_zeroed) writer.writeAttribute("zeroHeight", "1"); - if (m_outline_row_level) - writer.writeAttribute("outlineLevelRow", QString::number(m_outline_row_level)); - if (m_outline_col_level) - writer.writeAttribute("outlineLevelCol", QString::number(m_outline_col_level)); + if (d->outline_row_level) + writer.writeAttribute("outlineLevelRow", QString::number(d->outline_row_level)); + if (d->outline_col_level) + writer.writeAttribute("outlineLevelCol", QString::number(d->outline_col_level)); //for Excel 2010 // writer.writeAttribute("x14ac:dyDescent", "0.25"); writer.writeEndElement();//sheetFormatPr - if (!m_colsInfo.isEmpty()) { + if (!d->colsInfo.isEmpty()) { writer.writeStartElement("cols"); - foreach (XlsxColumnInfo *col_info, m_colsInfo) { + foreach (XlsxColumnInfo *col_info, d->colsInfo) { writer.writeStartElement("col"); writer.writeAttribute("min", QString::number(col_info->column_min)); writer.writeAttribute("max", QString::number(col_info->column_max)); @@ -398,10 +470,10 @@ void Worksheet::saveToXmlFile(QIODevice *device) } writer.writeStartElement("sheetData"); - if (m_dim_rowmax == INT32_MIN) { + if (d->dim_rowmax == INT32_MIN) { //If the max dimensions are equal to INT32_MIN, then there is no data to write } else { - writeSheetData(writer); + d->writeSheetData(writer); } writer.writeEndElement();//sheetData @@ -409,59 +481,29 @@ void Worksheet::saveToXmlFile(QIODevice *device) writer.writeEndDocument(); } -QString Worksheet::generateDimensionString() -{ - if (m_dim_rowmax == INT32_MIN && m_dim_colmax == INT32_MIN) { - //If the max dimensions are equal to INT32_MIN, then no dimension have been set - //and we use the default "A1" - return "A1"; - } - - if (m_dim_rowmax == INT32_MIN) { - //row dimensions aren't set but the column dimensions are set - if (m_dim_colmin == m_dim_colmax) { - //The dimensions are a single cell and not a range - return xl_rowcol_to_cell(0, m_dim_colmin); - } else { - const QString cell_1 = xl_rowcol_to_cell(0, m_dim_colmin); - const QString cell_2 = xl_rowcol_to_cell(0, m_dim_colmax); - return cell_1 + ":" + cell_2; - } - } - - if (m_dim_rowmin == m_dim_rowmax && m_dim_colmin == m_dim_colmax) { - //Single cell - return xl_rowcol_to_cell(m_dim_rowmin, m_dim_rowmin); - } - - QString cell_1 = xl_rowcol_to_cell(m_dim_rowmin, m_dim_colmin); - QString cell_2 = xl_rowcol_to_cell(m_dim_rowmax, m_dim_colmax); - return cell_1 + ":" + cell_2; -} - -void Worksheet::writeSheetData(XmlStreamWriter &writer) +void WorksheetPrivate::writeSheetData(XmlStreamWriter &writer) { calculateSpans(); - for (int row_num = m_dim_rowmin; row_num <= m_dim_rowmax; row_num++) { - if (!(m_cellTable.contains(row_num) || m_comments.contains(row_num) || m_rowsInfo.contains(row_num))) { + for (int row_num = dim_rowmin; row_num <= dim_rowmax; row_num++) { + if (!(cellTable.contains(row_num) || comments.contains(row_num) || rowsInfo.contains(row_num))) { //Only process rows with cell data / comments / formatting continue; } int span_index = row_num / 16; QString span; - if (m_row_spans.contains(span_index)) - span = m_row_spans[span_index]; + if (row_spans.contains(span_index)) + span = row_spans[span_index]; - if (m_cellTable.contains(row_num)) { + if (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 (rowsInfo.contains(row_num)) { + XlsxRowInfo *rowInfo = rowsInfo[row_num]; if (rowInfo->format) { writer.writeAttribute("s", QString::number(rowInfo->format->xfIndex())); writer.writeAttribute("customFormat", "1"); @@ -474,13 +516,13 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer) writer.writeAttribute("hidden", "1"); } - for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { - if (m_cellTable[row_num].contains(col_num)) { - writeCellData(writer, row_num, col_num, m_cellTable[row_num][col_num]); + for (int col_num = dim_colmin; col_num <= dim_colmax; col_num++) { + if (cellTable[row_num].contains(col_num)) { + writeCellData(writer, row_num, col_num, cellTable[row_num][col_num]); } } writer.writeEndElement(); //row - } else if (m_comments.contains(row_num)){ + } else if (comments.contains(row_num)){ } else { @@ -488,7 +530,7 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer) } } -void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell) +void WorksheetPrivate::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); @@ -499,10 +541,10 @@ void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCel //Style used by the cell, row or col 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())); + else if (rowsInfo.contains(row) && rowsInfo[row]->format) + writer.writeAttribute("s", QString::number(rowsInfo[row]->format->xfIndex())); + else if (colsInfoHelper.contains(col) && colsInfoHelper[col]->format) + writer.writeAttribute("s", QString::number(colsInfoHelper[col]->format->xfIndex())); if (cell->dataType == XlsxCellData::String) { //cell->data: Index of the string in sharedStringTable @@ -527,91 +569,36 @@ void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCel //Ok, empty here. } else if (cell->dataType == XlsxCellData::DateTime) { QDateTime epoch(QDate(1899, 12, 31)); - if (m_workbook->isDate1904()) + if (workbook->isDate1904()) epoch = QDateTime(QDate(1904, 1, 1)); qint64 delta = epoch.msecsTo(cell->value.toDateTime()); double excel_time = delta / (1000*60*60*24); //Account for Excel erroneously treating 1900 as a leap year. - if (!m_workbook->isDate1904() && excel_time > 59) + if (!workbook->isDate1904() && excel_time > 59) excel_time += 1; writer.writeTextElement("v", QString::number(excel_time, 'g', 15)); } writer.writeEndElement(); //c } -/* - Calculate the "spans" attribute of the tag. This is an - XLSX optimisation and isn't strictly required. However, it - makes comparing files easier. The span is the same for each - block of 16 rows. - */ -void Worksheet::calculateSpans() -{ - m_row_spans.clear(); - int span_min = INT32_MAX; - int span_max = INT32_MIN; - - for (int row_num = m_dim_rowmin; row_num <= m_dim_rowmax; row_num++) { - if (m_cellTable.contains(row_num)) { - for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { - if (m_cellTable[row_num].contains(col_num)) { - if (span_max == INT32_MIN) { - span_min = col_num; - span_max = col_num; - } else { - if (col_num < span_min) - span_min = col_num; - if (col_num > span_max) - span_max = col_num; - } - } - } - } - if (m_comments.contains(row_num)) { - for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { - if (m_comments[row_num].contains(col_num)) { - if (span_max == INT32_MIN) { - span_min = col_num; - span_max = col_num; - } else { - if (col_num < span_min) - span_min = col_num; - if (col_num > span_max) - span_max = col_num; - } - } - } - } - - if ((row_num + 1)%16 == 0 || row_num == m_dim_rowmax) { - int span_index = row_num / 16; - if (span_max != INT32_MIN) { - span_min += 1; - span_max += 1; - m_row_spans[span_index] = QString("%1:%2").arg(span_min).arg(span_max); - span_max = INT32_MIN; - } - } - } -} - /* 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; + Q_D(Worksheet); + int min_col = d->dim_colmax == INT32_MIN ? 0 : d->dim_colmin; - if (checkDimensions(row, min_col)) + if (d->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; + if (d->rowsInfo.contains(row)) { + d->rowsInfo[row]->height = height; + d->rowsInfo[row]->format = format; + d->rowsInfo[row]->hidden = hidden; } else { - m_rowsInfo[row] = new XlsxRowInfo(height, format, hidden); + d->rowsInfo[row] = new XlsxRowInfo(height, format, hidden); } return true; } @@ -624,19 +611,20 @@ bool Worksheet::setRow(int row, double height, Format *format, bool hidden) */ bool Worksheet::setColumn(int colFirst, int colLast, double width, Format *format, bool hidden) { + Q_D(Worksheet); bool ignore_row = true; bool ignore_col = (format || (width && hidden)) ? false : true; - if (checkDimensions(0, colLast, ignore_row, ignore_col)) + if (d->checkDimensions(0, colLast, ignore_row, ignore_col)) return false; - if (checkDimensions(0, colFirst, ignore_row, ignore_col)) + if (d->checkDimensions(0, colFirst, ignore_row, ignore_col)) return false; XlsxColumnInfo *info = new XlsxColumnInfo(colFirst, colLast, width, format, hidden); - m_colsInfo.append(info); + d->colsInfo.append(info); for (int col=colFirst; col<=colLast; ++col) - m_colsInfoHelper[col] = info; + d->colsInfoHelper[col] = info; return true; } diff --git a/src/xlsxworksheet.h b/src/xlsxworksheet.h index 0820651..55587bb 100755 --- a/src/xlsxworksheet.h +++ b/src/xlsxworksheet.h @@ -38,13 +38,11 @@ class Workbook; class XmlStreamWriter; class Format; -struct XlsxCellData; -struct XlsxRowInfo; -struct XlsxColumnInfo; - +class WorksheetPrivate; class Worksheet : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(Worksheet) public: int write(const QString row_column, const QVariant &value, Format *format=0); int write(int row, int column, const QVariant &value, Format *format=0); @@ -77,44 +75,8 @@ private: void setSelected(bool select); void setActived(bool act); void saveToXmlFile(QIODevice *device); - 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, XlsxCellData *cell); - void calculateSpans(); - - Workbook *m_workbook; - 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; - int m_xls_strmax; - int m_dim_rowmin; - int m_dim_rowmax; - int m_dim_colmin; - int m_dim_colmax; - int m_previous_row; - - QMap m_row_spans; - - int m_outline_row_level; - int m_outline_col_level; - - int m_default_row_height; - bool m_default_row_zeroed; - QString m_name; - int m_index; - bool m_hidden; - bool m_selected; - bool m_actived; - bool m_right_to_left; - bool m_show_zeros; + WorksheetPrivate * const d_ptr; }; } //QXlsx diff --git a/src/xlsxworksheet_p.h b/src/xlsxworksheet_p.h new file mode 100644 index 0000000..e2d45a6 --- /dev/null +++ b/src/xlsxworksheet_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** Copyright (c) 2013 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXWORKSHEET_P_H +#define XLSXWORKSHEET_P_H +#include "xlsxworksheet.h" + +namespace QXlsx { + +struct XlsxCellData +{ + enum CellDataType { + Blank, + String, + Number, + Formula, + ArrayFormula, + Boolean, + DateTime + }; + 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; +}; + +class WorksheetPrivate +{ + Q_DECLARE_PUBLIC(Worksheet) +public: + WorksheetPrivate(Worksheet *p); + ~WorksheetPrivate(); + int checkDimensions(int row, int col, bool ignore_row=false, bool ignore_col=false); + QString generateDimensionString(); + void calculateSpans(); + void writeSheetData(XmlStreamWriter &writer); + void writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell); + + Workbook *workbook; + QMap > cellTable; + QMap > comments; + QMap rowsInfo; + QList colsInfo; + QMap colsInfoHelper;//Not owns the XlsxColumnInfo + + int xls_rowmax; + int xls_colmax; + int xls_strmax; + int dim_rowmin; + int dim_rowmax; + int dim_colmin; + int dim_colmax; + int previous_row; + + QMap row_spans; + + int outline_row_level; + int outline_col_level; + + int default_row_height; + bool default_row_zeroed; + + QString name; + int index; + bool hidden; + bool selected; + bool actived; + bool right_to_left; + bool show_zeros; + + Worksheet *q_ptr; +}; + +} +#endif // XLSXWORKSHEET_P_H