Browse Source

Refactor: D-Pointer used for public classes

master
Debao Zhang 11 years ago
parent
commit
a563809f77
  1. 5
      src/qtxlsxwriter.pri
  2. 619
      src/xlsxformat.cpp
  3. 129
      src/xlsxformat.h
  4. 172
      src/xlsxformat_p.h
  5. 4
      src/xlsxstyles.cpp
  6. 100
      src/xlsxworkbook.cpp
  7. 19
      src/xlsxworkbook.h
  8. 58
      src/xlsxworkbook_p.h
  9. 496
      src/xlsxworksheet.cpp
  10. 44
      src/xlsxworksheet.h
  11. 129
      src/xlsxworksheet_p.h

5
src/qtxlsxwriter.pri

@ -15,7 +15,10 @@ HEADERS += $$PWD/xlsxdocprops_p.h \
$$PWD/xlsxstyles_p.h \ $$PWD/xlsxstyles_p.h \
$$PWD/xlsxworksheet.h \ $$PWD/xlsxworksheet.h \
$$PWD/zipwriter_p.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 \ SOURCES += $$PWD/xlsxdocprops.cpp \
$$PWD/xlsxrelationships.cpp \ $$PWD/xlsxrelationships.cpp \

619
src/xlsxformat.cpp

@ -23,316 +23,353 @@
** **
****************************************************************************/ ****************************************************************************/
#include "xlsxformat.h" #include "xlsxformat.h"
#include "xlsxformat_p.h"
#include <QDataStream> #include <QDataStream>
#include <QDebug> #include <QDebug>
namespace QXlsx { namespace QXlsx {
QList<Format *> Format::s_xfFormats; QList<Format *> FormatPrivate::s_xfFormats;
QList<Format *> Format::s_dxfFormats; QList<Format *> FormatPrivate::s_dxfFormats;
Format::Format() FormatPrivate::FormatPrivate(Format *p) :
{ q_ptr(p)
m_number.formatIndex = 0; {
dirty = true;
m_font.bold = false;
m_font.color = QColor(Qt::black); is_dxf_fomat = false;
m_font.italic = false; xf_index = -1;
m_font.name = "Calibri"; dxf_index = -1;
m_font.scirpt = FontScriptNormal;
m_font.size = 11; theme = 0;
m_font.strikeOut = false; color_indexed = 0;
m_font.underline = FontUnderlineNone; }
m_font.shadow = false;
m_font.outline = false; Format::Format() :
m_font.family = 2; d_ptr(new FormatPrivate(this))
m_font.scheme = "minor"; {
m_font.charset = 0;
m_font.condense = 0; }
m_font.extend = 0;
m_font._dirty = true; Format::~Format()
m_font._redundant = false; {
m_font._index = -1; delete d_ptr;
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;
} }
int Format::numberFormat() const int Format::numberFormat() const
{ {
return m_number.formatIndex; Q_D(const Format);
return d->numberData.formatIndex;
} }
void Format::setNumberFormat(int format) void Format::setNumberFormat(int format)
{ {
m_dirty = true; Q_D(Format);
m_number.formatIndex = format; d->dirty = true;
d->numberData.formatIndex = format;
} }
int Format::fontSize() const int Format::fontSize() const
{ {
return m_font.size; Q_D(const Format);
return d->fontData.size;
} }
void Format::setFontSize(int size) void Format::setFontSize(int size)
{ {
m_font.size = size; Q_D(Format);
m_font._dirty = true; d->fontData.size = size;
d->fontData._dirty = true;
} }
bool Format::fontItalic() const bool Format::fontItalic() const
{ {
return m_font.italic; Q_D(const Format);
return d->fontData.italic;
} }
void Format::setFontItalic(bool italic) void Format::setFontItalic(bool italic)
{ {
m_font.italic = italic; Q_D(Format);
m_font._dirty = true; d->fontData.italic = italic;
d->fontData._dirty = true;
} }
bool Format::fontStrikeOut() const bool Format::fontStrikeOut() const
{ {
return m_font.strikeOut; Q_D(const Format);
return d->fontData.strikeOut;
} }
void Format::setFontStrikeOut(bool strikeOut) void Format::setFontStrikeOut(bool strikeOut)
{ {
m_font.strikeOut = strikeOut; Q_D(Format);
m_font._dirty = true; d->fontData.strikeOut = strikeOut;
d->fontData._dirty = true;
} }
QColor Format::fontColor() const QColor Format::fontColor() const
{ {
return m_font.color; Q_D(const Format);
return d->fontData.color;
} }
void Format::setFontColor(const QColor &color) void Format::setFontColor(const QColor &color)
{ {
m_font.color = color; Q_D(Format);
m_font._dirty = true; d->fontData.color = color;
d->fontData._dirty = true;
} }
bool Format::fontBold() const bool Format::fontBold() const
{ {
return m_font.bold; Q_D(const Format);
return d->fontData.bold;
} }
void Format::setFontBold(bool bold) void Format::setFontBold(bool bold)
{ {
m_font.bold = bold; Q_D(Format);
m_font._dirty = true; d->fontData.bold = bold;
d->fontData._dirty = true;
} }
Format::FontScript Format::fontScript() const Format::FontScript Format::fontScript() const
{ {
return m_font.scirpt; Q_D(const Format);
return d->fontData.scirpt;
} }
void Format::setFontScript(FontScript script) void Format::setFontScript(FontScript script)
{ {
m_font.scirpt = script; Q_D(Format);
m_font._dirty = true; d->fontData.scirpt = script;
d->fontData._dirty = true;
} }
Format::FontUnderline Format::fontUnderline() const Format::FontUnderline Format::fontUnderline() const
{ {
return m_font.underline; Q_D(const Format);
return d->fontData.underline;
} }
void Format::setFontUnderline(FontUnderline underline) void Format::setFontUnderline(FontUnderline underline)
{ {
m_font.underline = underline; Q_D(Format);
m_font._dirty = true; d->fontData.underline = underline;
d->fontData._dirty = true;
} }
bool Format::fontOutline() const bool Format::fontOutline() const
{ {
return m_font.outline; Q_D(const Format);
return d->fontData.outline;
} }
void Format::setFontOutline(bool outline) void Format::setFontOutline(bool outline)
{ {
m_font.outline = outline; Q_D(Format);
m_font._dirty = true; d->fontData.outline = outline;
d->fontData._dirty = true;
} }
QString Format::fontName() const QString Format::fontName() const
{ {
return m_font.name; Q_D(const Format);
return d->fontData.name;
} }
void Format::setFontName(const QString &name) void Format::setFontName(const QString &name)
{ {
m_font.name = name; Q_D(Format);
m_font._dirty = true; 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 /* Internal
*/ */
QByteArray Format::fontKey() const QByteArray Format::fontKey() const
{ {
if (m_font._dirty) { Q_D(const Format);
if (d->fontData._dirty) {
QByteArray key; QByteArray key;
QDataStream stream(&key, QIODevice::WriteOnly); QDataStream stream(&key, QIODevice::WriteOnly);
stream<<m_font.bold<<m_font.charset<<m_font.color<<m_font.condense stream<<d->fontData.bold<<d->fontData.charset<<d->fontData.color<<d->fontData.condense
<<m_font.extend<<m_font.family<<m_font.italic<<m_font.name <<d->fontData.extend<<d->fontData.family<<d->fontData.italic<<d->fontData.name
<<m_font.outline<<m_font.scheme<<m_font.scirpt<<m_font.shadow <<d->fontData.outline<<d->fontData.scheme<<d->fontData.scirpt<<d->fontData.shadow
<<m_font.size<<m_font.strikeOut<<m_font.underline; <<d->fontData.size<<d->fontData.strikeOut<<d->fontData.underline;
const_cast<Format*>(this)->m_font._key = key; const_cast<FormatPrivate*>(d)->fontData._key = key;
const_cast<Format*>(this)->m_font._dirty = false; const_cast<FormatPrivate*>(d)->fontData._dirty = false;
const_cast<Format*>(this)->m_dirty = true; //Make sure formatKey() will be re-generated. const_cast<FormatPrivate*>(d)->dirty = true; //Make sure formatKey() will be re-generated.
} }
return m_font._key; return d->fontData._key;
} }
Format::HorizontalAlignment Format::horizontalAlignment() const Format::HorizontalAlignment Format::horizontalAlignment() const
{ {
return m_alignment.alignH; Q_D(const Format);
return d->alignmentData.alignH;
} }
void Format::setHorizontalAlignment(HorizontalAlignment align) 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)) { 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)) { || align == AlignHDistributed)) {
m_alignment.shinkToFit = false; d->alignmentData.shinkToFit = false;
} }
m_alignment.alignH = align; d->alignmentData.alignH = align;
m_dirty = true; d->dirty = true;
} }
Format::VerticalAlignment Format::verticalAlignment() const Format::VerticalAlignment Format::verticalAlignment() const
{ {
return m_alignment.alignV; Q_D(const Format);
return d->alignmentData.alignV;
} }
void Format::setVerticalAlignment(VerticalAlignment align) void Format::setVerticalAlignment(VerticalAlignment align)
{ {
m_alignment.alignV = align; Q_D(Format);
m_dirty = true; d->alignmentData.alignV = align;
d->dirty = true;
} }
bool Format::textWrap() const bool Format::textWrap() const
{ {
return m_alignment.wrap; Q_D(const Format);
return d->alignmentData.wrap;
} }
void Format::setTextWarp(bool wrap) void Format::setTextWarp(bool wrap)
{ {
if (wrap && m_alignment.shinkToFit) Q_D(Format);
m_alignment.shinkToFit = false; if (wrap && d->alignmentData.shinkToFit)
d->alignmentData.shinkToFit = false;
m_alignment.wrap = wrap; d->alignmentData.wrap = wrap;
m_dirty = true; d->dirty = true;
} }
int Format::rotation() const int Format::rotation() const
{ {
return m_alignment.rotation; Q_D(const Format);
return d->alignmentData.rotation;
} }
void Format::setRotation(int rotation) void Format::setRotation(int rotation)
{ {
m_alignment.rotation = rotation; Q_D(Format);
m_dirty = true; d->alignmentData.rotation = rotation;
d->dirty = true;
} }
int Format::indent() const int Format::indent() const
{ {
return m_alignment.indent; Q_D(const Format);
return d->alignmentData.indent;
} }
void Format::setIndent(int indent) void Format::setIndent(int indent)
{ {
if (indent && (m_alignment.alignH != AlignHGeneral Q_D(Format);
&& m_alignment.alignH != AlignLeft if (indent && (d->alignmentData.alignH != AlignHGeneral
&& m_alignment.alignH != AlignRight && d->alignmentData.alignH != AlignLeft
&& m_alignment.alignH != AlignHJustify)) { && d->alignmentData.alignH != AlignRight
m_alignment.alignH = AlignLeft; && d->alignmentData.alignH != AlignHJustify)) {
d->alignmentData.alignH = AlignLeft;
} }
m_alignment.indent = indent; d->alignmentData.indent = indent;
m_dirty = true; d->dirty = true;
} }
bool Format::shrinkToFit() const bool Format::shrinkToFit() const
{ {
return m_alignment.shinkToFit; Q_D(const Format);
return d->alignmentData.shinkToFit;
} }
void Format::setShrinkToFit(bool shink) void Format::setShrinkToFit(bool shink)
{ {
if (shink && m_alignment.wrap) Q_D(Format);
m_alignment.wrap = false; if (shink && d->alignmentData.wrap)
if (shink && (m_alignment.alignH == AlignHFill d->alignmentData.wrap = false;
|| m_alignment.alignH == AlignHJustify if (shink && (d->alignmentData.alignH == AlignHFill
|| m_alignment.alignH == AlignHDistributed)) { || d->alignmentData.alignH == AlignHJustify
m_alignment.alignH = AlignLeft; || d->alignmentData.alignH == AlignHDistributed)) {
d->alignmentData.alignH = AlignLeft;
} }
m_alignment.shinkToFit = shink; d->alignmentData.shinkToFit = shink;
m_dirty = true; d->dirty = true;
} }
bool Format::alignmentChanged() const bool Format::alignmentChanged() const
{ {
return m_alignment.alignH != AlignHGeneral Q_D(const Format);
|| m_alignment.alignV != AlignBottom return d->alignmentData.alignH != AlignHGeneral
|| m_alignment.indent != 0 || d->alignmentData.alignV != AlignBottom
|| m_alignment.wrap || d->alignmentData.indent != 0
|| m_alignment.rotation != 0 || d->alignmentData.wrap
|| m_alignment.shinkToFit; || d->alignmentData.rotation != 0
|| d->alignmentData.shinkToFit;
} }
QString Format::horizontalAlignmentString() const QString Format::horizontalAlignmentString() const
{ {
Q_D(const Format);
QString alignH; QString alignH;
switch (m_alignment.alignH) { switch (d->alignmentData.alignH) {
case Format::AlignLeft: case Format::AlignLeft:
alignH = "left"; alignH = "left";
break; break;
@ -362,8 +399,9 @@ QString Format::horizontalAlignmentString() const
QString Format::verticalAlignmentString() const QString Format::verticalAlignmentString() const
{ {
Q_D(const Format);
QString align; QString align;
switch (m_alignment.alignV) { switch (d->alignmentData.alignV) {
case AlignTop: case AlignTop:
align = "top"; align = "top";
break; break;
@ -400,236 +438,318 @@ void Format::setBorderColor(const QColor &color)
Format::BorderStyle Format::leftBorderStyle() const Format::BorderStyle Format::leftBorderStyle() const
{ {
return m_border.left; Q_D(const Format);
return d->borderData.left;
} }
void Format::setLeftBorderStyle(BorderStyle style) void Format::setLeftBorderStyle(BorderStyle style)
{ {
m_border.left = style; Q_D(Format);
m_border._dirty = true; d->borderData.left = style;
d->borderData._dirty = true;
} }
QColor Format::leftBorderColor() const QColor Format::leftBorderColor() const
{ {
return m_border.leftColor; Q_D(const Format);
return d->borderData.leftColor;
} }
void Format::setLeftBorderColor(const QColor &color) void Format::setLeftBorderColor(const QColor &color)
{ {
m_border.leftColor = color; Q_D(Format);
m_border._dirty = true; d->borderData.leftColor = color;
d->borderData._dirty = true;
} }
Format::BorderStyle Format::rightBorderStyle() const Format::BorderStyle Format::rightBorderStyle() const
{ {
return m_border.right; Q_D(const Format);
return d->borderData.right;
} }
void Format::setRightBorderStyle(BorderStyle style) void Format::setRightBorderStyle(BorderStyle style)
{ {
m_border.right = style; Q_D(Format);
m_border._dirty = true; d->borderData.right = style;
d->borderData._dirty = true;
} }
QColor Format::rightBorderColor() const QColor Format::rightBorderColor() const
{ {
return m_border.rightColor; Q_D(const Format);
return d->borderData.rightColor;
} }
void Format::setRightBorderColor(const QColor &color) void Format::setRightBorderColor(const QColor &color)
{ {
m_border.rightColor = color; Q_D(Format);
m_border._dirty = true; d->borderData.rightColor = color;
d->borderData._dirty = true;
} }
Format::BorderStyle Format::topBorderStyle() const Format::BorderStyle Format::topBorderStyle() const
{ {
return m_border.top; Q_D(const Format);
return d->borderData.top;
} }
void Format::setTopBorderStyle(BorderStyle style) void Format::setTopBorderStyle(BorderStyle style)
{ {
m_border.top = style; Q_D(Format);
m_border._dirty = true; d->borderData.top = style;
d->borderData._dirty = true;
} }
QColor Format::topBorderColor() const QColor Format::topBorderColor() const
{ {
return m_border.topColor; Q_D(const Format);
return d->borderData.topColor;
} }
void Format::setTopBorderColor(const QColor &color) void Format::setTopBorderColor(const QColor &color)
{ {
m_border.topColor = color; Q_D(Format);
m_border._dirty = true; d->borderData.topColor = color;
d->borderData._dirty = true;
} }
Format::BorderStyle Format::bottomBorderStyle() const Format::BorderStyle Format::bottomBorderStyle() const
{ {
return m_border.bottom; Q_D(const Format);
return d->borderData.bottom;
} }
void Format::setBottomBorderStyle(BorderStyle style) void Format::setBottomBorderStyle(BorderStyle style)
{ {
m_border.bottom = style; Q_D(Format);
m_border._dirty = true; d->borderData.bottom = style;
d->borderData._dirty = true;
} }
QColor Format::bottomBorderColor() const QColor Format::bottomBorderColor() const
{ {
return m_border.bottomColor; Q_D(const Format);
return d->borderData.bottomColor;
} }
void Format::setBottomBorderColor(const QColor &color) void Format::setBottomBorderColor(const QColor &color)
{ {
m_border.bottomColor = color; Q_D(Format);
m_border._dirty = true; d->borderData.bottomColor = color;
d->borderData._dirty = true;
} }
Format::BorderStyle Format::diagonalBorderStyle() const Format::BorderStyle Format::diagonalBorderStyle() const
{ {
return m_border.diagonal; Q_D(const Format);
return d->borderData.diagonal;
} }
void Format::setDiagonalBorderStyle(BorderStyle style) void Format::setDiagonalBorderStyle(BorderStyle style)
{ {
m_border.diagonal = style; Q_D(Format);
m_border._dirty = true; d->borderData.diagonal = style;
d->borderData._dirty = true;
} }
Format::DiagonalBorderType Format::diagonalBorderType() const Format::DiagonalBorderType Format::diagonalBorderType() const
{ {
return m_border.diagonalType; Q_D(const Format);
return d->borderData.diagonalType;
} }
void Format::setDiagonalBorderType(DiagonalBorderType style) void Format::setDiagonalBorderType(DiagonalBorderType style)
{ {
m_border.diagonalType = style; Q_D(Format);
m_border._dirty = true; d->borderData.diagonalType = style;
d->borderData._dirty = true;
} }
QColor Format::diagonalBorderColor() const QColor Format::diagonalBorderColor() const
{ {
return m_border.diagonalColor; Q_D(const Format);
return d->borderData.diagonalColor;
} }
void Format::setDiagonalBorderColor(const QColor &color) void Format::setDiagonalBorderColor(const QColor &color)
{ {
m_border.diagonalColor = color; Q_D(Format);
m_border._dirty = true; 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 /* Internal
*/ */
QByteArray Format::borderKey() const QByteArray Format::borderKey() const
{ {
if (m_border._dirty) { Q_D(const Format);
if (d->borderData._dirty) {
QByteArray key; QByteArray key;
QDataStream stream(&key, QIODevice::WriteOnly); QDataStream stream(&key, QIODevice::WriteOnly);
stream<<m_border.bottom<<m_border.bottomColor stream<<d->borderData.bottom<<d->borderData.bottomColor
<<m_border.diagonal<<m_border.diagonalColor<<m_border.diagonalType <<d->borderData.diagonal<<d->borderData.diagonalColor<<d->borderData.diagonalType
<<m_border.left<<m_border.leftColor <<d->borderData.left<<d->borderData.leftColor
<<m_border.right<<m_border.rightColor <<d->borderData.right<<d->borderData.rightColor
<<m_border.top<<m_border.topColor; <<d->borderData.top<<d->borderData.topColor;
const_cast<Format*>(this)->m_border._key = key; const_cast<FormatPrivate*>(d)->borderData._key = key;
const_cast<Format*>(this)->m_border._dirty = false; const_cast<FormatPrivate*>(d)->borderData._dirty = false;
const_cast<Format*>(this)->m_dirty = true; //Make sure formatKey() will be re-generated. const_cast<FormatPrivate*>(d)->dirty = true; //Make sure formatKey() will be re-generated.
} }
return m_border._key; return d->borderData._key;
} }
Format::FillPattern Format::fillPattern() const Format::FillPattern Format::fillPattern() const
{ {
return m_fill.pattern; Q_D(const Format);
return d->fillData.pattern;
} }
void Format::setFillPattern(FillPattern pattern) void Format::setFillPattern(FillPattern pattern)
{ {
m_fill.pattern = pattern; Q_D(Format);
m_fill._dirty = true; d->fillData.pattern = pattern;
d->fillData._dirty = true;
} }
QColor Format::patternForegroundColor() const QColor Format::patternForegroundColor() const
{ {
return m_fill.fgColor; Q_D(const Format);
return d->fillData.fgColor;
} }
void Format::setPatternForegroundColor(const QColor &color) void Format::setPatternForegroundColor(const QColor &color)
{ {
if (color.isValid() && m_fill.pattern == PatternNone) Q_D(Format);
m_fill.pattern = PatternSolid; if (color.isValid() && d->fillData.pattern == PatternNone)
m_fill.fgColor = color; d->fillData.pattern = PatternSolid;
m_fill._dirty = true; d->fillData.fgColor = color;
d->fillData._dirty = true;
} }
QColor Format::patternBackgroundColor() const QColor Format::patternBackgroundColor() const
{ {
return m_fill.bgColor; Q_D(const Format);
return d->fillData.bgColor;
} }
void Format::setPatternBackgroundColor(const QColor &color) void Format::setPatternBackgroundColor(const QColor &color)
{ {
if (color.isValid() && m_fill.pattern == PatternNone) Q_D(Format);
m_fill.pattern = PatternSolid; if (color.isValid() && d->fillData.pattern == PatternNone)
m_fill.bgColor = color; d->fillData.pattern = PatternSolid;
m_fill._dirty = true; 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 /* Internal
*/ */
QByteArray Format::fillKey() const QByteArray Format::fillKey() const
{ {
if (m_fill._dirty) { Q_D(const Format);
if (d->fillData._dirty) {
QByteArray key; QByteArray key;
QDataStream stream(&key, QIODevice::WriteOnly); QDataStream stream(&key, QIODevice::WriteOnly);
stream<<m_fill.bgColor<<m_fill.fgColor<<m_fill.pattern; stream<<d->fillData.bgColor<<d->fillData.fgColor<<d->fillData.pattern;
const_cast<Format*>(this)->m_fill._key = key; const_cast<FormatPrivate*>(d)->fillData._key = key;
const_cast<Format*>(this)->m_fill._dirty = false; const_cast<FormatPrivate*>(d)->fillData._dirty = false;
const_cast<Format*>(this)->m_dirty = true; //Make sure formatKey() will be re-generated. const_cast<FormatPrivate*>(d)->dirty = true; //Make sure formatKey() will be re-generated.
} }
return m_fill._key; return d->fillData._key;
} }
bool Format::hidden() const bool Format::hidden() const
{ {
return m_protection.hidden; Q_D(const Format);
return d->protectionData.hidden;
} }
void Format::setHidden(bool hidden) void Format::setHidden(bool hidden)
{ {
m_protection.hidden = hidden; Q_D(Format);
m_dirty = true; d->protectionData.hidden = hidden;
d->dirty = true;
} }
bool Format::locked() const bool Format::locked() const
{ {
return m_protection.locked; Q_D(const Format);
return d->protectionData.locked;
} }
void Format::setLocked(bool locked) void Format::setLocked(bool locked)
{ {
m_protection.locked = locked; Q_D(Format);
m_dirty = true; d->protectionData.locked = locked;
d->dirty = true;
} }
QByteArray Format::formatKey() const 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; QByteArray key;
QDataStream stream(&key, QIODevice::WriteOnly); QDataStream stream(&key, QIODevice::WriteOnly);
stream<<fontKey()<<borderKey()<<fillKey() stream<<fontKey()<<borderKey()<<fillKey()
<<m_number.formatIndex <<d->numberData.formatIndex
<<m_alignment.alignH<<m_alignment.alignV<<m_alignment.indent <<d->alignmentData.alignH<<d->alignmentData.alignV<<d->alignmentData.indent
<<m_alignment.rotation<<m_alignment.shinkToFit<<m_alignment.wrap <<d->alignmentData.rotation<<d->alignmentData.shinkToFit<<d->alignmentData.wrap
<<m_protection.hidden<<m_protection.locked; <<d->protectionData.hidden<<d->protectionData.locked;
const_cast<Format*>(this)->m_formatKey = key; const_cast<FormatPrivate*>(d)->formatKey = key;
const_cast<Format*>(this)->m_dirty = false; const_cast<FormatPrivate*>(d)->dirty = false;
} }
return m_formatKey; return d->formatKey;
} }
bool Format::operator ==(const Format &format) const bool Format::operator ==(const Format &format) const
@ -650,35 +770,60 @@ bool Format::operator !=(const Format &format) const
*/ */
int Format::xfIndex(bool generateIfNotValid) 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; int index = -1;
for (int i=0; i<s_xfFormats.size(); ++i) { for (int i=0; i<d->s_xfFormats.size(); ++i) {
if (*s_xfFormats[i] == *this) { if (*d->s_xfFormats[i] == *this) {
index = i; index = i;
break; break;
} }
} }
if (index != -1) { if (index != -1) {
m_xf_index = index; d->xf_index = index;
} else { } else {
m_xf_index = s_xfFormats.size(); d->xf_index = d->s_xfFormats.size();
s_xfFormats.append(this); d->s_xfFormats.append(this);
} }
} }
return m_xf_index; return d->xf_index;
} }
void Format::clearExtraInfos() void Format::clearExtraInfos()
{ {
m_xf_index = -1; Q_D(Format);
m_dxf_index = -1; d->xf_index = -1;
s_xfFormats.clear(); d->dxf_index = -1;
s_dxfFormats.clear(); d->s_xfFormats.clear();
d->s_dxfFormats.clear();
} }
bool Format::isDxfFormat() const 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 *> Format::xfFormats()
{
return FormatPrivate::s_xfFormats;
}
QList<Format *> Format::dxfFormats()
{
return FormatPrivate::s_dxfFormats;
} }
} // namespace QXlsx } // namespace QXlsx

129
src/xlsxformat.h

@ -34,9 +34,12 @@ namespace QXlsx {
class Styles; class Styles;
class Worksheet; class Worksheet;
class WorksheetPrivate;
class FormatPrivate;
class Format class Format
{ {
Q_DECLARE_PRIVATE(Format)
public: public:
enum FontScript enum FontScript
{ {
@ -123,6 +126,8 @@ public:
PatternGray0625 PatternGray0625
}; };
~Format();
int numberFormat() const; int numberFormat() const;
void setNumberFormat(int format); void setNumberFormat(int format);
@ -201,129 +206,47 @@ public:
private: private:
friend class Styles; friend class Styles;
friend class Worksheet; friend class Worksheet;
friend class WorksheetPrivate;
Format(); Format();
struct NumberData bool hasFont() const;
{ void setFontRedundant(bool redundant);
int formatIndex; int fontIndex() const;
} m_number; void setFontIndex(int index);
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;}
QByteArray fontKey() const; QByteArray fontKey() const;
int fontFamily() const{return m_font.family;} int fontFamily() const;
bool fontShadow() const {return m_font.shadow;} bool fontShadow() const;
QString fontScheme() const {return m_font.scheme;} QString fontScheme() const;
struct AlignmentData
{
HorizontalAlignment alignH;
VerticalAlignment alignV;
bool wrap;
int rotation;
int indent;
bool shinkToFit;
} m_alignment;
bool alignmentChanged() const; bool alignmentChanged() const;
QString horizontalAlignmentString() const; QString horizontalAlignmentString() const;
QString verticalAlignmentString() 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; QByteArray borderKey() const;
bool hasBorders() const {return !m_border._redundant;} bool hasBorders() const;
void setBorderRedundant(bool redundant) {m_border._redundant = redundant;} void setBorderRedundant(bool redundant);
int borderIndex() const {return m_border._index;} int borderIndex() const;
void setBorderIndex(int index) {m_border._index = index;} void setBorderIndex(int 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;
QByteArray fillKey() const; QByteArray fillKey() const;
bool hasFill() const {return !m_fill._redundant;} bool hasFill() const;
void setFillRedundant(bool redundant) {m_fill._redundant = redundant;} void setFillRedundant(bool redundant);
int fillIndex() const {return m_fill._index;} int fillIndex() const;
void setFillIndex(int index) {m_fill._index = index;} void setFillIndex(int index);
struct ProtectionData {
bool locked;
bool hidden;
} m_protection;
bool m_dirty; //The key re-generation is need.
QByteArray m_formatKey;
QByteArray formatKey() const; QByteArray formatKey() const;
static QList<Format *> s_xfFormats; static QList<Format *> xfFormats();
int m_xf_index; static QList<Format *> dxfFormats();
int xfIndex(bool generateIfNotValid=true); //Generate index when first called. int xfIndex(bool generateIfNotValid=true); //Generate index when first called.
void clearExtraInfos(); void clearExtraInfos();
bool m_is_dxf_fomat;
int m_dxf_index;
static QList<Format *> s_dxfFormats;
bool isDxfFormat() const; bool isDxfFormat() const;
int m_theme; int theme() const;
int m_color_indexed; int colorIndexed() const;
int theme() const {return m_theme;}
int colorIndexed() const {return m_color_indexed;}
FormatPrivate * const d_ptr;
}; };
} // namespace QXlsx } // namespace QXlsx

172
src/xlsxformat_p.h

@ -0,0 +1,172 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** 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<Format *> s_xfFormats;
int xf_index;
static QList<Format *> s_dxfFormats;
bool is_dxf_fomat;
int dxf_index;
int theme;
int color_indexed;
Format *q_ptr;
};
}
#endif // XLSXFORMAT_P_H

4
src/xlsxstyles.cpp

@ -60,8 +60,8 @@ Format *Styles::addFormat()
*/ */
void Styles::prepareStyles() void Styles::prepareStyles()
{ {
m_xf_formats = Format::s_xfFormats; m_xf_formats = Format::xfFormats();
m_dxf_formats = Format::s_dxfFormats; m_dxf_formats = Format::dxfFormats();
if (m_xf_formats.isEmpty()) if (m_xf_formats.isEmpty())
m_xf_formats.append(this->addFormat()); m_xf_formats.append(this->addFormat());

100
src/xlsxworkbook.cpp

@ -23,6 +23,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "xlsxworkbook.h" #include "xlsxworkbook.h"
#include "xlsxworkbook_p.h"
#include "xlsxsharedstrings_p.h" #include "xlsxsharedstrings_p.h"
#include "xlsxworksheet.h" #include "xlsxworksheet.h"
#include "xlsxstyles_p.h" #include "xlsxstyles_p.h"
@ -32,44 +33,52 @@
namespace QXlsx { namespace QXlsx {
Workbook::Workbook(QObject *parent) : WorkbookPrivate::WorkbookPrivate(Workbook *q) :
QObject(parent) q_ptr(q)
{ {
m_sharedStrings = new SharedStrings(this); sharedStrings = new SharedStrings(q);
m_styles = new Styles(this); 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; Workbook::Workbook(QObject *parent) :
m_y_window = 15; QObject(parent), d_ptr(new WorkbookPrivate(this))
m_window_width = 16095; {
m_window_height = 9660;
m_strings_to_numbers_enabled = false;
m_date1904 = false;
m_activesheet = 0;
m_firstsheet = 0;
m_table_count = 0;
} }
Workbook::~Workbook() Workbook::~Workbook()
{ {
delete d_ptr;
} }
void Workbook::save(const QString &name) void Workbook::save(const QString &name)
{ {
Q_D(Workbook);
//Add a default worksheet if non have been added. //Add a default worksheet if non have been added.
if (m_worksheets.size() == 0) if (d->worksheets.size() == 0)
addWorksheet(); addWorksheet();
//Ensure that at least one worksheet has been selected. //Ensure that at least one worksheet has been selected.
if (m_activesheet == 0) { if (d->activesheet == 0) {
m_worksheets[0]->setHidden(false); d->worksheets[0]->setHidden(false);
m_worksheets[0]->setSelected(true); d->worksheets[0]->setSelected(true);
} }
//Set the active sheet //Set the active sheet
foreach (Worksheet *sheet, m_worksheets) { foreach (Worksheet *sheet, d->worksheets) {
if (sheet->index() == m_activesheet) if (sheet->index() == d->activesheet)
sheet->setActived(true); sheet->setActived(true);
} }
@ -80,7 +89,8 @@ void Workbook::save(const QString &name)
bool Workbook::isDate1904() const 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) 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) void Workbook::setStringsToNumbersEnabled(bool enable)
{ {
m_strings_to_numbers_enabled = enable; Q_D(Workbook);
d->strings_to_numbers_enabled = enable;
} }
bool Workbook::isStringsToNumbersEnabled() const 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) 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) Worksheet *Workbook::addWorksheet(const QString &name)
{ {
Q_D(Workbook);
QString worksheetName = name; QString worksheetName = name;
int index = m_worksheets.size()+1; int index = d->worksheets.size()+1;
if (name.isEmpty()) if (name.isEmpty())
worksheetName = QString("Sheet%1").arg(index); worksheetName = QString("Sheet%1").arg(index);
Worksheet *sheet = new Worksheet(worksheetName, index, this); Worksheet *sheet = new Worksheet(worksheetName, index, this);
m_worksheets.append(sheet); d->worksheets.append(sheet);
return sheet; return sheet;
} }
Format *Workbook::addFormat() Format *Workbook::addFormat()
{ {
return m_styles->addFormat(); Q_D(Workbook);
return d->styles->addFormat();
} }
QList<Worksheet *> Workbook::worksheets() const QList<Worksheet *> Workbook::worksheets() const
{ {
return m_worksheets; Q_D(const Workbook);
return d->worksheets;
} }
SharedStrings *Workbook::sharedStrings() SharedStrings *Workbook::sharedStrings()
{ {
return m_sharedStrings; Q_D(Workbook);
return d->sharedStrings;
} }
Styles *Workbook::styles() Styles *Workbook::styles()
{ {
return m_styles; Q_D(Workbook);
return d->styles;
} }
void Workbook::saveToXmlFile(QIODevice *device) void Workbook::saveToXmlFile(QIODevice *device)
{ {
Q_D(Workbook);
XmlStreamWriter writer(device); XmlStreamWriter writer(device);
writer.writeStartDocument("1.0", true); writer.writeStartDocument("1.0", true);
@ -166,26 +186,26 @@ void Workbook::saveToXmlFile(QIODevice *device)
// writer.writeAttribute("codeName", "{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}"); // writer.writeAttribute("codeName", "{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}");
writer.writeEmptyElement("workbookPr"); writer.writeEmptyElement("workbookPr");
if (m_date1904) if (d->date1904)
writer.writeAttribute("date1904", "1"); writer.writeAttribute("date1904", "1");
writer.writeAttribute("defaultThemeVersion", "124226"); writer.writeAttribute("defaultThemeVersion", "124226");
writer.writeStartElement("bookViews"); writer.writeStartElement("bookViews");
writer.writeEmptyElement("workbookView"); writer.writeEmptyElement("workbookView");
writer.writeAttribute("xWindow", QString::number(m_x_window)); writer.writeAttribute("xWindow", QString::number(d->x_window));
writer.writeAttribute("yWindow", QString::number(m_y_window)); writer.writeAttribute("yWindow", QString::number(d->y_window));
writer.writeAttribute("windowWidth", QString::number(m_window_width)); writer.writeAttribute("windowWidth", QString::number(d->window_width));
writer.writeAttribute("windowHeight", QString::number(m_window_height)); writer.writeAttribute("windowHeight", QString::number(d->window_height));
//Store the firstSheet when it isn't the default //Store the firstSheet when it isn't the default
if (m_firstsheet > 0) if (d->firstsheet > 0)
writer.writeAttribute("firstSheet", QString::number(m_firstsheet + 1)); writer.writeAttribute("firstSheet", QString::number(d->firstsheet + 1));
//Store the activeTab when it isn't the first sheet //Store the activeTab when it isn't the first sheet
if (m_activesheet > 0) if (d->activesheet > 0)
writer.writeAttribute("activeTab", QString::number(m_activesheet)); writer.writeAttribute("activeTab", QString::number(d->activesheet));
writer.writeEndElement();//bookviews writer.writeEndElement();//bookviews
writer.writeStartElement("sheets"); writer.writeStartElement("sheets");
foreach (Worksheet *sheet, m_worksheets) { foreach (Worksheet *sheet, d->worksheets) {
writer.writeEmptyElement("sheet"); writer.writeEmptyElement("sheet");
writer.writeAttribute("name", sheet->name()); writer.writeAttribute("name", sheet->name());
writer.writeAttribute("sheetId", QString::number(sheet->index())); writer.writeAttribute("sheetId", QString::number(sheet->index()));

19
src/xlsxworkbook.h

@ -37,13 +37,16 @@ class SharedStrings;
class Styles; class Styles;
class Package; class Package;
class WorkbookPrivate;
class Workbook : public QObject class Workbook : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(Workbook)
public: public:
Workbook(QObject *parent=0); Workbook(QObject *parent=0);
~Workbook(); ~Workbook();
QList<Worksheet *> worksheets() const;
Worksheet *addWorksheet(const QString &name = QString()); Worksheet *addWorksheet(const QString &name = QString());
Format *addFormat(); Format *addFormat();
// void addChart(); // void addChart();
@ -59,25 +62,11 @@ private:
friend class Package; friend class Package;
friend class Worksheet; friend class Worksheet;
QList<Worksheet *> worksheets() const;
SharedStrings *sharedStrings(); SharedStrings *sharedStrings();
Styles *styles(); Styles *styles();
void saveToXmlFile(QIODevice *device); void saveToXmlFile(QIODevice *device);
SharedStrings *m_sharedStrings; WorkbookPrivate * const d_ptr;
QList<Worksheet *> 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;
}; };
} //QXlsx } //QXlsx

58
src/xlsxworkbook_p.h

@ -0,0 +1,58 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** 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<Worksheet *> 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

496
src/xlsxworksheet.cpp

@ -23,6 +23,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "xlsxworksheet.h" #include "xlsxworksheet.h"
#include "xlsxworksheet_p.h"
#include "xlsxworkbook.h" #include "xlsxworkbook.h"
#include "xlsxformat.h" #include "xlsxformat.h"
#include "xlsxutility_p.h" #include "xlsxutility_p.h"
@ -39,55 +40,157 @@
namespace QXlsx { namespace QXlsx {
struct XlsxCellData WorksheetPrivate::WorksheetPrivate(Worksheet *p) :
q_ptr(p)
{ {
enum CellDataType { xls_rowmax = 1048576;
Blank, xls_colmax = 16384;
String, xls_strmax = 32767;
Number, dim_rowmin = INT32_MAX;
Formula, dim_rowmax = INT32_MIN;
ArrayFormula, dim_colmin = INT32_MAX;
Boolean, dim_colmax = INT32_MIN;
DateTime
}; previous_row = 0;
XlsxCellData(const QVariant &data=QVariant(), CellDataType type=Blank, Format *format=0) :
value(data), dataType(type), format(format) outline_row_level = 0;
{ outline_col_level = 0;
} default_row_height = 15;
default_row_zeroed = false;
QVariant value;
QString formula; hidden = false;
CellDataType dataType; selected = false;
Format *format; actived = false;
}; right_to_left = false;
show_zeros = true;
struct XlsxRowInfo }
WorksheetPrivate::~WorksheetPrivate()
{
typedef QMap<int, XlsxCellData *> 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 <row> 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;
}
}
}
}
QString WorksheetPrivate::generateDimensionString()
{ {
XlsxRowInfo(double height, Format *format, bool hidden) : if (dim_rowmax == INT32_MIN && dim_colmax == INT32_MIN) {
height(height), format(format), hidden(hidden) //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;
}
}
if (dim_rowmin == dim_rowmax && dim_colmin == dim_colmax) {
//Single cell
return xl_rowcol_to_cell(dim_rowmin, dim_rowmin);
} }
double height; QString cell_1 = xl_rowcol_to_cell(dim_rowmin, dim_colmin);
Format *format; QString cell_2 = xl_rowcol_to_cell(dim_rowmax, dim_colmax);
bool hidden; 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) : if (row >= xls_rowmax || col >= xls_colmax)
column_min(column_min), column_max(column_max), width(width), format(format), hidden(hidden) 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; return 0;
double width; }
Format *format;
bool hidden;
};
/*! /*!
* \brief Worksheet::Worksheet * \brief Worksheet::Worksheet
@ -96,44 +199,16 @@ struct XlsxColumnInfo
* \param parent * \param parent
*/ */
Worksheet::Worksheet(const QString &name, int index, Workbook *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; d_ptr->name = name;
m_xls_colmax = 16384; d_ptr->index = index;
m_xls_strmax = 32767; d_ptr->workbook = parent;
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;
} }
Worksheet::~Worksheet() Worksheet::~Worksheet()
{ {
typedef QMap<int, XlsxCellData *> RowMap; delete d_ptr;
foreach (RowMap row, m_cellTable) {
foreach (XlsxCellData *item, row)
delete item;
}
foreach (XlsxRowInfo *row, m_rowsInfo)
delete row;
foreach (XlsxColumnInfo *col, m_colsInfo)
delete col;
} }
bool Worksheet::isChartsheet() const bool Worksheet::isChartsheet() const
@ -143,59 +218,73 @@ bool Worksheet::isChartsheet() const
QString Worksheet::name() const QString Worksheet::name() const
{ {
return m_name; Q_D(const Worksheet);
return d->name;
} }
int Worksheet::index() const int Worksheet::index() const
{ {
return m_index; Q_D(const Worksheet);
return d->index;
} }
bool Worksheet::isHidden() const bool Worksheet::isHidden() const
{ {
return m_hidden; Q_D(const Worksheet);
return d->hidden;
} }
bool Worksheet::isSelected() const bool Worksheet::isSelected() const
{ {
return m_selected; Q_D(const Worksheet);
return d->selected;
} }
bool Worksheet::isActived() const bool Worksheet::isActived() const
{ {
return m_actived; Q_D(const Worksheet);
return d->actived;
} }
void Worksheet::setHidden(bool hidden) void Worksheet::setHidden(bool hidden)
{ {
m_hidden = hidden; Q_D(Worksheet);
d->hidden = hidden;
} }
void Worksheet::setSelected(bool select) void Worksheet::setSelected(bool select)
{ {
m_selected = select; Q_D(Worksheet);
d->selected = select;
} }
void Worksheet::setActived(bool act) void Worksheet::setActived(bool act)
{ {
m_actived = act; Q_D(Worksheet);
d->actived = act;
} }
void Worksheet::setRightToLeft(bool enable) void Worksheet::setRightToLeft(bool enable)
{ {
m_right_to_left = enable; Q_D(Worksheet);
d->right_to_left = enable;
} }
void Worksheet::setZeroValuesHidden(bool 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) int Worksheet::write(int row, int column, const QVariant &value, Format *format)
{ {
Q_D(Worksheet);
bool ok; bool ok;
int ret = 0; int ret = 0;
if (d->checkDimensions(row, column))
return -1;
if (value.isNull()) { //blank if (value.isNull()) { //blank
ret = writeBlank(row, column, format); ret = writeBlank(row, column, format);
} else if (value.type() == QMetaType::Bool) { //Bool } 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 } else if (value.toDateTime().isValid()) { //DateTime
ret = writeDateTime(row, column, value.toDateTime(), format); ret = writeDateTime(row, column, value.toDateTime(), format);
} else if (value.toDouble(&ok), ok) { //Number } 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. //Don't convert string to number if the flag not enabled.
ret = writeString(row, column, value.toString(), format); ret = writeString(row, column, value.toString(), format);
} else { } 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) int Worksheet::writeString(int row, int column, const QString &value, Format *format)
{ {
Q_D(Worksheet);
int error = 0; int error = 0;
QString content = value; QString content = value;
if (checkDimensions(row, column)) if (d->checkDimensions(row, column))
return -1; return -1;
if (value.size() > m_xls_strmax) { if (value.size() > d->xls_strmax) {
content = value.left(m_xls_strmax); content = value.left(d->xls_strmax);
error = -2; error = -2;
} }
SharedStrings *sharedStrings = m_workbook->sharedStrings(); SharedStrings *sharedStrings = d->workbook->sharedStrings();
int index = sharedStrings->addSharedString(content); 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; return error;
} }
int Worksheet::writeNumber(int row, int column, double value, Format *format) 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; return -1;
m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format); d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Number, format);
return 0; return 0;
} }
int Worksheet::writeFormula(int row, int column, const QString &content, Format *format, double result) int Worksheet::writeFormula(int row, int column, const QString &content, Format *format, double result)
{ {
Q_D(Worksheet);
int error = 0; int error = 0;
QString formula = content; QString formula = content;
if (checkDimensions(row, column)) if (d->checkDimensions(row, column))
return -1; return -1;
//Remove the formula '=' sign if exists //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); XlsxCellData *data = new XlsxCellData(result, XlsxCellData::Formula, format);
data->formula = formula; data->formula = formula;
m_cellTable[row][column] = data; d->cellTable[row][column] = data;
return error; return error;
} }
int Worksheet::writeBlank(int row, int column, Format *format) int Worksheet::writeBlank(int row, int column, Format *format)
{ {
if (checkDimensions(row, column)) Q_D(Worksheet);
if (d->checkDimensions(row, column))
return -1; return -1;
m_cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format); d->cellTable[row][column] = new XlsxCellData(QVariant(), XlsxCellData::Blank, format);
return 0; return 0;
} }
int Worksheet::writeBool(int row, int column, bool value, Format *format) 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; return -1;
m_cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format); d->cellTable[row][column] = new XlsxCellData(value, XlsxCellData::Boolean, format);
return 0; return 0;
} }
int Worksheet::writeDateTime(int row, int column, const QDateTime &dt, Format *format) 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; return -1;
m_cellTable[row][column] = new XlsxCellData(dt, XlsxCellData::DateTime, format); d->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;
}
return 0; return 0;
} }
void Worksheet::saveToXmlFile(QIODevice *device) void Worksheet::saveToXmlFile(QIODevice *device)
{ {
Q_D(Worksheet);
XmlStreamWriter writer(device); XmlStreamWriter writer(device);
writer.writeStartDocument("1.0", true); writer.writeStartDocument("1.0", true);
@ -350,38 +422,38 @@ void Worksheet::saveToXmlFile(QIODevice *device)
// writer.writeAttribute("mc:Ignorable", "x14ac"); // writer.writeAttribute("mc:Ignorable", "x14ac");
writer.writeStartElement("dimension"); writer.writeStartElement("dimension");
writer.writeAttribute("ref", generateDimensionString()); writer.writeAttribute("ref", d->generateDimensionString());
writer.writeEndElement();//dimension writer.writeEndElement();//dimension
writer.writeStartElement("sheetViews"); writer.writeStartElement("sheetViews");
writer.writeStartElement("sheetView"); writer.writeStartElement("sheetView");
if (!m_show_zeros) if (!d->show_zeros)
writer.writeAttribute("showZeros", "0"); writer.writeAttribute("showZeros", "0");
if (m_right_to_left) if (d->right_to_left)
writer.writeAttribute("rightToLeft", "1"); writer.writeAttribute("rightToLeft", "1");
if (m_selected) if (d->selected)
writer.writeAttribute("tabSelected", "1"); writer.writeAttribute("tabSelected", "1");
writer.writeAttribute("workbookViewId", "0"); writer.writeAttribute("workbookViewId", "0");
writer.writeEndElement();//sheetView writer.writeEndElement();//sheetView
writer.writeEndElement();//sheetViews writer.writeEndElement();//sheetViews
writer.writeStartElement("sheetFormatPr"); writer.writeStartElement("sheetFormatPr");
writer.writeAttribute("defaultRowHeight", QString::number(m_default_row_height)); writer.writeAttribute("defaultRowHeight", QString::number(d->default_row_height));
if (m_default_row_height != 15) if (d->default_row_height != 15)
writer.writeAttribute("customHeight", "1"); writer.writeAttribute("customHeight", "1");
if (m_default_row_zeroed) if (d->default_row_zeroed)
writer.writeAttribute("zeroHeight", "1"); writer.writeAttribute("zeroHeight", "1");
if (m_outline_row_level) if (d->outline_row_level)
writer.writeAttribute("outlineLevelRow", QString::number(m_outline_row_level)); writer.writeAttribute("outlineLevelRow", QString::number(d->outline_row_level));
if (m_outline_col_level) if (d->outline_col_level)
writer.writeAttribute("outlineLevelCol", QString::number(m_outline_col_level)); writer.writeAttribute("outlineLevelCol", QString::number(d->outline_col_level));
//for Excel 2010 //for Excel 2010
// writer.writeAttribute("x14ac:dyDescent", "0.25"); // writer.writeAttribute("x14ac:dyDescent", "0.25");
writer.writeEndElement();//sheetFormatPr writer.writeEndElement();//sheetFormatPr
if (!m_colsInfo.isEmpty()) { if (!d->colsInfo.isEmpty()) {
writer.writeStartElement("cols"); writer.writeStartElement("cols");
foreach (XlsxColumnInfo *col_info, m_colsInfo) { foreach (XlsxColumnInfo *col_info, d->colsInfo) {
writer.writeStartElement("col"); writer.writeStartElement("col");
writer.writeAttribute("min", QString::number(col_info->column_min)); writer.writeAttribute("min", QString::number(col_info->column_min));
writer.writeAttribute("max", QString::number(col_info->column_max)); writer.writeAttribute("max", QString::number(col_info->column_max));
@ -398,10 +470,10 @@ void Worksheet::saveToXmlFile(QIODevice *device)
} }
writer.writeStartElement("sheetData"); 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 //If the max dimensions are equal to INT32_MIN, then there is no data to write
} else { } else {
writeSheetData(writer); d->writeSheetData(writer);
} }
writer.writeEndElement();//sheetData writer.writeEndElement();//sheetData
@ -409,59 +481,29 @@ void Worksheet::saveToXmlFile(QIODevice *device)
writer.writeEndDocument(); writer.writeEndDocument();
} }
QString Worksheet::generateDimensionString() void WorksheetPrivate::writeSheetData(XmlStreamWriter &writer)
{
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)
{ {
calculateSpans(); calculateSpans();
for (int row_num = m_dim_rowmin; row_num <= m_dim_rowmax; row_num++) { for (int row_num = dim_rowmin; row_num <= dim_rowmax; row_num++) {
if (!(m_cellTable.contains(row_num) || m_comments.contains(row_num) || m_rowsInfo.contains(row_num))) { if (!(cellTable.contains(row_num) || comments.contains(row_num) || rowsInfo.contains(row_num))) {
//Only process rows with cell data / comments / formatting //Only process rows with cell data / comments / formatting
continue; continue;
} }
int span_index = row_num / 16; int span_index = row_num / 16;
QString span; QString span;
if (m_row_spans.contains(span_index)) if (row_spans.contains(span_index))
span = m_row_spans[span_index]; span = row_spans[span_index];
if (m_cellTable.contains(row_num)) { if (cellTable.contains(row_num)) {
writer.writeStartElement("row"); writer.writeStartElement("row");
writer.writeAttribute("r", QString::number(row_num + 1)); writer.writeAttribute("r", QString::number(row_num + 1));
if (!span.isEmpty()) if (!span.isEmpty())
writer.writeAttribute("spans", span); writer.writeAttribute("spans", span);
if (m_rowsInfo.contains(row_num)) { if (rowsInfo.contains(row_num)) {
XlsxRowInfo *rowInfo = m_rowsInfo[row_num]; XlsxRowInfo *rowInfo = rowsInfo[row_num];
if (rowInfo->format) { if (rowInfo->format) {
writer.writeAttribute("s", QString::number(rowInfo->format->xfIndex())); writer.writeAttribute("s", QString::number(rowInfo->format->xfIndex()));
writer.writeAttribute("customFormat", "1"); writer.writeAttribute("customFormat", "1");
@ -474,13 +516,13 @@ void Worksheet::writeSheetData(XmlStreamWriter &writer)
writer.writeAttribute("hidden", "1"); writer.writeAttribute("hidden", "1");
} }
for (int col_num = m_dim_colmin; col_num <= m_dim_colmax; col_num++) { for (int col_num = dim_colmin; col_num <= dim_colmax; col_num++) {
if (m_cellTable[row_num].contains(col_num)) { if (cellTable[row_num].contains(col_num)) {
writeCellData(writer, row_num, col_num, m_cellTable[row_num][col_num]); writeCellData(writer, row_num, col_num, cellTable[row_num][col_num]);
} }
} }
writer.writeEndElement(); //row writer.writeEndElement(); //row
} else if (m_comments.contains(row_num)){ } else if (comments.contains(row_num)){
} else { } 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. //This is the innermost loop so efficiency is important.
QString cell_range = xl_rowcol_to_cell_fast(row, col); 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 //Style used by the cell, row or col
if (cell->format) if (cell->format)
writer.writeAttribute("s", QString::number(cell->format->xfIndex())); writer.writeAttribute("s", QString::number(cell->format->xfIndex()));
else if (m_rowsInfo.contains(row) && m_rowsInfo[row]->format) else if (rowsInfo.contains(row) && rowsInfo[row]->format)
writer.writeAttribute("s", QString::number(m_rowsInfo[row]->format->xfIndex())); writer.writeAttribute("s", QString::number(rowsInfo[row]->format->xfIndex()));
else if (m_colsInfoHelper.contains(col) && m_colsInfoHelper[col]->format) else if (colsInfoHelper.contains(col) && colsInfoHelper[col]->format)
writer.writeAttribute("s", QString::number(m_colsInfoHelper[col]->format->xfIndex())); writer.writeAttribute("s", QString::number(colsInfoHelper[col]->format->xfIndex()));
if (cell->dataType == XlsxCellData::String) { if (cell->dataType == XlsxCellData::String) {
//cell->data: Index of the string in sharedStringTable //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. //Ok, empty here.
} else if (cell->dataType == XlsxCellData::DateTime) { } else if (cell->dataType == XlsxCellData::DateTime) {
QDateTime epoch(QDate(1899, 12, 31)); QDateTime epoch(QDate(1899, 12, 31));
if (m_workbook->isDate1904()) if (workbook->isDate1904())
epoch = QDateTime(QDate(1904, 1, 1)); epoch = QDateTime(QDate(1904, 1, 1));
qint64 delta = epoch.msecsTo(cell->value.toDateTime()); qint64 delta = epoch.msecsTo(cell->value.toDateTime());
double excel_time = delta / (1000*60*60*24); double excel_time = delta / (1000*60*60*24);
//Account for Excel erroneously treating 1900 as a leap year. //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; excel_time += 1;
writer.writeTextElement("v", QString::number(excel_time, 'g', 15)); writer.writeTextElement("v", QString::number(excel_time, 'g', 15));
} }
writer.writeEndElement(); //c writer.writeEndElement(); //c
} }
/*
Calculate the "spans" attribute of the <row> 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 Sets row height and format. Row height measured in point size. If format
equals 0 then format is ignored. equals 0 then format is ignored.
*/ */
bool Worksheet::setRow(int row, double height, Format *format, bool hidden) 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; return false;
if (m_rowsInfo.contains(row)) { if (d->rowsInfo.contains(row)) {
m_rowsInfo[row]->height = height; d->rowsInfo[row]->height = height;
m_rowsInfo[row]->format = format; d->rowsInfo[row]->format = format;
m_rowsInfo[row]->hidden = hidden; d->rowsInfo[row]->hidden = hidden;
} else { } else {
m_rowsInfo[row] = new XlsxRowInfo(height, format, hidden); d->rowsInfo[row] = new XlsxRowInfo(height, format, hidden);
} }
return true; 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) bool Worksheet::setColumn(int colFirst, int colLast, double width, Format *format, bool hidden)
{ {
Q_D(Worksheet);
bool ignore_row = true; bool ignore_row = true;
bool ignore_col = (format || (width && hidden)) ? false : 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; return false;
if (checkDimensions(0, colFirst, ignore_row, ignore_col)) if (d->checkDimensions(0, colFirst, ignore_row, ignore_col))
return false; return false;
XlsxColumnInfo *info = new XlsxColumnInfo(colFirst, colLast, width, format, hidden); XlsxColumnInfo *info = new XlsxColumnInfo(colFirst, colLast, width, format, hidden);
m_colsInfo.append(info); d->colsInfo.append(info);
for (int col=colFirst; col<=colLast; ++col) for (int col=colFirst; col<=colLast; ++col)
m_colsInfoHelper[col] = info; d->colsInfoHelper[col] = info;
return true; return true;
} }

44
src/xlsxworksheet.h

@ -38,13 +38,11 @@ class Workbook;
class XmlStreamWriter; class XmlStreamWriter;
class Format; class Format;
struct XlsxCellData; class WorksheetPrivate;
struct XlsxRowInfo;
struct XlsxColumnInfo;
class Worksheet : public QObject class Worksheet : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(Worksheet)
public: public:
int write(const QString row_column, const QVariant &value, Format *format=0); int write(const QString row_column, const QVariant &value, Format *format=0);
int write(int row, int 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 setSelected(bool select);
void setActived(bool act); void setActived(bool act);
void saveToXmlFile(QIODevice *device); 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<int, QMap<int, XlsxCellData *> > m_cellTable;
QMap<int, QMap<int, QString> > m_comments;
QMap<int, XlsxRowInfo *> m_rowsInfo;
QList<XlsxColumnInfo *> m_colsInfo;
QMap<int, XlsxColumnInfo *> 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<int, QString> 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; WorksheetPrivate * const d_ptr;
int m_index;
bool m_hidden;
bool m_selected;
bool m_actived;
bool m_right_to_left;
bool m_show_zeros;
}; };
} //QXlsx } //QXlsx

129
src/xlsxworksheet_p.h

@ -0,0 +1,129 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** 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<int, QMap<int, XlsxCellData *> > cellTable;
QMap<int, QMap<int, QString> > comments;
QMap<int, XlsxRowInfo *> rowsInfo;
QList<XlsxColumnInfo *> colsInfo;
QMap<int, XlsxColumnInfo *> 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<int, QString> 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
Loading…
Cancel
Save