Browse Source

Refactoring Code and change it for pattern file with out value

xlsxtoXmlConverter
nasiCurious 2 years ago
commit
060e7ea0b2
  1. 1
      .gitignore
  2. 44
      XlsxToXmlConverter.pro
  3. 48
      include/QXlsx/xlsxabstractooxmlfile.h
  4. 31
      include/QXlsx/xlsxabstractooxmlfile_p.h
  5. 49
      include/QXlsx/xlsxabstractsheet.h
  6. 36
      include/QXlsx/xlsxabstractsheet_p.h
  7. 82
      include/QXlsx/xlsxcell.h
  8. 41
      include/QXlsx/xlsxcell_p.h
  9. 55
      include/QXlsx/xlsxcellformula.h
  10. 31
      include/QXlsx/xlsxcellformula_p.h
  11. 33
      include/QXlsx/xlsxcelllocation.h
  12. 73
      include/QXlsx/xlsxcellrange.h
  13. 47
      include/QXlsx/xlsxcellreference.h
  14. 58
      include/QXlsx/xlsxchart.h
  15. 148
      include/QXlsx/xlsxchart_p.h
  16. 38
      include/QXlsx/xlsxchartsheet.h
  17. 25
      include/QXlsx/xlsxchartsheet_p.h
  18. 59
      include/QXlsx/xlsxcolor_p.h
  19. 120
      include/QXlsx/xlsxconditionalformatting.h
  20. 99
      include/QXlsx/xlsxconditionalformatting_p.h
  21. 55
      include/QXlsx/xlsxcontenttypes_p.h
  22. 105
      include/QXlsx/xlsxdatavalidation.h
  23. 37
      include/QXlsx/xlsxdatavalidation_p.h
  24. 48
      include/QXlsx/xlsxdatetype.h
  25. 40
      include/QXlsx/xlsxdocpropsapp_p.h
  26. 34
      include/QXlsx/xlsxdocpropscore_p.h
  27. 143
      include/QXlsx/xlsxdocument.h
  28. 41
      include/QXlsx/xlsxdocument_p.h
  29. 38
      include/QXlsx/xlsxdrawing_p.h
  30. 169
      include/QXlsx/xlsxdrawinganchor_p.h
  31. 262
      include/QXlsx/xlsxformat.h
  32. 130
      include/QXlsx/xlsxformat_p.h
  33. 33
      include/QXlsx/xlsxglobal.h
  34. 46
      include/QXlsx/xlsxmediafile_p.h
  35. 51
      include/QXlsx/xlsxnumformatparser_p.h
  36. 89
      include/QXlsx/xlsxrelationships_p.h
  37. 89
      include/QXlsx/xlsxrichstring.h
  38. 60
      include/QXlsx/xlsxrichstring_p.h
  39. 98
      include/QXlsx/xlsxsharedstrings_p.h
  40. 60
      include/QXlsx/xlsxsimpleooxmlfile_p.h
  41. 143
      include/QXlsx/xlsxstyles_p.h
  42. 29
      include/QXlsx/xlsxtheme_p.h
  43. 42
      include/QXlsx/xlsxutility_p.h
  44. 95
      include/QXlsx/xlsxworkbook.h
  45. 74
      include/QXlsx/xlsxworkbook_p.h
  46. 164
      include/QXlsx/xlsxworksheet.h
  47. 252
      include/QXlsx/xlsxworksheet_p.h
  48. 37
      include/QXlsx/xlsxzipreader_p.h
  49. 34
      include/QXlsx/xlsxzipwriter_p.h
  50. 12
      include/XlsxReader.h
  51. 23
      include/XlsxXmlConverter.h
  52. 15
      include/XmlGenerator.h
  53. 12
      include/XmlTemplateReader.h
  54. 15
      main.cpp
  55. 97
      src/QXlsx/xlsxabstractooxmlfile.cpp
  56. 186
      src/QXlsx/xlsxabstractsheet.cpp
  57. 364
      src/QXlsx/xlsxcell.cpp
  58. 453
      src/QXlsx/xlsxcellformula.cpp
  59. 23
      src/QXlsx/xlsxcelllocation.cpp
  60. 127
      src/QXlsx/xlsxcellrange.cpp
  61. 154
      src/QXlsx/xlsxcellreference.cpp
  62. 2335
      src/QXlsx/xlsxchart.cpp
  63. 142
      src/QXlsx/xlsxchartsheet.cpp
  64. 196
      src/QXlsx/xlsxcolor.cpp
  65. 751
      src/QXlsx/xlsxconditionalformatting.cpp
  66. 184
      src/QXlsx/xlsxcontenttypes.cpp
  67. 537
      src/QXlsx/xlsxdatavalidation.cpp
  68. 85
      src/QXlsx/xlsxdatetype.cpp
  69. 138
      src/QXlsx/xlsxdocpropsapp.cpp
  70. 176
      src/QXlsx/xlsxdocpropscore.cpp
  71. 1454
      src/QXlsx/xlsxdocument.cpp
  72. 84
      src/QXlsx/xlsxdrawing.cpp
  73. 1203
      src/QXlsx/xlsxdrawinganchor.cpp
  74. 1437
      src/QXlsx/xlsxformat.cpp
  75. 78
      src/QXlsx/xlsxmediafile.cpp
  76. 74
      src/QXlsx/xlsxnumformatparser.cpp
  77. 169
      src/QXlsx/xlsxrelationships.cpp
  78. 329
      src/QXlsx/xlsxrichstring.cpp
  79. 382
      src/QXlsx/xlsxsharedstrings.cpp
  80. 37
      src/QXlsx/xlsxsimpleooxmlfile.cpp
  81. 1409
      src/QXlsx/xlsxstyles.cpp
  82. 216
      src/QXlsx/xlsxtheme.cpp
  83. 291
      src/QXlsx/xlsxutility.cpp
  84. 740
      src/QXlsx/xlsxworkbook.cpp
  85. 3083
      src/QXlsx/xlsxworksheet.cpp
  86. 50
      src/QXlsx/xlsxzipreader.cpp
  87. 48
      src/QXlsx/xlsxzipwriter.cpp
  88. 61
      src/XlsxReader.cpp
  89. 38
      src/XlsxXmlConverter.cpp
  90. 44
      src/XmlGenerator.cpp
  91. 71
      src/XmlTemplateReader.cpp

1
.gitignore

@ -0,0 +1 @@
*.pro.user

44
XlsxToXmlConverter.pro

@ -0,0 +1,44 @@
QT += gui
QT += xml
QT += xmlpatterns
TARGET = QXlsx
QT += core
QT += gui-private
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += $$files(src/*.cpp, true)
SOURCES += main.cpp
HEADERS += $$files(include/QXlsx/*.h, true)
HEADERS += $$files(include/*.h, true)
INCLUDEPATH += "$$PWD/include/" \
INCLUDEPATH += "$$PWD/include/QXlsx" \
$$PWD/..
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

48
include/QXlsx/xlsxabstractooxmlfile.h

@ -0,0 +1,48 @@
//xlsxabstractooxmlfile.h
#ifndef QXLSX_XLSXABSTRACTOOXMLFILE_H
#define QXLSX_XLSXABSTRACTOOXMLFILE_H
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class Relationships;
class AbstractOOXmlFilePrivate;
class QXLSX_EXPORT AbstractOOXmlFile
{
Q_DECLARE_PRIVATE(AbstractOOXmlFile)
public:
enum CreateFlag
{
F_NewFromScratch,
F_LoadFromExists
};
public:
virtual ~AbstractOOXmlFile();
virtual void saveToXmlFile(QIODevice* device) const = 0;
virtual bool loadFromXmlFile(QIODevice* device) = 0;
virtual QByteArray saveToXmlData() const;
virtual bool loadFromXmlData(const QByteArray& data);
Relationships* relationships() const;
void setFilePath(const QString path);
QString filePath() const;
protected:
AbstractOOXmlFile(CreateFlag flag);
AbstractOOXmlFile(AbstractOOXmlFilePrivate* d);
AbstractOOXmlFilePrivate* d_ptr;
};
QT_END_NAMESPACE_XLSX
#endif //QXLSX_XLSXABSTRACTOOXMLFILE_H

31
include/QXlsx/xlsxabstractooxmlfile_p.h

@ -0,0 +1,31 @@
// xlsxabstractooxmlfile_p.h
#ifndef XLSXOOXMLFILE_P_H
#define XLSXOOXMLFILE_P_H
#include "xlsxglobal.h"
#include "xlsxabstractooxmlfile.h"
#include "xlsxrelationships_p.h"
QT_BEGIN_NAMESPACE_XLSX
class AbstractOOXmlFilePrivate
{
Q_DECLARE_PUBLIC(AbstractOOXmlFile)
public:
AbstractOOXmlFilePrivate(AbstractOOXmlFile* q, AbstractOOXmlFile::CreateFlag flag);
virtual ~AbstractOOXmlFilePrivate();
public:
QString filePathInPackage; //such as "xl/worksheets/sheet1.xml"
Relationships *relationships;
AbstractOOXmlFile::CreateFlag flag;
AbstractOOXmlFile *q_ptr;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXOOXMLFILE_P_H

49
include/QXlsx/xlsxabstractsheet.h

@ -0,0 +1,49 @@
// xlsxabstractsheet.h
#ifndef XLSXABSTRACTSHEET_H
#define XLSXABSTRACTSHEET_H
#include "xlsxglobal.h"
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class Workbook;
class Drawing;
class AbstractSheetPrivate;
class QXLSX_EXPORT AbstractSheet : public AbstractOOXmlFile
{
Q_DECLARE_PRIVATE(AbstractSheet)
public:
Workbook *workbook() const;
public:
// NOTE: If all Qt compiler supports C++1x, recommend to use a 'class enum'.
enum SheetType { ST_WorkSheet, ST_ChartSheet, ST_DialogSheet, ST_MacroSheet };
enum SheetState { SS_Visible,SS_Hidden, SS_VeryHidden };
public:
QString sheetName() const;
SheetType sheetType() const;
SheetState sheetState() const;
void setSheetState(SheetState ss);
bool isHidden() const;
bool isVisible() const;
void setHidden(bool hidden);
void setVisible(bool visible);
protected:
friend class Workbook;
AbstractSheet(const QString &sheetName, int sheetId, Workbook *book, AbstractSheetPrivate *d);
virtual AbstractSheet *copy(const QString &distName, int distId) const = 0;
void setSheetName(const QString &sheetName);
void setSheetType(SheetType type);
int sheetId() const;
Drawing *drawing() const;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXABSTRACTSHEET_H

36
include/QXlsx/xlsxabstractsheet_p.h

@ -0,0 +1,36 @@
// xlsxabstractsheet_p/h
#ifndef XLSXABSTRACTSHEET_P_H
#define XLSXABSTRACTSHEET_P_H
#include <QString>
#include <memory>
#include "xlsxglobal.h"
#include "xlsxabstractsheet.h"
#include "xlsxabstractooxmlfile_p.h"
#include "xlsxdrawing_p.h"
QT_BEGIN_NAMESPACE_XLSX
class AbstractSheetPrivate : public AbstractOOXmlFilePrivate
{
Q_DECLARE_PUBLIC(AbstractSheet)
public:
AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag);
~AbstractSheetPrivate();
Workbook *workbook;
std::shared_ptr<Drawing> drawing;
QString name;
int id;
AbstractSheet::SheetState sheetState;
AbstractSheet::SheetType type;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXABSTRACTSHEET_P_H

82
include/QXlsx/xlsxcell.h

@ -0,0 +1,82 @@
// xlsxcell.h
#ifndef QXLSX_XLSXCELL_H
#define QXLSX_XLSXCELL_H
#include <cstdio>
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QVariant>
#include <QDate>
#include <QDateTime>
#include <QTime>
#include "xlsxglobal.h"
#include "xlsxformat.h"
QT_BEGIN_NAMESPACE_XLSX
class Worksheet;
class Format;
class CellFormula;
class CellPrivate;
class WorksheetPrivate;
class QXLSX_EXPORT Cell
{
Q_DECLARE_PRIVATE(Cell)
private:
friend class Worksheet;
friend class WorksheetPrivate;
public:
enum CellType // See ECMA 376, 18.18.11. ST_CellType (Cell Type) for more information.
{
BooleanType,
DateType,
ErrorType,
InlineStringType,
NumberType,
SharedStringType,
StringType,
CustomType, // custom or un-defined cell type
};
public:
Cell(const QVariant &data = QVariant(),
CellType type = NumberType,
const Format &format = Format(),
Worksheet *parent = nullptr,
qint32 styleIndex = (-1) );
Cell(const Cell * const cell);
~Cell();
public:
CellPrivate * const d_ptr; // See D-pointer and Q-pointer of Qt, for more information.
public:
CellType cellType() const;
QVariant value() const;
QVariant readValue() const;
Format format() const;
bool hasFormula() const;
CellFormula formula() const;
bool isDateTime() const;
QVariant dateTime() const; // QDateTime, QDate, QTime
bool isRichString() const;
qint32 styleNumber() const;
static bool isDateType(CellType cellType, const Format &format);
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXCELL_H

41
include/QXlsx/xlsxcell_p.h

@ -0,0 +1,41 @@
// xlsxcell_p.h
#ifndef XLSXCELL_P_H
#define XLSXCELL_P_H
#include <QtGlobal>
#include <QObject>
#include <QList>
#include "xlsxglobal.h"
#include "xlsxcell.h"
#include "xlsxcellrange.h"
#include "xlsxrichstring.h"
#include "xlsxcellformula.h"
QT_BEGIN_NAMESPACE_XLSX
class CellPrivate
{
Q_DECLARE_PUBLIC(Cell)
public:
CellPrivate(Cell *p);
CellPrivate(const CellPrivate * const cp);
public:
Worksheet *parent;
Cell *q_ptr;
public:
Cell::CellType cellType;
QVariant value;
CellFormula formula;
Format format;
RichString richString;
qint32 styleNumber;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXCELL_P_H

55
include/QXlsx/xlsxcellformula.h

@ -0,0 +1,55 @@
// xlsxcellformula.h
#ifndef QXLSX_XLSXCELLFORMULA_H
#define QXLSX_XLSXCELLFORMULA_H
#include "xlsxglobal.h"
#include <QExplicitlySharedDataPointer>
class QXmlStreamWriter;
class QXmlStreamReader;
QT_BEGIN_NAMESPACE_XLSX
class CellFormulaPrivate;
class CellRange;
class Worksheet;
class WorksheetPrivate;
class QXLSX_EXPORT CellFormula
{
public:
enum FormulaType { NormalType, ArrayType, DataTableType, SharedType };
public:
CellFormula();
CellFormula(const char *formula, FormulaType type=NormalType);
CellFormula(const QString &formula, FormulaType type=NormalType);
CellFormula(const QString &formula, const CellRange &ref, FormulaType type);
CellFormula(const CellFormula &other);
~CellFormula();
public:
CellFormula &operator =(const CellFormula &other);
bool isValid() const;
FormulaType formulaType() const;
QString formulaText() const;
CellRange reference() const;
int sharedIndex() const;
bool operator == (const CellFormula &formula) const;
bool operator != (const CellFormula &formula) const;
bool saveToXml(QXmlStreamWriter &writer) const;
bool loadFromXml(QXmlStreamReader &reader);
private:
friend class Worksheet;
friend class WorksheetPrivate;
QExplicitlySharedDataPointer<CellFormulaPrivate> d;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXCELLFORMULA_H

31
include/QXlsx/xlsxcellformula_p.h

@ -0,0 +1,31 @@
// xlsxcellformula_p.h
#ifndef XLSXCELLFORMULA_P_H
#define XLSXCELLFORMULA_P_H
#include "xlsxglobal.h"
#include "xlsxcellformula.h"
#include "xlsxcellrange.h"
#include <QSharedData>
#include <QString>
QT_BEGIN_NAMESPACE_XLSX
class CellFormulaPrivate : public QSharedData
{
public:
CellFormulaPrivate(const QString &formula, const CellRange &reference, CellFormula::FormulaType type);
CellFormulaPrivate(const CellFormulaPrivate &other);
~CellFormulaPrivate();
QString formula; //formula contents
CellFormula::FormulaType type;
CellRange reference;
bool ca; //Calculate Cell
int si; //Shared group index
};
QT_END_NAMESPACE_XLSX
#endif // XLSXCELLFORMULA_P_H

33
include/QXlsx/xlsxcelllocation.h

@ -0,0 +1,33 @@
// xlsxcelllocation.h
#ifndef CELL_LOCATION_H
#define CELL_LOCATION_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QVector>
#include <QList>
#include <QMetaType>
#include <memory>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class Cell;
class QXLSX_EXPORT CellLocation
{
public:
CellLocation();
int col;
int row;
std::shared_ptr<Cell> cell;
};
QT_END_NAMESPACE_XLSX
#endif

73
include/QXlsx/xlsxcellrange.h

@ -0,0 +1,73 @@
// xlsxcellrange.h
#ifndef QXLSX_XLSXCELLRANGE_H
#define QXLSX_XLSXCELLRANGE_H
#include <QtGlobal>
#include <QObject>
#include "xlsxglobal.h"
#include "xlsxcellreference.h"
QT_BEGIN_NAMESPACE_XLSX
// dev57
class QXLSX_EXPORT CellRange
{
public:
CellRange();
CellRange(int firstRow, int firstColumn, int lastRow, int lastColumn);
CellRange(const CellReference &topLeft, const CellReference &bottomRight);
CellRange(const QString &range);
CellRange(const char *range);
CellRange(const CellRange &other);
~CellRange();
QString toString(bool row_abs=false, bool col_abs=false) const;
bool isValid() const;
inline void setFirstRow(int row) { top = row; }
inline void setLastRow(int row) { bottom = row; }
inline void setFirstColumn(int col) { left = col; }
inline void setLastColumn(int col) { right = col; }
inline int firstRow() const { return top; }
inline int lastRow() const { return bottom; }
inline int firstColumn() const { return left; }
inline int lastColumn() const { return right; }
inline int rowCount() const { return bottom - top + 1; }
inline int columnCount() const { return right - left + 1; }
inline CellReference topLeft() const { return CellReference(top, left); }
inline CellReference topRight() const { return CellReference(top, right); }
inline CellReference bottomLeft() const { return CellReference(bottom, left); }
inline CellReference bottomRight() const { return CellReference(bottom, right); }
inline void operator =(const CellRange &other)
{
top = other.top;
bottom = other.bottom;
left = other.left;
right = other.right;
}
inline bool operator ==(const CellRange &other) const
{
return top==other.top && bottom==other.bottom
&& left == other.left && right == other.right;
}
inline bool operator !=(const CellRange &other) const
{
return top!=other.top || bottom!=other.bottom
|| left != other.left || right != other.right;
}
private:
void init(const QString &range);
int top;
int left;
int bottom;
int right;
};
QT_END_NAMESPACE_XLSX
Q_DECLARE_TYPEINFO(QXlsx::CellRange, Q_MOVABLE_TYPE);
#endif // QXLSX_XLSXCELLRANGE_H

47
include/QXlsx/xlsxcellreference.h

@ -0,0 +1,47 @@
// xlsxcellreference.h
#ifndef QXLSX_XLSXCELLREFERENCE_H
#define QXLSX_XLSXCELLREFERENCE_H
#include <QtGlobal>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class QXLSX_EXPORT CellReference
{
public:
CellReference();
CellReference(int row, int column);
CellReference(const QString &cell);
CellReference(const char *cell);
CellReference(const CellReference &other);
~CellReference();
QString toString(bool row_abs=false, bool col_abs=false) const;
static CellReference fromString(const QString &cell);
bool isValid() const;
inline void setRow(int row) { _row = row; }
inline void setColumn(int col) { _column = col; }
inline int row() const { return _row; }
inline int column() const { return _column; }
inline bool operator ==(const CellReference &other) const
{
return _row==other._row && _column==other._column;
}
inline bool operator !=(const CellReference &other) const
{
return _row!=other._row || _column!=other._column;
}
private:
void init(const QString &cell);
int _row, _column;
};
QT_END_NAMESPACE_XLSX
Q_DECLARE_TYPEINFO(QXlsx::CellReference, Q_MOVABLE_TYPE);
#endif // QXLSX_XLSXCELLREFERENCE_H

58
include/QXlsx/xlsxchart.h

@ -0,0 +1,58 @@
// xlsxchart.h
#ifndef QXLSX_CHART_H
#define QXLSX_CHART_H
#include <QtGlobal>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class AbstractSheet;
class Worksheet;
class ChartPrivate;
class CellRange;
class DrawingAnchor;
class QXLSX_EXPORT Chart : public AbstractOOXmlFile
{
Q_DECLARE_PRIVATE(Chart)
public:
enum ChartType { // 16 type of chart (ECMA 376)
CT_NoStatementChart = 0, // Zero is internally used for unknown types
CT_AreaChart, CT_Area3DChart, CT_LineChart,
CT_Line3DChart, CT_StockChart, CT_RadarChart,
CT_ScatterChart, CT_PieChart, CT_Pie3DChart,
CT_DoughnutChart, CT_BarChart, CT_Bar3DChart,
CT_OfPieChart, CT_SurfaceChart, CT_Surface3DChart,
CT_BubbleChart,
};
enum ChartAxisPos { None = (-1), Left = 0, Right, Top, Bottom };
private:
friend class AbstractSheet;
friend class Worksheet;
friend class Chartsheet;
friend class DrawingAnchor;
private:
Chart(AbstractSheet *parent, CreateFlag flag);
public:
~Chart();
public:
void addSeries(const CellRange &range, AbstractSheet *sheet = NULL, bool headerH = false, bool headerV = false, bool swapHeaders = false);
void setChartType(ChartType type);
void setChartStyle(int id);
void setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle);
void setChartTitle(QString strchartTitle);
void setChartLegend(Chart::ChartAxisPos legendPos, bool overlap = false);
void setGridlinesEnable(bool majorGridlinesEnable = false, bool minorGridlinesEnable = false);
public:
bool loadFromXmlFile(QIODevice *device) override;
void saveToXmlFile(QIODevice *device) const override;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_CHART_H

148
include/QXlsx/xlsxchart_p.h

@ -0,0 +1,148 @@
// xlsxchart_p.h
#ifndef QXLSX_CHART_P_H
#define QXLSX_CHART_P_H
#include <QObject>
#include <QString>
#include <QVector>
#include <QMap>
#include <QList>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <memory>
#include "xlsxabstractooxmlfile_p.h"
#include "xlsxchart.h"
QT_BEGIN_NAMESPACE_XLSX
class XlsxSeries
{
public:
//At present, we care about number cell ranges only!
QString numberDataSource_numRef; // yval, val
QString axDataSource_numRef; // xval, cat
QString headerH_numRef;
QString headerV_numRef;
bool swapHeader = false;
};
class XlsxAxis
{
public:
enum Type { T_None = (-1), T_Cat, T_Val, T_Date, T_Ser };
enum AxisPos { None = (-1), Left, Right, Top, Bottom };
public:
XlsxAxis(){}
XlsxAxis( Type t,
XlsxAxis::AxisPos p,
int id,
int crossId,
QString axisTitle = QString())
{
type = t;
axisPos = p;
axisId = id;
crossAx = crossId;
if ( !axisTitle.isEmpty() )
{
axisNames[ p ] = axisTitle;
}
}
public:
Type type;
XlsxAxis::AxisPos axisPos;
int axisId;
int crossAx;
QMap< XlsxAxis::AxisPos, QString > axisNames;
};
class ChartPrivate : public AbstractOOXmlFilePrivate
{
Q_DECLARE_PUBLIC(Chart)
public:
ChartPrivate(Chart *q, Chart::CreateFlag flag);
~ChartPrivate();
public:
bool loadXmlChart(QXmlStreamReader &reader);
bool loadXmlPlotArea(QXmlStreamReader &reader);
protected:
bool loadXmlPlotAreaElement(QXmlStreamReader &reader);
public:
bool loadXmlXxxChart(QXmlStreamReader &reader);
bool loadXmlSer(QXmlStreamReader &reader);
QString loadXmlNumRef(QXmlStreamReader &reader);
QString loadXmlStrRef(QXmlStreamReader &reader);
bool loadXmlChartTitle(QXmlStreamReader &reader);
bool loadXmlChartLegend(QXmlStreamReader &reader);
protected:
bool loadXmlChartTitleTx(QXmlStreamReader &reader);
bool loadXmlChartTitleTxRich(QXmlStreamReader &reader);
bool loadXmlChartTitleTxRichP(QXmlStreamReader &reader);
bool loadXmlChartTitleTxRichP_R(QXmlStreamReader &reader);
protected:
bool loadXmlAxisCatAx(QXmlStreamReader &reader);
bool loadXmlAxisDateAx(QXmlStreamReader &reader);
bool loadXmlAxisSerAx(QXmlStreamReader &reader);
bool loadXmlAxisValAx(QXmlStreamReader &reader);
bool loadXmlAxisEG_AxShared(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Scaling(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Overlay(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Tx(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Tx_Rich(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Tx_Rich_P(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(QXmlStreamReader &reader, XlsxAxis* axis);
bool loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(QXmlStreamReader &reader, XlsxAxis* axis);
QString readSubTree(QXmlStreamReader &reader);
public:
void saveXmlChart(QXmlStreamWriter &writer) const;
void saveXmlChartTitle(QXmlStreamWriter &writer) const;
void saveXmlPieChart(QXmlStreamWriter &writer) const;
void saveXmlBarChart(QXmlStreamWriter &writer) const;
void saveXmlLineChart(QXmlStreamWriter &writer) const;
void saveXmlScatterChart(QXmlStreamWriter &writer) const;
void saveXmlAreaChart(QXmlStreamWriter &writer) const;
void saveXmlDoughnutChart(QXmlStreamWriter &writer) const;
void saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const;
void saveXmlAxis(QXmlStreamWriter &writer) const;
void saveXmlChartLegend(QXmlStreamWriter &writer) const;
protected:
void saveXmlAxisCatAx(QXmlStreamWriter &writer, XlsxAxis* axis) const;
void saveXmlAxisDateAx(QXmlStreamWriter &writer, XlsxAxis* axis) const;
void saveXmlAxisSerAx(QXmlStreamWriter &writer, XlsxAxis* axis) const;
void saveXmlAxisValAx(QXmlStreamWriter &writer, XlsxAxis* axis) const;
void saveXmlAxisEG_AxShared(QXmlStreamWriter &writer, XlsxAxis* axis) const;
void saveXmlAxisEG_AxShared_Title(QXmlStreamWriter &writer, XlsxAxis* axis) const;
QString GetAxisPosString( XlsxAxis::AxisPos axisPos ) const;
QString GetAxisName(XlsxAxis* ptrXlsxAxis) const;
public:
Chart::ChartType chartType;
QList< std::shared_ptr<XlsxSeries> > seriesList;
QList< std::shared_ptr<XlsxAxis> > axisList;
QMap< XlsxAxis::AxisPos, QString > axisNames;
QString chartTitle;
AbstractSheet* sheet;
Chart::ChartAxisPos legendPos;
bool legendOverlay;
bool majorGridlinesEnabled;
bool minorGridlinesEnabled;
QString layout; // only for storing a readed file
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_CHART_P_H

38
include/QXlsx/xlsxchartsheet.h

@ -0,0 +1,38 @@
// xlsxchartsheet.h
#ifndef XLSXCHARTSHEET_H
#define XLSXCHARTSHEET_H
#include <QtGlobal>
#include <QStringList>
#include "xlsxabstractsheet.h"
QT_BEGIN_NAMESPACE_XLSX
class Workbook;
class DocumentPrivate;
class ChartsheetPrivate;
class Chart;
class QXLSX_EXPORT Chartsheet : public AbstractSheet
{
Q_DECLARE_PRIVATE(Chartsheet)
public:
~Chartsheet();
Chart *chart();
private:
friend class DocumentPrivate;
friend class Workbook;
Chartsheet(const QString &sheetName, int sheetId, Workbook *book, CreateFlag flag);
Chartsheet *copy(const QString &distName, int distId) const override;
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXCHARTSHEET_H

25
include/QXlsx/xlsxchartsheet_p.h

@ -0,0 +1,25 @@
// xlsxchartsheet_p.h
#ifndef XLSXCHARTSHEET_P_H
#define XLSXCHARTSHEET_P_H
#include <QtGlobal>
#include "xlsxglobal.h"
#include "xlsxchartsheet.h"
#include "xlsxabstractsheet_p.h"
QT_BEGIN_NAMESPACE_XLSX
class ChartsheetPrivate : public AbstractSheetPrivate
{
Q_DECLARE_PUBLIC(Chartsheet)
public:
ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag);
~ChartsheetPrivate();
Chart *chart;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXCHARTSHEET_P_H

59
include/QXlsx/xlsxcolor_p.h

@ -0,0 +1,59 @@
// xlsxcolor_p.h
#ifndef QXLSX_XLSXCOLOR_P_H
#define QXLSX_XLSXCOLOR_P_H
#include <QtGlobal>
#include <QVariant>
#include <QColor>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class Styles;
class XlsxColor
{
public:
explicit XlsxColor(const QColor &color = QColor());
explicit XlsxColor(const QString &theme, const QString &tint=QString());
explicit XlsxColor (int index);
bool isThemeColor() const;
bool isIndexedColor() const;
bool isRgbColor() const;
bool isInvalid() const;
QColor rgbColor() const;
int indexedColor() const;
QStringList themeColor() const;
operator QVariant() const;
static QColor fromARGBString(const QString &c);
static QString toARGBString(const QColor &c);
bool saveToXml(QXmlStreamWriter &writer, const QString &node=QString()) const;
bool loadFromXml(QXmlStreamReader &reader);
private:
QVariant val;
};
#if !defined(QT_NO_DATASTREAM)
QDataStream &operator<<(QDataStream &, const XlsxColor &);
QDataStream &operator>>(QDataStream &, XlsxColor &);
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const XlsxColor &c);
#endif
QT_END_NAMESPACE_XLSX
Q_DECLARE_METATYPE(QXlsx::XlsxColor)
#endif // QXLSX_XLSXCOLOR_P_H

120
include/QXlsx/xlsxconditionalformatting.h

@ -0,0 +1,120 @@
// xlsxconditionalformatting.h
#ifndef QXLSX_XLSXCONDITIONALFORMATTING_H
#define QXLSX_XLSXCONDITIONALFORMATTING_H
#include <QtGlobal>
#include <QString>
#include <QList>
#include <QColor>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QSharedDataPointer>
#include "xlsxglobal.h"
#include "xlsxcellrange.h"
#include "xlsxcellreference.h"
class ConditionalFormattingTest;
QT_BEGIN_NAMESPACE_XLSX
class Format;
class Worksheet;
class Styles;
class ConditionalFormattingPrivate;
class QXLSX_EXPORT ConditionalFormatting
{
public:
enum HighlightRuleType {
Highlight_LessThan,
Highlight_LessThanOrEqual,
Highlight_Equal,
Highlight_NotEqual,
Highlight_GreaterThanOrEqual,
Highlight_GreaterThan,
Highlight_Between,
Highlight_NotBetween,
Highlight_ContainsText,
Highlight_NotContainsText,
Highlight_BeginsWith,
Highlight_EndsWith,
Highlight_TimePeriod,
Highlight_Duplicate,
Highlight_Unique,
Highlight_Blanks,
Highlight_NoBlanks,
Highlight_Errors,
Highlight_NoErrors,
Highlight_Top,
Highlight_TopPercent,
Highlight_Bottom,
Highlight_BottomPercent,
Highlight_AboveAverage,
Highlight_AboveOrEqualAverage,
Highlight_AboveStdDev1,
Highlight_AboveStdDev2,
Highlight_AboveStdDev3,
Highlight_BelowAverage,
Highlight_BelowOrEqualAverage,
Highlight_BelowStdDev1,
Highlight_BelowStdDev2,
Highlight_BelowStdDev3,
Highlight_Expression
};
enum ValueObjectType
{
VOT_Formula,
VOT_Max,
VOT_Min,
VOT_Num,
VOT_Percent,
VOT_Percentile
};
public:
ConditionalFormatting();
ConditionalFormatting(const ConditionalFormatting &other);
~ConditionalFormatting();
public:
bool addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue=false);
bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const Format &format, bool stopIfTrue=false);
bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue=false);
bool addDataBarRule(const QColor &color, bool showData=true, bool stopIfTrue=false);
bool addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData=true, bool stopIfTrue=false);
bool add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue=false);
bool add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue=false);
QList<CellRange> ranges() const;
void addCell(const CellReference &cell);
void addCell(int row, int col);
void addRange(int firstRow, int firstCol, int lastRow, int lastCol);
void addRange(const CellRange &range);
//needed by QSharedDataPointer!!
ConditionalFormatting &operator=(const ConditionalFormatting &other);
private:
friend class Worksheet;
friend class ::ConditionalFormattingTest;
private:
bool saveToXml(QXmlStreamWriter &writer) const;
bool loadFromXml(QXmlStreamReader &reader, Styles* styles = NULL);
QSharedDataPointer<ConditionalFormattingPrivate> d;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXCONDITIONALFORMATTING_H

99
include/QXlsx/xlsxconditionalformatting_p.h

@ -0,0 +1,99 @@
// xlsxconditionalformatting_p.h
#ifndef XLSXCONDITIONALFORMATTING_P_H
#define XLSXCONDITIONALFORMATTING_P_H
#include <QSharedData>
#include <QMap>
#include <memory>
#include "xlsxconditionalformatting.h"
#include "xlsxformat.h"
#include "xlsxcolor_p.h"
QT_BEGIN_NAMESPACE_XLSX
class XlsxCfVoData
{
public:
XlsxCfVoData()
:gte(true)
{
}
XlsxCfVoData(ConditionalFormatting::ValueObjectType type, const QString &value, bool gte=true)
:type(type), value(value), gte(gte)
{
}
ConditionalFormatting::ValueObjectType type;
QString value;
bool gte;
};
class XlsxCfRuleData
{
public:
enum Attribute {
A_type,
A_dxfId,
//A_priority,
A_stopIfTrue,
A_aboveAverage,
A_percent,
A_bottom,
A_operator,
A_text,
A_timePeriod,
A_rank,
A_stdDev,
A_equalAverage,
A_dxfFormat,
A_formula1,
A_formula2,
A_formula3,
A_formula1_temp,
A_color1,
A_color2,
A_color3,
A_cfvo1,
A_cfvo2,
A_cfvo3,
A_hideData
};
XlsxCfRuleData()
:priority(1)
{}
int priority;
Format dxfFormat;
QMap<int, QVariant> attrs;
};
class ConditionalFormattingPrivate : public QSharedData
{
public:
ConditionalFormattingPrivate();
ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other);
~ConditionalFormattingPrivate();
void writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData& cfvo) const;
bool readCfVo(QXmlStreamReader &reader, XlsxCfVoData& cfvo);
bool readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *cfRule, Styles *styles);
bool readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *cfRule);
bool readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *cfRule);
QList<std::shared_ptr<XlsxCfRuleData> >cfRules;
QList<CellRange> ranges;
};
QT_END_NAMESPACE_XLSX
Q_DECLARE_METATYPE(QXlsx::XlsxCfVoData)
#endif // XLSXCONDITIONALFORMATTING_P_H

55
include/QXlsx/xlsxcontenttypes_p.h

@ -0,0 +1,55 @@
// xlsxcontenttypes_p.h
#ifndef XLSXCONTENTTYPES_H
#define XLSXCONTENTTYPES_H
#include <QtGlobal>
#include <QString>
#include <QStringList>
#include <QMap>
#include <QIODevice>
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class ContentTypes : public AbstractOOXmlFile
{
public:
ContentTypes(CreateFlag flag);
void addDefault(const QString &key, const QString &value);
void addOverride(const QString &key, const QString &value);
//Convenient funcation for addOverride()
void addDocPropCore();
void addDocPropApp();
void addStyles();
void addTheme();
void addWorkbook();
void addWorksheetName(const QString &name);
void addChartsheetName(const QString &name);
void addChartName(const QString &name);
void addDrawingName(const QString &name);
void addCommentName(const QString &name);
void addTableName(const QString &name);
void addExternalLinkName(const QString &name);
void addSharedString();
void addVmlName();
void addCalcChain();
void addVbaProject();
void clearOverrides();
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
private:
QMap<QString, QString> m_defaults;
QMap<QString, QString> m_overrides;
QString m_package_prefix;
QString m_document_prefix;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXCONTENTTYPES_H

105
include/QXlsx/xlsxdatavalidation.h

@ -0,0 +1,105 @@
// xlsxvalidation.h
#ifndef QXLSX_XLSXDATAVALIDATION_H
#define QXLSX_XLSXDATAVALIDATION_H
#include <QtGlobal>
#include <QSharedDataPointer>
#include <QString>
#include <QList>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include "xlsxglobal.h"
class QXmlStreamReader;
class QXmlStreamWriter;
QT_BEGIN_NAMESPACE_XLSX
class Worksheet;
class CellRange;
class CellReference;
class DataValidationPrivate;
class QXLSX_EXPORT DataValidation
{
public:
enum ValidationType
{
None,
Whole,
Decimal,
List,
Date,
Time,
TextLength,
Custom
};
enum ValidationOperator
{
Between,
NotBetween,
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual
};
enum ErrorStyle
{
Stop,
Warning,
Information
};
DataValidation();
DataValidation(ValidationType type, ValidationOperator op=Between, const QString &formula1=QString()
, const QString &formula2=QString(), bool allowBlank=false);
DataValidation(const DataValidation &other);
~DataValidation();
ValidationType validationType() const;
ValidationOperator validationOperator() const;
ErrorStyle errorStyle() const;
QString formula1() const;
QString formula2() const;
bool allowBlank() const;
QString errorMessage() const;
QString errorMessageTitle() const;
QString promptMessage() const;
QString promptMessageTitle() const;
bool isPromptMessageVisible() const;
bool isErrorMessageVisible() const;
QList<CellRange> ranges() const;
void setValidationType(ValidationType type);
void setValidationOperator(ValidationOperator op);
void setErrorStyle(ErrorStyle es);
void setFormula1(const QString &formula);
void setFormula2(const QString &formula);
void setErrorMessage(const QString &error, const QString &title=QString());
void setPromptMessage(const QString &prompt, const QString &title=QString());
void setAllowBlank(bool enable);
void setPromptMessageVisible(bool visible);
void setErrorMessageVisible(bool visible);
void addCell(const CellReference &cell);
void addCell(int row, int col);
void addRange(int firstRow, int firstCol, int lastRow, int lastCol);
void addRange(const CellRange &range);
DataValidation &operator=(const DataValidation &other);
bool saveToXml(QXmlStreamWriter &writer) const;
static DataValidation loadFromXml(QXmlStreamReader &reader);
private:
QSharedDataPointer<DataValidationPrivate> d;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXDATAVALIDATION_H

37
include/QXlsx/xlsxdatavalidation_p.h

@ -0,0 +1,37 @@
// xlsxdatavalidation_p.h
#ifndef XLSXDATAVALIDATION_P_H
#define XLSXDATAVALIDATION_P_H
#include <QtGlobal>
#include <QSharedData>
#include "xlsxdatavalidation.h"
QT_BEGIN_NAMESPACE_XLSX
class DataValidationPrivate : public QSharedData
{
public:
DataValidationPrivate();
DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank);
DataValidationPrivate(const DataValidationPrivate &other);
~DataValidationPrivate();
DataValidation::ValidationType validationType;
DataValidation::ValidationOperator validationOperator;
DataValidation::ErrorStyle errorStyle;
bool allowBlank;
bool isPromptMessageVisible;
bool isErrorMessageVisible;
QString formula1;
QString formula2;
QString errorMessage;
QString errorMessageTitle;
QString promptMessage;
QString promptMessageTitle;
QList<CellRange> ranges;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXDATAVALIDATION_P_H

48
include/QXlsx/xlsxdatetype.h

@ -0,0 +1,48 @@
// xlsxdatetype.h
#ifndef QXLSX_XLSXDATETYPE_H
#define QXLSX_XLSXDATETYPE_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QDateTime>
#include <QDate>
#include <QTime>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class QXLSX_EXPORT DateType
{
public:
DateType();
/*
DateType(bool is1904 = false);
DateType(double d, bool is1904 = false);
DateType(QDateTime qdt, bool is1904 = false);
DateType(QDate qd, bool is1904 = false);
DateType(QTime qt, bool is1904 = false);
public:
enum currentDateType { DateAndTimeType, OnlyDateType, OnlyTimeType };
public:
currentDateType getType();
bool getValue(QDateTime* pQdt);
bool getValue(QDate* pQd);
bool getValue(QTime* pQt);
bool getValue(double* pD);
protected:
protected:
bool isSet;
double dValue;
bool is1904Type;
currentDateType dType;
*/
};
QT_END_NAMESPACE_XLSX
#endif

40
include/QXlsx/xlsxdocpropsapp_p.h

@ -0,0 +1,40 @@
// xlsxdocpropsapp_p.h
#ifndef XLSXDOCPROPSAPP_H
#define XLSXDOCPROPSAPP_H
#include <QList>
#include <QStringList>
#include <QMap>
#include "xlsxglobal.h"
#include "xlsxabstractooxmlfile.h"
class QIODevice;
QT_BEGIN_NAMESPACE_XLSX
class DocPropsApp : public AbstractOOXmlFile
{
public:
DocPropsApp(CreateFlag flag);
void addPartTitle(const QString &title);
void addHeadingPair(const QString &name, int value);
bool setProperty(const QString &name, const QString &value);
QString property(const QString &name) const;
QStringList propertyNames() const;
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
private:
QStringList m_titlesOfPartsList;
QList<std::pair<QString, int> > m_headingPairsList;
QMap<QString, QString> m_properties;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXDOCPROPSAPP_H

34
include/QXlsx/xlsxdocpropscore_p.h

@ -0,0 +1,34 @@
// xlsxdocpropscore_p.h
#ifndef XLSXDOCPROPSCORE_H
#define XLSXDOCPROPSCORE_H
#include "xlsxglobal.h"
#include "xlsxabstractooxmlfile.h"
#include <QMap>
#include <QStringList>
class QIODevice;
QT_BEGIN_NAMESPACE_XLSX
class DocPropsCore : public AbstractOOXmlFile
{
public:
explicit DocPropsCore(CreateFlag flag);
bool setProperty(const QString &name, const QString &value);
QString property(const QString &name) const;
QStringList propertyNames() const;
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
private:
QMap<QString, QString> m_properties;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXDOCPROPSCORE_H

143
include/QXlsx/xlsxdocument.h

@ -0,0 +1,143 @@
// xlsxdocument.h
#ifndef QXLSX_XLSXDOCUMENT_H
#define QXLSX_XLSXDOCUMENT_H
#include <QtGlobal>
#include <QObject>
#include <QVariant>
#include <QIODevice>
#include <QImage>
#include "xlsxglobal.h"
#include "xlsxformat.h"
#include "xlsxworksheet.h"
QT_BEGIN_NAMESPACE_XLSX
class Workbook;
class Cell;
class CellRange;
class DataValidation;
class ConditionalFormatting;
class Chart;
class CellReference;
class DocumentPrivate;
class QXLSX_EXPORT Document : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(Document) // D-Pointer. Qt classes have a Q_DECLARE_PRIVATE
// macro in the public class. The macro reads: qglobal.h
public:
explicit Document(QObject *parent = nullptr);
Document(const QString& xlsxName, QObject* parent = nullptr);
Document(QIODevice* device, QObject* parent = nullptr);
~Document();
bool write(const CellReference &cell, const QVariant &value, const Format &format=Format());
bool write(int row, int col, const QVariant &value, const Format &format=Format());
QVariant read(const CellReference &cell) const;
QVariant read(int row, int col) const;
int insertImage(int row, int col, const QImage &image);
bool getImage(int imageIndex, QImage& img);
bool getImage(int row, int col, QImage& img);
uint getImageCount();
Chart *insertChart(int row, int col, const QSize &size);
bool mergeCells(const CellRange &range, const Format &format=Format());
bool unmergeCells(const CellRange &range);
bool setColumnWidth(const CellRange &range, double width);
bool setColumnFormat(const CellRange &range, const Format &format);
bool setColumnHidden(const CellRange &range, bool hidden);
bool setColumnWidth(int column, double width);
bool setColumnFormat(int column, const Format &format);
bool setColumnHidden(int column, bool hidden);
bool setColumnWidth(int colFirst, int colLast, double width);
bool setColumnFormat(int colFirst, int colLast, const Format &format);
bool setColumnHidden(int colFirst, int colLast, bool hidden);
double columnWidth(int column);
Format columnFormat(int column);
bool isColumnHidden(int column);
bool setRowHeight(int row, double height);
bool setRowFormat(int row, const Format &format);
bool setRowHidden(int row, bool hidden);
bool setRowHeight(int rowFirst, int rowLast, double height);
bool setRowFormat(int rowFirst, int rowLast, const Format &format);
bool setRowHidden(int rowFirst, int rowLast, bool hidden);
double rowHeight(int row);
Format rowFormat(int row);
bool isRowHidden(int row);
bool groupRows(int rowFirst, int rowLast, bool collapsed = true);
bool groupColumns(int colFirst, int colLast, bool collapsed = true);
bool addDataValidation(const DataValidation &validation);
bool addConditionalFormatting(const ConditionalFormatting &cf);
Cell *cellAt(const CellReference &cell) const;
Cell *cellAt(int row, int col) const;
bool defineName(const QString &name, const QString &formula,
const QString &comment=QString(), const QString &scope=QString());
CellRange dimension() const;
QString documentProperty(const QString &name) const;
void setDocumentProperty(const QString &name, const QString &property);
QStringList documentPropertyNames() const;
QStringList sheetNames() const;
bool addSheet(const QString &name = QString(),
AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
bool insertSheet(int index, const QString &name = QString(),
AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
bool selectSheet(const QString &name);
bool selectSheet(int index);
bool renameSheet(const QString &oldName, const QString &newName);
bool copySheet(const QString &srcName, const QString &distName = QString());
bool moveSheet(const QString &srcName, int distIndex);
bool deleteSheet(const QString &name);
Workbook *workbook() const;
AbstractSheet *sheet(const QString &sheetName) const;
AbstractSheet *currentSheet() const;
Worksheet *currentWorksheet() const;
bool save() const;
bool saveAs(const QString &xlsXname) const;
bool saveAs(QIODevice *device) const;
// copy style from one xlsx file to other
static bool copyStyle(const QString &from, const QString &to);
bool isLoadPackage() const;
bool load() const; // equals to isLoadPackage()
bool changeimage(int filenoinmidea,QString newfile); // add by liufeijin20181025
bool autosizeColumnWidth(const CellRange &range);
bool autosizeColumnWidth(int column);
bool autosizeColumnWidth(int colFirst, int colLast);
bool autosizeColumnWidth(void);
private:
QMap<int, int> getMaximalColumnWidth(int firstRow=1, int lastRow=INT_MAX);
private:
Q_DISABLE_COPY(Document) // Disables the use of copy constructors and
// assignment operators for the given Class.
DocumentPrivate* const d_ptr;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXDOCUMENT_H

41
include/QXlsx/xlsxdocument_p.h

@ -0,0 +1,41 @@
// xlsxdocument_p.h
#ifndef XLSXDOCUMENT_P_H
#define XLSXDOCUMENT_P_H
#include <QtGlobal>
#include <QMap>
#include "xlsxglobal.h"
#include "xlsxdocument.h"
#include "xlsxworkbook.h"
#include "xlsxcontenttypes_p.h"
QT_BEGIN_NAMESPACE_XLSX
class DocumentPrivate
{
Q_DECLARE_PUBLIC(Document)
public:
DocumentPrivate(Document *p);
void init();
bool loadPackage(QIODevice *device);
bool savePackage(QIODevice *device) const;
// copy style from one xlsx file to other
static bool copyStyle(const QString &from, const QString &to);
Document *q_ptr;
const QString defaultPackageName; //default name when package name not specified
QString packageName; //name of the .xlsx file
QMap<QString, QString> documentProperties; //core, app and custom properties
QSharedPointer<Workbook> workbook;
std::shared_ptr<ContentTypes> contentTypes;
bool isLoad;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXDOCUMENT_P_H

38
include/QXlsx/xlsxdrawing_p.h

@ -0,0 +1,38 @@
// xlsxdrwaing_p.h
#ifndef QXLSX_DRAWING_H
#define QXLSX_DRAWING_H
#include <QtGlobal>
#include <QList>
#include <QString>
#include "xlsxrelationships_p.h"
#include "xlsxabstractooxmlfile.h"
class QIODevice;
class QXmlStreamWriter;
QT_BEGIN_NAMESPACE_XLSX
class DrawingAnchor;
class Workbook;
class AbstractSheet;
class MediaFile;
class Drawing : public AbstractOOXmlFile
{
public:
Drawing(AbstractSheet *sheet, CreateFlag flag);
~Drawing();
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
AbstractSheet *sheet;
Workbook *workbook;
QList<DrawingAnchor *> anchors;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_DRAWING_H

169
include/QXlsx/xlsxdrawinganchor_p.h

@ -0,0 +1,169 @@
// xlsxdrawinganchor_p.h
#ifndef QXLSX_XLSXDRAWINGANCHOR_P_H
#define QXLSX_XLSXDRAWINGANCHOR_P_H
#include <QPoint>
#include <QSize>
#include <QString>
#include <QSharedPointer>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <memory>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class Drawing;
class MediaFile;
class Chart;
//Helper class
struct XlsxMarker
{
XlsxMarker(){}
XlsxMarker(int row, int column, int rowOffset, int colOffset)
:cell(QPoint(row, column)), offset(rowOffset, colOffset)
{
}
int row() const {return cell.x();}
int col() const {return cell.y();}
int rowOff() const {return offset.width();}
int colOff() const {return offset.height();}
QPoint cell;
QSize offset;
};
class DrawingAnchor
{
public:
enum ObjectType {
GraphicFrame,
Shape,
GroupShape,
ConnectionShape,
Picture,
Unknown
};
DrawingAnchor(Drawing *drawing, ObjectType objectType);
virtual ~DrawingAnchor();
void setObjectPicture(const QImage &img);
bool getObjectPicture(QImage &img);
void setObjectGraphicFrame(QSharedPointer<Chart> chart);
virtual bool loadFromXml(QXmlStreamReader &reader) = 0;
virtual void saveToXml(QXmlStreamWriter &writer) const = 0;
virtual int row() const;
virtual int col() const;
protected:
QPoint loadXmlPos(QXmlStreamReader &reader);
QSize loadXmlExt(QXmlStreamReader &reader);
XlsxMarker loadXmlMarker(QXmlStreamReader &reader, const QString &node);
void loadXmlObject(QXmlStreamReader &reader);
void loadXmlObjectShape(QXmlStreamReader &reader);
void loadXmlObjectGroupShape(QXmlStreamReader &reader);
void loadXmlObjectGraphicFrame(QXmlStreamReader &reader);
void loadXmlObjectConnectionShape(QXmlStreamReader &reader);
void loadXmlObjectPicture(QXmlStreamReader &reader);
void saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const;
void saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const;
void saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const;
void saveXmlObject(QXmlStreamWriter &writer) const;
void saveXmlObjectShape(QXmlStreamWriter &writer) const;
void saveXmlObjectGroupShape(QXmlStreamWriter &writer) const;
void saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const;
void saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const;
void saveXmlObjectPicture(QXmlStreamWriter &writer) const;
Drawing *m_drawing;
ObjectType m_objectType;
std::shared_ptr<MediaFile> m_pictureFile;
QSharedPointer<Chart> m_chartFile;
int m_id;
public:
int getm_id();
protected:
// liufeij {{
void setObjectShape(const QImage &img); // liufeij
QString editASName;
// below only for twocellanchor shape
QPoint posTA; // for shape liufeij 20181024
QSize extTA; // for shape liufeij 20181024
int rotWithShapeTA; //// for shape liufeij 20181024
int dpiTA; //// for shape liufeij 20181024
QString sp_textlink,sp_macro,sp_blip_cstate,sp_blip_rembed;
// BELOW only for cxnSp shape
QString cxnSp_filpV,cxnSp_macro;
// belwo for cxnsp and sp
QString xsp_cNvPR_name,xsp_cNvPR_id; //x measns shape and cxnSp together using
QString xbwMode; // same as above
QString xIn_algn,xIn_cmpd,xIn_cap,xIn_w; //cxnSp only need xIn_w
QString xprstGeom_prst;
QString x_headEnd_w,x_headEnd_len,x_headEnd_tyep;
QString x_tailEnd_w,x_tailEnd_len,x_tailEnd_tyep;
QString Style_inref_idx,style_fillref_idx,style_effectref_idx,style_forntref_idx;
QString Style_inref_val,style_fillref_val,style_effectref_val,style_forntref_val;
// liufeij }}
};
class DrawingAbsoluteAnchor : public DrawingAnchor
{
public:
DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType=Unknown);
QPoint pos;
QSize ext;
bool loadFromXml(QXmlStreamReader &reader) override;
void saveToXml(QXmlStreamWriter &writer) const override;
};
class DrawingOneCellAnchor : public DrawingAnchor
{
public:
DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType=Unknown);
XlsxMarker from;
QSize ext;
int row() const override;
int col() const override;
bool loadFromXml(QXmlStreamReader &reader) override;
void saveToXml(QXmlStreamWriter &writer) const override;
};
class DrawingTwoCellAnchor : public DrawingAnchor
{
public:
DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType=Unknown);
XlsxMarker from;
XlsxMarker to;
int row() const override;
int col() const override;
bool loadFromXml(QXmlStreamReader &reader) override;
void saveToXml(QXmlStreamWriter &writer) const override;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXDRAWINGANCHOR_P_H

262
include/QXlsx/xlsxformat.h

@ -0,0 +1,262 @@
// xlsxformat.h
#ifndef QXLSX_FORMAT_H
#define QXLSX_FORMAT_H
#include <QFont>
#include <QColor>
#include <QByteArray>
#include <QList>
#include <QExplicitlySharedDataPointer>
#include <QVariant>
#include "xlsxglobal.h"
class FormatTest;
QT_BEGIN_NAMESPACE_XLSX
class Styles;
class Worksheet;
class WorksheetPrivate;
class RichStringPrivate;
class SharedStrings;
class FormatPrivate;
class QXLSX_EXPORT Format
{
public:
enum FontScript
{
FontScriptNormal,
FontScriptSuper,
FontScriptSub
};
enum FontUnderline
{
FontUnderlineNone,
FontUnderlineSingle,
FontUnderlineDouble,
FontUnderlineSingleAccounting,
FontUnderlineDoubleAccounting
};
enum HorizontalAlignment
{
AlignHGeneral,
AlignLeft,
AlignHCenter,
AlignRight,
AlignHFill,
AlignHJustify,
AlignHMerge,
AlignHDistributed
};
enum VerticalAlignment
{
AlignTop,
AlignVCenter,
AlignBottom,
AlignVJustify,
AlignVDistributed
};
enum BorderStyle
{
BorderNone,
BorderThin,
BorderMedium,
BorderDashed,
BorderDotted,
BorderThick,
BorderDouble,
BorderHair,
BorderMediumDashed,
BorderDashDot,
BorderMediumDashDot,
BorderDashDotDot,
BorderMediumDashDotDot,
BorderSlantDashDot
};
enum DiagonalBorderType
{
DiagonalBorderNone,
DiagonalBorderDown,
DiagonalBorderUp,
DiagnoalBorderBoth
};
enum FillPattern
{
PatternNone,
PatternSolid,
PatternMediumGray,
PatternDarkGray,
PatternLightGray,
PatternDarkHorizontal,
PatternDarkVertical,
PatternDarkDown,
PatternDarkUp,
PatternDarkGrid,
PatternDarkTrellis,
PatternLightHorizontal,
PatternLightVertical,
PatternLightDown,
PatternLightUp,
PatternLightTrellis,
PatternGray125,
PatternGray0625,
PatternLightGrid
};
Format();
Format(const Format &other);
Format &operator=(const Format &rhs);
~Format();
int numberFormatIndex() const;
void setNumberFormatIndex(int format);
QString numberFormat() const;
void setNumberFormat(const QString &format);
void setNumberFormat(int id, const QString &format);
bool isDateTimeFormat() const;
int fontSize() const;
void setFontSize(int size);
bool fontItalic() const;
void setFontItalic(bool italic);
bool fontStrikeOut() const;
void setFontStrikeOut(bool);
QColor fontColor() const;
void setFontColor(const QColor &);
bool fontBold() const;
void setFontBold(bool bold);
FontScript fontScript() const;
void setFontScript(FontScript);
FontUnderline fontUnderline() const;
void setFontUnderline(FontUnderline);
bool fontOutline() const;
void setFontOutline(bool outline);
QString fontName() const;
void setFontName(const QString &);
QFont font() const;
void setFont(const QFont &font);
HorizontalAlignment horizontalAlignment() const;
void setHorizontalAlignment(HorizontalAlignment align);
VerticalAlignment verticalAlignment() const;
void setVerticalAlignment(VerticalAlignment align);
bool textWrap() const;
void setTextWrap(bool textWrap);
int rotation() const;
void setRotation(int rotation);
int indent() const;
void setIndent(int indent);
bool shrinkToFit() const;
void setShrinkToFit(bool shink);
void setBorderStyle(BorderStyle style);
void setBorderColor(const QColor &color);
BorderStyle leftBorderStyle() const;
void setLeftBorderStyle(BorderStyle style);
QColor leftBorderColor() const;
void setLeftBorderColor(const QColor &color);
BorderStyle rightBorderStyle() const;
void setRightBorderStyle(BorderStyle style);
QColor rightBorderColor() const;
void setRightBorderColor(const QColor &color);
BorderStyle topBorderStyle() const;
void setTopBorderStyle(BorderStyle style);
QColor topBorderColor() const;
void setTopBorderColor(const QColor &color);
BorderStyle bottomBorderStyle() const;
void setBottomBorderStyle(BorderStyle style);
QColor bottomBorderColor() const;
void setBottomBorderColor(const QColor &color);
BorderStyle diagonalBorderStyle() const;
void setDiagonalBorderStyle(BorderStyle style);
DiagonalBorderType diagonalBorderType() const;
void setDiagonalBorderType(DiagonalBorderType style);
QColor diagonalBorderColor() const;
void setDiagonalBorderColor(const QColor &color);
FillPattern fillPattern() const;
void setFillPattern(FillPattern pattern);
QColor patternForegroundColor() const;
void setPatternForegroundColor(const QColor &color);
QColor patternBackgroundColor() const;
void setPatternBackgroundColor(const QColor &color);
bool locked() const;
void setLocked(bool locked);
bool hidden() const;
void setHidden(bool hidden);
void mergeFormat(const Format &modifier);
bool isValid() const;
bool isEmpty() const;
bool operator == (const Format &format) const;
bool operator != (const Format &format) const;
QVariant property(int propertyId, const QVariant &defaultValue=QVariant()) const;
void setProperty(int propertyId, const QVariant &value, const QVariant &clearValue=QVariant(), bool detach=true);
void clearProperty(int propertyId);
bool hasProperty(int propertyId) const;
bool boolProperty(int propertyId, bool defaultValue=false) const;
int intProperty(int propertyId, int defaultValue=0) const;
double doubleProperty(int propertyId, double defaultValue = 0.0) const;
QString stringProperty(int propertyId, const QString &defaultValue = QString()) const;
QColor colorProperty(int propertyId, const QColor &defaultValue = QColor()) const;
bool hasNumFmtData() const;
bool hasFontData() const;
bool hasFillData() const;
bool hasBorderData() const;
bool hasAlignmentData() const;
bool hasProtectionData() const;
bool fontIndexValid() const;
int fontIndex() const;
QByteArray fontKey() const;
bool borderIndexValid() const;
QByteArray borderKey() const;
int borderIndex() const;
bool fillIndexValid() const;
QByteArray fillKey() const;
int fillIndex() const;
QByteArray formatKey() const;
bool xfIndexValid() const;
int xfIndex() const;
bool dxfIndexValid() const;
int dxfIndex() const;
void fixNumberFormat(int id, const QString &format);
void setFontIndex(int index);
void setBorderIndex(int index);
void setFillIndex(int index);
void setXfIndex(int index);
void setDxfIndex(int index);
private:
friend class Styles;
friend class ::FormatTest;
friend QDebug operator<<(QDebug, const Format &f);
int theme() const;
QExplicitlySharedDataPointer<FormatPrivate> d;
};
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const Format &f);
#endif
QT_END_NAMESPACE_XLSX
#endif // QXLSX_FORMAT_H

130
include/QXlsx/xlsxformat_p.h

@ -0,0 +1,130 @@
// xlsxformat_p.h
#ifndef XLSXFORMAT_P_H
#define XLSXFORMAT_P_H
#include <QtGlobal>
#include <QSharedData>
#include <QMap>
#include <QSet>
#include "xlsxformat.h"
QT_BEGIN_NAMESPACE_XLSX
class FormatPrivate : public QSharedData
{
public:
enum FormatType
{
FT_Invalid = 0,
FT_NumFmt = 0x01,
FT_Font = 0x02,
FT_Alignment = 0x04,
FT_Border = 0x08,
FT_Fill = 0x10,
FT_Protection = 0x20
};
enum Property {
P_STARTID,
//numFmt
P_NumFmt_Id,
P_NumFmt_FormatCode,
//font
P_Font_STARTID,
P_Font_Size = P_Font_STARTID,
P_Font_Italic,
P_Font_StrikeOut,
P_Font_Color,
P_Font_Bold,
P_Font_Script,
P_Font_Underline,
P_Font_Outline,
P_Font_Shadow,
P_Font_Name,
P_Font_Family,
P_Font_Charset,
P_Font_Scheme,
P_Font_Condense,
P_Font_Extend,
P_Font_ENDID,
//border
P_Border_STARTID,
P_Border_LeftStyle = P_Border_STARTID,
P_Border_RightStyle,
P_Border_TopStyle,
P_Border_BottomStyle,
P_Border_DiagonalStyle,
P_Border_LeftColor,
P_Border_RightColor,
P_Border_TopColor,
P_Border_BottomColor,
P_Border_DiagonalColor,
P_Border_DiagonalType,
P_Border_ENDID,
//fill
P_Fill_STARTID,
P_Fill_Pattern = P_Fill_STARTID,
P_Fill_BgColor,
P_Fill_FgColor,
P_Fill_ENDID,
//alignment
P_Alignment_STARTID,
P_Alignment_AlignH = P_Alignment_STARTID,
P_Alignment_AlignV,
P_Alignment_Wrap,
P_Alignment_Rotation,
P_Alignment_Indent,
P_Alignment_ShinkToFit,
P_Alignment_ENDID,
//protection
P_Protection_Locked,
P_Protection_Hidden,
P_ENDID
};
FormatPrivate();
FormatPrivate(const FormatPrivate &other);
~FormatPrivate();
bool dirty; //The key re-generation is need.
QByteArray formatKey;
bool font_dirty;
bool font_index_valid;
QByteArray font_key;
int font_index;
bool fill_dirty;
bool fill_index_valid;
QByteArray fill_key;
int fill_index;
bool border_dirty;
bool border_index_valid;
QByteArray border_key;
int border_index;
int xf_index;
bool xf_indexValid;
bool is_dxf_fomat;
int dxf_index;
bool dxf_indexValid;
int theme;
QMap<int, QVariant> properties;
};
QT_END_NAMESPACE_XLSX
#endif

33
include/QXlsx/xlsxglobal.h

@ -0,0 +1,33 @@
// xlsxglobal.h
#ifndef XLSXGLOBAL_H
#define XLSXGLOBAL_H
#include <cstdio>
#include <string>
#include <iostream>
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QVariant>
#include <QIODevice>
#include <QByteArray>
#include <QStringList>
#if defined(QXlsx_SHAREDLIB)
#if defined(QXlsx_EXPORTS)
# define QXLSX_EXPORT Q_DECL_EXPORT
#else
# define QXLSX_EXPORT Q_DECL_IMPORT
#endif
#else
# define QXLSX_EXPORT
#endif
#define QT_BEGIN_NAMESPACE_XLSX namespace QXlsx {
#define QT_END_NAMESPACE_XLSX }
#define QXLSX_USE_NAMESPACE using namespace QXlsx;
#endif // XLSXGLOBAL_H

46
include/QXlsx/xlsxmediafile_p.h

@ -0,0 +1,46 @@
// xlsxmediafile_p.h
#ifndef QXLSX_XLSXMEDIAFILE_H
#define QXLSX_XLSXMEDIAFILE_H
#include "xlsxglobal.h"
#include <QString>
#include <QByteArray>
QT_BEGIN_NAMESPACE_XLSX
class MediaFile
{
public:
MediaFile(const QString &fileName);
MediaFile(const QByteArray &bytes, const QString &suffix, const QString &mimeType=QString());
public:
void set(const QByteArray &bytes, const QString &suffix, const QString &mimeType=QString());
QString suffix() const;
QString mimeType() const;
QByteArray contents() const;
bool isIndexValid() const;
int index() const;
void setIndex(int idx);
QByteArray hashKey() const;
void setFileName(const QString &name);
QString fileName() const;
protected:
QString m_fileName;
QByteArray m_contents;
QString m_suffix;
QString m_mimeType;
int m_index;
bool m_indexValid;
QByteArray m_hashKey;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXMEDIAFILE_H

51
include/QXlsx/xlsxnumformatparser_p.h

@ -0,0 +1,51 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 QXLSX_NUMFORMATPARSER_H
#define QXLSX_NUMFORMATPARSER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class NumFormatParser
{
public:
static bool isDateTime(const QString &formatCode);
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_NUMFORMATPARSER_H

89
include/QXlsx/xlsxrelationships_p.h

@ -0,0 +1,89 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXRELATIONSHIPS_H
#define XLSXRELATIONSHIPS_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "xlsxglobal.h"
#include <QList>
#include <QString>
#include <QIODevice>
QT_BEGIN_NAMESPACE_XLSX
struct XlsxRelationship
{
QString id;
QString type;
QString target;
QString targetMode;
};
class Relationships
{
public:
Relationships();
QList<XlsxRelationship> documentRelationships(const QString &relativeType) const;
QList<XlsxRelationship> packageRelationships(const QString &relativeType) const;
QList<XlsxRelationship> msPackageRelationships(const QString &relativeType) const;
QList<XlsxRelationship> worksheetRelationships(const QString &relativeType) const;
void addDocumentRelationship(const QString &relativeType, const QString &target);
void addPackageRelationship(const QString &relativeType, const QString &target);
void addMsPackageRelationship(const QString &relativeType, const QString &target);
void addWorksheetRelationship(const QString &relativeType, const QString &target, const QString &targetMode=QString());
void saveToXmlFile(QIODevice *device) const;
QByteArray saveToXmlData() const;
bool loadFromXmlFile(QIODevice *device);
bool loadFromXmlData(const QByteArray &data);
XlsxRelationship getRelationshipById(const QString &id) const;
void clear();
int count() const;
bool isEmpty() const;
private:
QList<XlsxRelationship> relationships(const QString &type) const;
void addRelationship(const QString &type, const QString &target, const QString &targetMode=QString());
QList<XlsxRelationship> m_relationships;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXRELATIONSHIPS_H

89
include/QXlsx/xlsxrichstring.h

@ -0,0 +1,89 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXRICHSTRING_H
#define XLSXRICHSTRING_H
#include "xlsxglobal.h"
#include "xlsxformat.h"
#include <QVariant>
#include <QStringList>
#include <QSharedDataPointer>
QT_BEGIN_NAMESPACE_XLSX
class RichStringPrivate;
class RichString;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
uint qHash(const RichString &rs, uint seed = 0) Q_DECL_NOTHROW;
class QXLSX_EXPORT RichString
{
public:
RichString();
explicit RichString(const QString& text);
RichString(const RichString &other);
~RichString();
bool isRichString() const;
bool isNull() const;
bool isEmtpy() const;
QString toPlainString() const;
QString toHtml() const;
void setHtml(const QString &text);
int fragmentCount() const;
void addFragment(const QString &text, const Format &format);
QString fragmentText(int index) const;
Format fragmentFormat(int index) const;
operator QVariant() const;
RichString &operator=(const RichString &other);
private:
friend uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW;
friend bool operator==(const RichString &rs1, const RichString &rs2);
friend bool operator!=(const RichString &rs1, const RichString &rs2);
friend bool operator<(const RichString &rs1, const RichString &rs2);
friend QDebug operator<<(QDebug dbg, const RichString &rs);
QSharedDataPointer<RichStringPrivate> d;
};
bool operator==(const RichString &rs1, const RichString &rs2);
bool operator!=(const RichString &rs1, const RichString &rs2);
bool operator<(const RichString &rs1, const RichString &rs2);
bool operator==(const RichString &rs1, const QString &rs2);
bool operator==(const QString &rs1, const RichString &rs2);
bool operator!=(const RichString &rs1, const QString &rs2);
bool operator!=(const QString &rs1, const RichString &rs2);
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const RichString &rs);
#endif
QT_END_NAMESPACE_XLSX
Q_DECLARE_METATYPE(QXlsx::RichString)
#endif // XLSXRICHSTRING_H

60
include/QXlsx/xlsxrichstring_p.h

@ -0,0 +1,60 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXRICHSTRING_P_H
#define XLSXRICHSTRING_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "xlsxrichstring.h"
QT_BEGIN_NAMESPACE_XLSX
class RichStringPrivate : public QSharedData
{
public:
RichStringPrivate();
RichStringPrivate(const RichStringPrivate &other);
~RichStringPrivate();
QByteArray idKey() const;
QStringList fragmentTexts;
QList<Format> fragmentFormats;
QByteArray _idKey;
bool _dirty;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXRICHSTRING_P_H

98
include/QXlsx/xlsxsharedstrings_p.h

@ -0,0 +1,98 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXSHAREDSTRINGS_H
#define XLSXSHAREDSTRINGS_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QHash>
#include <QStringList>
#include <QIODevice>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include "xlsxglobal.h"
#include "xlsxrichstring.h"
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class XlsxSharedStringInfo
{
public:
XlsxSharedStringInfo(int index=0, int count = 1) :
index(index), count(count)
{
}
int index;
int count;
};
class SharedStrings : public AbstractOOXmlFile
{
public:
SharedStrings(CreateFlag flag);
int count() const;
bool isEmpty() const;
int addSharedString(const QString &string);
int addSharedString(const RichString &string);
void removeSharedString(const QString &string);
void removeSharedString(const RichString &string);
void incRefByStringIndex(int idx);
int getSharedStringIndex(const QString &string) const;
int getSharedStringIndex(const RichString &string) const;
RichString getSharedString(int index) const;
QList<RichString> getSharedStrings() const;
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
private:
void readString(QXmlStreamReader &reader); // <si>
void readRichStringPart(QXmlStreamReader &reader, RichString &rich); // <r>
void readPlainStringPart(QXmlStreamReader &reader, RichString &rich); // <v>
Format readRichStringPart_rPr(QXmlStreamReader &reader);
void writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const;
QHash<RichString, XlsxSharedStringInfo> m_stringTable; //for fast lookup
QList<RichString> m_stringList;
int m_stringCount;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXSHAREDSTRINGS_H

60
include/QXlsx/xlsxsimpleooxmlfile_p.h

@ -0,0 +1,60 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXSIMPLEOOXMLFILE_H
#define XLSXSIMPLEOOXMLFILE_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "xlsxabstractooxmlfile.h"
#include <QString>
#include <QIODevice>
QT_BEGIN_NAMESPACE_XLSX
class SimpleOOXmlFile : public AbstractOOXmlFile
{
public:
SimpleOOXmlFile(CreateFlag flag);
void saveToXmlFile(QIODevice *device) const override;
QByteArray saveToXmlData() const override;
bool loadFromXmlData(const QByteArray &data) override;
bool loadFromXmlFile(QIODevice *device) override;
QByteArray xmlData;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXSIMPLEOOXMLFILE_H

143
include/QXlsx/xlsxstyles_p.h

@ -0,0 +1,143 @@
/****************************************************************************
** Copyright (c) 2013-2014 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 XLSXSTYLES_H
#define XLSXSTYLES_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt Xlsx API. It exists for the convenience
// of the Qt Xlsx. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QSharedPointer>
#include <QHash>
#include <QList>
#include <QMap>
#include <QStringList>
#include <QVector>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QIODevice>
// class StylesTest;
#include "xlsxglobal.h"
#include "xlsxformat.h"
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class Format;
class XlsxColor;
struct XlsxFormatNumberData
{
XlsxFormatNumberData() : formatIndex(0) {}
int formatIndex;
QString formatString;
};
class Styles : public AbstractOOXmlFile
{
public:
Styles(CreateFlag flag);
~Styles();
void addXfFormat(const Format &format, bool force=false);
Format xfFormat(int idx) const;
void addDxfFormat(const Format &format, bool force=false);
Format dxfFormat(int idx) const;
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
QColor getColorByIndex(int idx);
private:
friend class Format;
// friend class ::StylesTest;
void fixNumFmt(const Format &format);
void writeNumFmts(QXmlStreamWriter &writer) const;
void writeFonts(QXmlStreamWriter &writer) const;
void writeFont(QXmlStreamWriter &writer, const Format &font, bool isDxf = false) const;
void writeFills(QXmlStreamWriter &writer) const;
void writeFill(QXmlStreamWriter &writer, const Format &fill, bool isDxf = false) const;
void writeBorders(QXmlStreamWriter &writer) const;
void writeBorder(QXmlStreamWriter &writer, const Format &border, bool isDxf = false) const;
void writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const;
void writeCellXfs(QXmlStreamWriter &writer) const;
void writeDxfs(QXmlStreamWriter &writer) const;
void writeDxf(QXmlStreamWriter &writer, const Format &format) const;
void writeColors(QXmlStreamWriter &writer) const;
bool readNumFmts(QXmlStreamReader &reader);
bool readFonts(QXmlStreamReader &reader);
bool readFont(QXmlStreamReader &reader, Format &format);
bool readFills(QXmlStreamReader &reader);
bool readFill(QXmlStreamReader &reader, Format &format);
bool readBorders(QXmlStreamReader &reader);
bool readBorder(QXmlStreamReader &reader, Format &format);
bool readSubBorder(QXmlStreamReader &reader, const QString &name, Format::BorderStyle &style, XlsxColor &color);
bool readCellXfs(QXmlStreamReader &reader);
bool readDxfs(QXmlStreamReader &reader);
bool readDxf(QXmlStreamReader &reader);
bool readColors(QXmlStreamReader &reader);
bool readIndexedColors(QXmlStreamReader &reader);
bool readCellStyleXfs(QXmlStreamReader &reader);
QHash<QString, int> m_builtinNumFmtsHash;
QMap<int, QSharedPointer<XlsxFormatNumberData> > m_customNumFmtIdMap;
QHash<QString, QSharedPointer<XlsxFormatNumberData> > m_customNumFmtsHash;
int m_nextCustomNumFmtId;
QList<Format> m_fontsList;
QList<Format> m_fillsList;
QList<Format> m_bordersList;
QHash<QByteArray, Format> m_fontsHash;
QHash<QByteArray, Format> m_fillsHash;
QHash<QByteArray, Format> m_bordersHash;
QVector<QColor> m_indexedColors;
bool m_isIndexedColorsDefault;
QList<Format> m_xf_formatsList;
QHash<QByteArray, Format> m_xf_formatsHash;
QList<Format> m_dxf_formatsList;
QHash<QByteArray, Format> m_dxf_formatsHash;
bool m_emptyFormatAdded;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXSTYLES_H

29
include/QXlsx/xlsxtheme_p.h

@ -0,0 +1,29 @@
// xlsxtheme_p.h
#ifndef XLSXTHEME_H
#define XLSXTHEME_H
#include <QtGlobal>
#include <QString>
#include <QIODevice>
#include "xlsxabstractooxmlfile.h"
QT_BEGIN_NAMESPACE_XLSX
class Theme : public AbstractOOXmlFile
{
public:
Theme(CreateFlag flag);
void saveToXmlFile(QIODevice *device) const override;
QByteArray saveToXmlData() const override;
bool loadFromXmlData(const QByteArray &data) override;
bool loadFromXmlFile(QIODevice *device) override;
QByteArray xmlData;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXTHEME_H

42
include/QXlsx/xlsxutility_p.h

@ -0,0 +1,42 @@
// xlsxutility_p.h
#ifndef XLSXUTILITY_H
#define XLSXUTILITY_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QPoint>
#include <QString>
#include <QStringList>
#include <QColor>
#include <QDateTime>
#include <QDate>
#include <QTime>
#include <QVariant>
#include "xlsxglobal.h"
QT_BEGIN_NAMESPACE_XLSX
class CellReference;
bool parseXsdBoolean(const QString &value, bool defaultValue=false);
QStringList splitPath(const QString &path);
QString getRelFilePath(const QString &filePath);
double datetimeToNumber(const QDateTime &dt, bool is1904=false);
QVariant datetimeFromNumber(double num, bool is1904=false);
double timeToNumber(const QTime &t);
QString createSafeSheetName(const QString &nameProposal);
QString escapeSheetName(const QString &sheetName);
QString unescapeSheetName(const QString &sheetName);
bool isSpaceReserveNeeded(const QString &string);
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell);
QT_END_NAMESPACE_XLSX
#endif // XLSXUTILITY_H

95
include/QXlsx/xlsxworkbook.h

@ -0,0 +1,95 @@
// xlsxworkbook.h
#ifndef XLSXWORKBOOK_H
#define XLSXWORKBOOK_H
#include <QtGlobal>
#include <QList>
#include <QImage>
#include <QSharedPointer>
#include <QIODevice>
#include <memory>
#include "xlsxglobal.h"
#include "xlsxabstractooxmlfile.h"
#include "xlsxabstractsheet.h"
QT_BEGIN_NAMESPACE_XLSX
class SharedStrings;
class Styles;
class Drawing;
class Document;
class Theme;
class Relationships;
class DocumentPrivate;
class MediaFile;
class Chart;
class Chartsheet;
class Worksheet;
class WorkbookPrivate;
class QXLSX_EXPORT Workbook : public AbstractOOXmlFile
{
Q_DECLARE_PRIVATE(Workbook)
public:
~Workbook();
int sheetCount() const;
AbstractSheet *sheet(int index) const;
AbstractSheet *addSheet(const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
AbstractSheet *insertSheet(int index, const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
bool renameSheet(int index, const QString &name);
bool deleteSheet(int index);
bool copySheet(int index, const QString &newName=QString());
bool moveSheet(int srcIndex, int distIndex);
AbstractSheet *activeSheet() const;
bool setActiveSheet(int index);
// void addChart();
bool defineName(const QString &name, const QString &formula, const QString &comment=QString(), const QString &scope=QString());
bool isDate1904() const;
void setDate1904(bool date1904);
bool isStringsToNumbersEnabled() const;
void setStringsToNumbersEnabled(bool enable=true);
bool isStringsToHyperlinksEnabled() const;
void setStringsToHyperlinksEnabled(bool enable=true);
bool isHtmlToRichStringEnabled() const;
void setHtmlToRichStringEnabled(bool enable=true);
QString defaultDateFormat() const;
void setDefaultDateFormat(const QString &format);
//internal used member
void addMediaFile(std::shared_ptr<MediaFile> media, bool force=false);
QList<std::shared_ptr<MediaFile> > mediaFiles() const;
void addChartFile(QSharedPointer<Chart> chartFile);
QList<QSharedPointer<Chart> > chartFiles() const;
private:
friend class Worksheet;
friend class Chartsheet;
friend class WorksheetPrivate;
friend class Document;
friend class DocumentPrivate;
Workbook(Workbook::CreateFlag flag);
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
SharedStrings *sharedStrings() const;
Styles *styles();
Theme *theme();
QList<QImage> images();
QList<Drawing *> drawings();
QList<QSharedPointer<AbstractSheet> > getSheetsByTypes(AbstractSheet::SheetType type) const;
QStringList worksheetNames() const;
AbstractSheet *addSheet(const QString &name, int sheetId, AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
};
QT_END_NAMESPACE_XLSX
#endif // XLSXWORKBOOK_H

74
include/QXlsx/xlsxworkbook_p.h

@ -0,0 +1,74 @@
// xlsxworkbook_p.h
#ifndef XLSXWORKBOOK_P_H
#define XLSXWORKBOOK_P_H
#include <QtGlobal>
#include <QSharedPointer>
#include <QStringList>
#include "xlsxworkbook.h"
#include "xlsxabstractooxmlfile_p.h"
#include "xlsxtheme_p.h"
#include "xlsxsimpleooxmlfile_p.h"
#include "xlsxrelationships_p.h"
QT_BEGIN_NAMESPACE_XLSX
struct XlsxDefineNameData
{
XlsxDefineNameData()
:sheetId(-1)
{}
XlsxDefineNameData(const QString &name, const QString &formula, const QString &comment, int sheetId=-1)
:name(name), formula(formula), comment(comment), sheetId(sheetId)
{
}
QString name;
QString formula;
QString comment;
//using internal sheetId, instead of the localSheetId(order in the workbook)
int sheetId;
};
class WorkbookPrivate : public AbstractOOXmlFilePrivate
{
Q_DECLARE_PUBLIC(Workbook)
public:
WorkbookPrivate(Workbook *q, Workbook::CreateFlag flag);
QSharedPointer<SharedStrings> sharedStrings;
QList<QSharedPointer<AbstractSheet> > sheets;
QList<QSharedPointer<SimpleOOXmlFile> > externalLinks;
QStringList sheetNames;
QSharedPointer<Styles> styles;
QSharedPointer<Theme> theme;
QList<std::shared_ptr<MediaFile> > mediaFiles;
QList<QSharedPointer<Chart> > chartFiles;
QList<XlsxDefineNameData> definedNamesList;
bool strings_to_numbers_enabled;
bool strings_to_hyperlinks_enabled;
bool html_to_richstring_enabled;
bool date1904;
QString defaultDateFormat;
int x_window;
int y_window;
int window_width;
int window_height;
int activesheetIndex;
int firstsheet;
int table_count;
//Used to generate new sheet name and id
int last_worksheet_index;
int last_chartsheet_index;
int last_sheet_id;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXWORKBOOK_P_H

164
include/QXlsx/xlsxworksheet.h

@ -0,0 +1,164 @@
// xlsxworksheet.h
#ifndef XLSXWORKSHEET_H
#define XLSXWORKSHEET_H
#include <QtGlobal>
#include <QObject>
#include <QStringList>
#include <QMap>
#include <QVariant>
#include <QPointF>
#include <QIODevice>
#include <QDateTime>
#include <QUrl>
#include <QImage>
#include "xlsxabstractsheet.h"
#include "xlsxcell.h"
#include "xlsxcellrange.h"
#include "xlsxcellreference.h"
#include "xlsxcelllocation.h"
class WorksheetTest;
QT_BEGIN_NAMESPACE_XLSX
class DocumentPrivate;
class Workbook;
class Format;
class Drawing;
class DataValidation;
class ConditionalFormatting;
class CellRange;
class RichString;
class Relationships;
class Chart;
class WorksheetPrivate;
class QXLSX_EXPORT Worksheet : public AbstractSheet
{
Q_DECLARE_PRIVATE(Worksheet)
private:
friend class DocumentPrivate;
friend class Workbook;
friend class ::WorksheetTest;
Worksheet(const QString &sheetName, int sheetId, Workbook *book, CreateFlag flag);
Worksheet *copy(const QString &distName, int distId) const override;
public:
~Worksheet();
public:
bool write(const CellReference &row_column, const QVariant &value, const Format &format=Format());
bool write(int row, int column, const QVariant &value, const Format &format=Format());
QVariant read(const CellReference &row_column) const;
QVariant read(int row, int column) const;
bool writeString(const CellReference &row_column, const QString &value, const Format &format=Format());
bool writeString(int row, int column, const QString &value, const Format &format=Format());
bool writeString(const CellReference &row_column, const RichString &value, const Format &format=Format());
bool writeString(int row, int column, const RichString &value, const Format &format=Format());
bool writeInlineString(const CellReference &row_column, const QString &value, const Format &format=Format());
bool writeInlineString(int row, int column, const QString &value, const Format &format=Format());
bool writeNumeric(const CellReference &row_column, double value, const Format &format=Format());
bool writeNumeric(int row, int column, double value, const Format &format=Format());
bool writeFormula(const CellReference &row_column, const CellFormula &formula, const Format &format=Format(), double result=0);
bool writeFormula(int row, int column, const CellFormula &formula, const Format &format=Format(), double result=0);
bool writeBlank(const CellReference &row_column, const Format &format=Format());
bool writeBlank(int row, int column, const Format &format=Format());
bool writeBool(const CellReference &row_column, bool value, const Format &format=Format());
bool writeBool(int row, int column, bool value, const Format &format=Format());
bool writeDateTime(const CellReference &row_column, const QDateTime& dt, const Format &format=Format());
bool writeDateTime(int row, int column, const QDateTime& dt, const Format &format=Format());
// dev67
bool writeDate(const CellReference &row_column, const QDate& dt, const Format &format=Format());
bool writeDate(int row, int column, const QDate& dt, const Format &format=Format());
bool writeTime(const CellReference &row_column, const QTime& t, const Format &format=Format());
bool writeTime(int row, int column, const QTime& t, const Format &format=Format());
bool writeHyperlink(const CellReference &row_column, const QUrl &url, const Format &format=Format(), const QString &display=QString(), const QString &tip=QString());
bool writeHyperlink(int row, int column, const QUrl &url, const Format &format=Format(), const QString &display=QString(), const QString &tip=QString());
bool addDataValidation(const DataValidation &validation);
bool addConditionalFormatting(const ConditionalFormatting &cf);
Cell *cellAt(const CellReference &row_column) const;
Cell *cellAt(int row, int column) const;
int insertImage(int row, int column, const QImage &image);
bool getImage(int imageIndex, QImage& img);
bool getImage(int row, int column, QImage& img);
uint getImageCount();
Chart *insertChart(int row, int column, const QSize &size);
bool mergeCells(const CellRange &range, const Format &format=Format());
bool unmergeCells(const CellRange &range);
QList<CellRange> mergedCells() const;
bool setColumnWidth(const CellRange& range, double width);
bool setColumnFormat(const CellRange& range, const Format &format);
bool setColumnHidden(const CellRange& range, bool hidden);
bool setColumnWidth(int colFirst, int colLast, double width);
bool setColumnFormat(int colFirst, int colLast, const Format &format);
bool setColumnHidden(int colFirst, int colLast, bool hidden);
double columnWidth(int column);
Format columnFormat(int column);
bool isColumnHidden(int column);
bool setRowHeight(int rowFirst,int rowLast, double height);
bool setRowFormat(int rowFirst,int rowLast, const Format &format);
bool setRowHidden(int rowFirst,int rowLast, bool hidden);
double rowHeight(int row);
Format rowFormat(int row);
bool isRowHidden(int row);
bool groupRows(int rowFirst, int rowLast, bool collapsed = true);
bool groupColumns(int colFirst, int colLast, bool collapsed = true);
bool groupColumns(const CellRange &range, bool collapsed = true);
CellRange dimension() const;
bool isWindowProtected() const;
void setWindowProtected(bool protect);
bool isFormulasVisible() const;
void setFormulasVisible(bool visible);
bool isGridLinesVisible() const;
void setGridLinesVisible(bool visible);
bool isRowColumnHeadersVisible() const;
void setRowColumnHeadersVisible(bool visible);
bool isZerosVisible() const;
void setZerosVisible(bool visible);
bool isRightToLeft() const;
void setRightToLeft(bool enable);
bool isSelected() const;
void setSelected(bool select);
bool isRulerVisible() const;
void setRulerVisible(bool visible);
bool isOutlineSymbolsVisible() const;
void setOutlineSymbolsVisible(bool visible);
bool isWhiteSpaceVisible() const;
void setWhiteSpaceVisible(bool visible);
bool setStartPage(int spagen); //add by liufeijin20181028
QVector<CellLocation> getFullCells(int* maxRow, int* maxCol);
private:
void saveToXmlFile(QIODevice *device) const override;
bool loadFromXmlFile(QIODevice *device) override;
};
QT_END_NAMESPACE_XLSX
#endif // XLSXWORKSHEET_H

252
include/QXlsx/xlsxworksheet_p.h

@ -0,0 +1,252 @@
// xlsxworksheet_p.h
#ifndef XLSXWORKSHEET_P_H
#define XLSXWORKSHEET_P_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QVector>
#include <QImage>
#include <QSharedPointer>
#include <QRegularExpression>
#include "xlsxworksheet.h"
#include "xlsxabstractsheet_p.h"
#include "xlsxcell.h"
#include "xlsxdatavalidation.h"
#include "xlsxconditionalformatting.h"
#include "xlsxcellformula.h"
class QXmlStreamWriter;
class QXmlStreamReader;
QT_BEGIN_NAMESPACE_XLSX
const int XLSX_ROW_MAX = 1048576;
const int XLSX_COLUMN_MAX = 16384;
const int XLSX_STRING_MAX = 32767;
class SharedStrings;
struct XlsxHyperlinkData
{
enum LinkType
{
External,
Internal
};
XlsxHyperlinkData(LinkType linkType=External, const QString &target=QString(), const QString &location=QString()
, const QString &display=QString(), const QString &tip=QString())
:linkType(linkType), target(target), location(location), display(display), tooltip(tip)
{
}
LinkType linkType;
QString target; //For External link
QString location;
QString display;
QString tooltip;
};
// ECMA-376 Part1 18.3.1.81
struct XlsxSheetFormatProps
{
XlsxSheetFormatProps(int baseColWidth = 8,
bool customHeight = false,
double defaultColWidth = 8.430f, // https://learn.microsoft.com/en-us/office/troubleshoot/excel/determine-column-widths
double defaultRowHeight = 15,
quint8 outlineLevelCol = 0,
quint8 outlineLevelRow = 0,
bool thickBottom = false,
bool thickTop = false,
bool zeroHeight = false) :
baseColWidth(baseColWidth),
customHeight(customHeight),
defaultColWidth(defaultColWidth),
defaultRowHeight(defaultRowHeight),
outlineLevelCol(outlineLevelCol),
outlineLevelRow(outlineLevelRow),
thickBottom(thickBottom),
thickTop(thickTop),
zeroHeight(zeroHeight) {
}
int baseColWidth;
bool customHeight;
double defaultColWidth;
double defaultRowHeight;
quint8 outlineLevelCol;
quint8 outlineLevelRow;
bool thickBottom;
bool thickTop;
bool zeroHeight;
};
struct XlsxRowInfo
{
XlsxRowInfo(double height=0, const Format &format=Format(), bool hidden=false) :
customHeight(false), height(height), format(format), hidden(hidden), outlineLevel(0)
, collapsed(false)
{
}
bool customHeight;
double height;
Format format;
bool hidden;
int outlineLevel;
bool collapsed;
};
struct XlsxColumnInfo
{
XlsxColumnInfo( int firstColumn, // = 0,
int lastColumn, // = 1,
bool isSetWidth,
double width = 0,
const Format &format = Format(),
bool hidden = false)
: width(width),
format(format),
firstColumn(firstColumn),
lastColumn(lastColumn),
outlineLevel(0),
isSetWidth(isSetWidth),
customWidth(false),
hidden(hidden),
collapsed(false)
{
}
double width;
Format format;
int firstColumn;
int lastColumn;
int outlineLevel;
bool isSetWidth;
bool customWidth;
bool hidden;
bool collapsed;
};
class WorksheetPrivate : public AbstractSheetPrivate
{
Q_DECLARE_PUBLIC(Worksheet)
public:
WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag);
~WorksheetPrivate();
public:
int checkDimensions(int row, int col, bool ignore_row=false, bool ignore_col=false);
Format cellFormat(int row, int col) const;
QString generateDimensionString() const;
void calculateSpans() const;
void splitColsInfo(int colFirst, int colLast);
void validateDimension();
void saveXmlSheetData(QXmlStreamWriter &writer) const;
void saveXmlCellData(QXmlStreamWriter &writer, int row, int col, std::shared_ptr<Cell> cell) const;
void saveXmlMergeCells(QXmlStreamWriter &writer) const;
void saveXmlHyperlinks(QXmlStreamWriter &writer) const;
void saveXmlDrawings(QXmlStreamWriter &writer) const;
void saveXmlDataValidations(QXmlStreamWriter &writer) const;
int rowPixelsSize(int row) const;
int colPixelsSize(int col) const;
void loadXmlSheetData(QXmlStreamReader &reader);
void loadXmlColumnsInfo(QXmlStreamReader &reader);
void loadXmlMergeCells(QXmlStreamReader &reader);
void loadXmlDataValidations(QXmlStreamReader &reader);
void loadXmlSheetFormatProps(QXmlStreamReader &reader);
void loadXmlSheetViews(QXmlStreamReader &reader);
void loadXmlHyperlinks(QXmlStreamReader &reader);
QList<QSharedPointer<XlsxRowInfo> > getRowInfoList(int rowFirst, int rowLast);
QList<QSharedPointer<XlsxColumnInfo> > getColumnInfoList(int colFirst, int colLast);
QList<int> getColumnIndexes(int colFirst, int colLast);
bool isColumnRangeValid(int colFirst, int colLast);
SharedStrings *sharedStrings() const;
public:
QMap<int, QMap<int, std::shared_ptr<Cell> > > cellTable;
QMap<int, QMap<int, QString> > comments;
QMap<int, QMap<int, QSharedPointer<XlsxHyperlinkData> > > urlTable;
QList<CellRange> merges;
QMap<int, QSharedPointer<XlsxRowInfo> > rowsInfo;
QMap<int, QSharedPointer<XlsxColumnInfo> > colsInfo;
QMap<int, QSharedPointer<XlsxColumnInfo> > colsInfoHelper;
QList<DataValidation> dataValidationsList;
QList<ConditionalFormatting> conditionalFormattingList;
QMap<int, CellFormula> sharedFormulaMap; // shared formula map
CellRange dimension;
int previous_row;
mutable QMap<int, QString> row_spans;
QMap<int, double> row_sizes;
QMap<int, double> col_sizes;
int outline_row_level;
int outline_col_level;
int default_row_height;
bool default_row_zeroed;
// pagesetup and print settings add by liufeijin 20181028, liufeijin
QString PpaperSize;
QString Pscale;
QString PfirstPageNumber;
QString Porientation;
QString PuseFirstPageNumber;
QString PhorizontalDpi;
QString PverticalDpi;
QString Prid;
QString Pcopies;
// pageMargins, liufeijin
QString PMheader;
QString PMfooter;
QString PMtop;
QString PMbotton;
QString PMleft;
QString PMright;
// header footer, liufeijin
QString MoodFooter;
QString ModdHeader;
QString MoodalignWithMargins; // add align 20190619
XlsxSheetFormatProps sheetFormatProps;
bool windowProtection;
bool showFormulas;
bool showGridLines;
bool showRowColHeaders;
bool showZeros;
bool rightToLeft;
bool tabSelected;
bool showRuler;
bool showOutlineSymbols;
bool showWhiteSpace;
QRegularExpression urlPattern;
private:
static double calculateColWidth(int characters);
};
QT_END_NAMESPACE_XLSX
#endif // XLSXWORKSHEET_P_H

37
include/QXlsx/xlsxzipreader_p.h

@ -0,0 +1,37 @@
// xlsxzipreader_p.h
#ifndef QXLSX_XLSXZIPREADER_P_H
#define QXLSX_XLSXZIPREADER_P_H
#include <QScopedPointer>
#include <QStringList>
#include <QIODevice>
#include "xlsxglobal.h"
#include <QVector>
class QZipReader;
QT_BEGIN_NAMESPACE_XLSX
class ZipReader
{
public:
explicit ZipReader(const QString &fileName);
explicit ZipReader(QIODevice *device);
~ZipReader();
bool exists() const;
QStringList filePaths() const;
QByteArray fileData(const QString &fileName) const;
private:
Q_DISABLE_COPY(ZipReader)
void init();
QScopedPointer<QZipReader> m_reader;
QStringList m_filePaths;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_XLSXZIPREADER_P_H

34
include/QXlsx/xlsxzipwriter_p.h

@ -0,0 +1,34 @@
// xlsxzipwriter_p.h
#ifndef QXLSX_ZIPWRITER_H
#define QXLSX_ZIPWRITER_H
#include <QtGlobal>
#include <QString>
#include <QIODevice>
#include "xlsxglobal.h"
class QZipWriter;
QT_BEGIN_NAMESPACE_XLSX
class ZipWriter
{
public:
explicit ZipWriter(const QString &filePath);
explicit ZipWriter(QIODevice *device);
~ZipWriter();
void addFile(const QString &filePath, QIODevice *device);
void addFile(const QString &filePath, const QByteArray &data);
bool error() const;
void close();
private:
QZipWriter *m_writer;
};
QT_END_NAMESPACE_XLSX
#endif // QXLSX_ZIPWRITER_H

12
include/XlsxReader.h

@ -0,0 +1,12 @@
#ifndef XLSXREADER_H
#define XLSXREADER_H
#include <QList>
class XlsxReader
{
public:
XlsxReader();
QList<QStringList> ReadeXlsx(QString pathOfXlsx);
};
#endif //XLSXREADER_H

23
include/XlsxXmlConverter.h

@ -0,0 +1,23 @@
#ifndef XLSXXMLCONVERTER_H
#define XLSXXMLCONVERTER_H
#include <QString>
#include <QList>
class XlsxXmlConverter
{
private:
QString xlsxFilePath;
QString xmlPatternFilePath;
QString xmlOutPutFilePath;
QList<QStringList> xlsxData;
QList<QString> patternList;
public:
XlsxXmlConverter();
void initPath(QString xlsxPath, QString patternFilePath, QString outputFilePath);
void readXlsx();
void readPattern();
void wrtiteXMl();
};
#endif //XLSXXMLCONVERTER_H

15
include/XmlGenerator.h

@ -0,0 +1,15 @@
#ifndef XMLGENERATOR_H
#define XMLGENERATOR_H
#include <QList>
class XmlGenerator
{
public:
XmlGenerator();
void generateXML(QList<QStringList> inputList,
qint16 sheetCounter,
QList<QString> patternList,
QString outputPath);
};
#endif //XMLGENERATOR_H

12
include/XmlTemplateReader.h

@ -0,0 +1,12 @@
#ifndef XMLTEMPLATEREADER_H
#define XMLTEMPLATEREADER_H
#include <QList>
class XmlTemplateReader
{
public:
XmlTemplateReader();
QList<QString> readxmlPattern(QString pathOfPattern);
};
#endif //XMLTEMPLATEREADER_H

15
main.cpp

@ -0,0 +1,15 @@
#include <QCoreApplication>
#include "include/XlsxXmlConverter.h"
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
XlsxXmlConverter convert;
convert.initPath("BPresetValue.xlsx", "Pattern.xml", "");
convert.readXlsx();
convert.readPattern();
convert.wrtiteXMl();
return a.exec();
}

97
src/QXlsx/xlsxabstractooxmlfile.cpp

@ -0,0 +1,97 @@
//xlsxabstractooxmlfile.cpp
#include <QtGlobal>
#include <QBuffer>
#include <QByteArray>
#include "include/QXlsx/xlsxabstractooxmlfile.h"
#include "xlsxabstractooxmlfile_p.h"
QT_BEGIN_NAMESPACE_XLSX
AbstractOOXmlFilePrivate::AbstractOOXmlFilePrivate(AbstractOOXmlFile* q,
AbstractOOXmlFile::CreateFlag flag = AbstractOOXmlFile::F_NewFromScratch)
: relationships(new Relationships), flag(flag), q_ptr(q)
{
}
AbstractOOXmlFilePrivate::~AbstractOOXmlFilePrivate()
{
if(relationships)
{
delete relationships;
}
}
/*!
* \internal
*
* \class AbstractOOXmlFile
*
* Base class of all the ooxml part file.
*/
AbstractOOXmlFile::AbstractOOXmlFile(CreateFlag flag)
: d_ptr(new AbstractOOXmlFilePrivate(this, flag))
{
}
AbstractOOXmlFile::AbstractOOXmlFile(AbstractOOXmlFilePrivate* d)
: d_ptr(d)
{
}
AbstractOOXmlFile::~AbstractOOXmlFile()
{
delete d_ptr;
}
QByteArray AbstractOOXmlFile::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool AbstractOOXmlFile::loadFromXmlData(const QByteArray& data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
/*!
* \internal
*/
void AbstractOOXmlFile::setFilePath(const QString path)
{
Q_D(AbstractOOXmlFile);
d->filePathInPackage = path;
}
/*!
* \internal
*/
QString AbstractOOXmlFile::filePath() const
{
Q_D(const AbstractOOXmlFile);
return d->filePathInPackage;
}
/*!
* \internal
*/
Relationships* AbstractOOXmlFile::relationships() const
{
Q_D(const AbstractOOXmlFile);
return d->relationships;
}
QT_END_NAMESPACE_XLSX

186
src/QXlsx/xlsxabstractsheet.cpp

@ -0,0 +1,186 @@
// xlsxabstractsheet.cpp
#include <QtGlobal>
#include "xlsxabstractsheet.h"
#include "xlsxabstractsheet_p.h"
#include "xlsxworkbook.h"
QT_BEGIN_NAMESPACE_XLSX
AbstractSheetPrivate::AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag)
: AbstractOOXmlFilePrivate(p, flag)
{
type = AbstractSheet::ST_WorkSheet;
sheetState = AbstractSheet::SS_Visible;
}
AbstractSheetPrivate::~AbstractSheetPrivate()
{
}
/*!
\class AbstractSheet
\inmodule QtXlsx
\brief Base class for worksheet, chartsheet, etc.
*/
/*!
\enum AbstractSheet::SheetType
\value ST_WorkSheet
\value ST_ChartSheet
\omitvalue ST_DialogSheet
\omitvalue ST_MacroSheet
*/
/*!
\enum AbstractSheet::SheetState
\value SS_Visible
\value SS_Hidden
\value SS_VeryHidden User cann't make a veryHidden sheet visible in normal way.
*/
/*!
\fn AbstractSheet::copy(const QString &distName, int distId) const
Copies the current sheet to a sheet called \a distName with \a distId.
Returns the new sheet.
*/
/*!
* \internal
*/
AbstractSheet::AbstractSheet(const QString &name, int id, Workbook *workbook, AbstractSheetPrivate *d) :
AbstractOOXmlFile(d)
{
d_func()->name = name;
d_func()->id = id;
d_func()->workbook = workbook;
}
/*!
* Returns the name of the sheet.
*/
QString AbstractSheet::sheetName() const
{
Q_D(const AbstractSheet);
return d->name;
}
/*!
* \internal
*/
void AbstractSheet::setSheetName(const QString &sheetName)
{
Q_D(AbstractSheet);
d->name = sheetName;
}
/*!
* Returns the type of the sheet.
*/
AbstractSheet::SheetType AbstractSheet::sheetType() const
{
Q_D(const AbstractSheet);
return d->type;
}
/*!
* \internal
*/
void AbstractSheet::setSheetType(SheetType type)
{
Q_D(AbstractSheet);
d->type = type;
}
/*!
* Returns the state of the sheet.
*
* \sa isHidden(), isVisible(), setSheetState()
*/
AbstractSheet::SheetState AbstractSheet::sheetState() const
{
Q_D(const AbstractSheet);
return d->sheetState;
}
/*!
* Set the state of the sheet to \a state.
*/
void AbstractSheet::setSheetState(SheetState state)
{
Q_D(AbstractSheet);
d->sheetState = state;
}
/*!
* Returns true if the sheet is not visible, otherwise false will be returned.
*
* \sa sheetState(), setHidden()
*/
bool AbstractSheet::isHidden() const
{
Q_D(const AbstractSheet);
return d->sheetState != SS_Visible;
}
/*!
* Returns true if the sheet is visible.
*/
bool AbstractSheet::isVisible() const
{
return !isHidden();
}
/*!
* Make the sheet hiden or visible based on \a hidden.
*/
void AbstractSheet::setHidden(bool hidden)
{
Q_D(AbstractSheet);
if (hidden == isHidden())
return;
d->sheetState = hidden ? SS_Hidden : SS_Visible;
}
/*!
* Convenience function, equivalent to setHidden(! \a visible).
*/
void AbstractSheet::setVisible(bool visible)
{
setHidden(!visible);
}
/*!
* \internal
*/
int AbstractSheet::sheetId() const
{
Q_D(const AbstractSheet);
return d->id;
}
/*!
* \internal
*/
Drawing *AbstractSheet::drawing() const
{
Q_D(const AbstractSheet);
return d->drawing.get();
}
/*!
* Return the workbook
*/
Workbook *AbstractSheet::workbook() const
{
Q_D(const AbstractSheet);
return d->workbook;
}
QT_END_NAMESPACE_XLSX

364
src/QXlsx/xlsxcell.cpp

@ -0,0 +1,364 @@
// xlsxcell.cpp
#include <cmath>
#include <QtGlobal>
#include <QDebug>
#include <QDateTime>
#include <QDate>
#include <QTime>
#include "xlsxcell.h"
#include "xlsxcell_p.h"
#include "xlsxformat.h"
#include "xlsxformat_p.h"
#include "xlsxutility_p.h"
#include "xlsxworksheet.h"
#include "xlsxworkbook.h"
QT_BEGIN_NAMESPACE_XLSX
CellPrivate::CellPrivate(Cell *p) :
q_ptr(p)
{
}
CellPrivate::CellPrivate(const CellPrivate * const cp)
: parent(cp->parent)
, cellType(cp->cellType)
, value(cp->value)
, formula(cp->formula)
, format(cp->format)
, richString(cp->richString)
, styleNumber(cp->styleNumber)
{
}
/*!
\class Cell
\inmodule QtXlsx
\brief The Cell class provides a API that is used to handle the worksheet cell.
*/
/*!
\enum Cell::CellType
\value BooleanType Boolean type
\value NumberType Number type, can be blank or used with forumula
\value ErrorType Error type
\value SharedStringType Shared string type
\value StringType String type, can be used with forumula
\value InlineStringType Inline string type
*/
/*!
* \internal
* Created by Worksheet only.
*/
// qint32 styleIndex = (-1)
Cell::Cell(const QVariant &data,
CellType type,
const Format &format,
Worksheet *parent,
qint32 styleIndex ) :
d_ptr(new CellPrivate(this))
{
d_ptr->value = data;
d_ptr->cellType = type;
d_ptr->format = format;
d_ptr->parent = parent;
d_ptr->styleNumber = styleIndex;
}
/*!
* \internal
*/
Cell::Cell(const Cell * const cell):
d_ptr(new CellPrivate(cell->d_ptr))
{
d_ptr->q_ptr = this;
}
/*!
* Destroys the Cell and cleans up.
*/
Cell::~Cell()
{
if ( NULL != d_ptr )
delete d_ptr;
}
/*!
* Return the dataType of this Cell
*/
Cell::CellType Cell::cellType() const
{
Q_D(const Cell);
return d->cellType;
}
/*!
* Return the data content of this Cell
*/
QVariant Cell::value() const
{
Q_D(const Cell);
return d->value;
}
/*!
* Return the data content of this Cell for reading
*/
QVariant Cell::readValue() const
{
Q_D(const Cell);
QVariant ret; // return value
ret = d->value;
Format fmt = this->format();
if (isDateTime())
{
QVariant vDT = dateTime();
if ( vDT.isNull() )
{
return QVariant();
}
// https://github.com/QtExcel/QXlsx/issues/171
// https://www.qt.io/blog/whats-new-in-qmetatype-qvariant
#if QT_VERSION >= 0x060000 // Qt 6.0 or over
if ( vDT.metaType().id() == QMetaType::QDateTime )
{
ret = vDT;
}
else if ( vDT.metaType().id() == QMetaType::QDate )
{
ret = vDT;
}
else if ( vDT.metaType().id() == QMetaType::QTime )
{
ret = vDT;
}
else
{
return QVariant();
}
#else
if ( vDT.type() == QVariant::DateTime )
{
ret = vDT;
}
else if ( vDT.type() == QVariant::Date )
{
ret = vDT;
}
else if ( vDT.type() == QVariant::Time )
{
ret = vDT;
}
else
{
return QVariant();
}
#endif
// QDateTime dt = dateTime();
// ret = dt;
// QString strFormat = fmt.numberFormat();
// if (!strFormat.isEmpty())
// {
// // TODO: use number format
// }
// qint32 styleNo = d->styleNumber;
// if (styleNo == 10)
// {
// }
// if (styleNo == 11)
// {
// QTime timeValue = dt.time(); // only time. (HH:mm:ss)
// ret = timeValue;
// return ret;
// }
// if (styleNo == 12)
// {
// }
// if (styleNo == 13) // (HH:mm:ss)
// {
// double dValue = d->value.toDouble();
// int day = int(dValue); // unit is day.
// double deciamlPointValue1 = dValue - double(day);
// double dHour = deciamlPointValue1 * (double(1.0) / double(24.0));
// int hour = int(dHour);
// double deciamlPointValue2 = deciamlPointValue1 - (double(hour) * (double(1.0) / double(24.0)));
// double dMin = deciamlPointValue2 * (double(1.0) / double(60.0));
// int min = int(dMin);
// double deciamlPointValue3 = deciamlPointValue2 - (double(min) * (double(1.0) / double(60.0)));
// double dSec = deciamlPointValue3 * (double(1.0) / double(60.0));
// int sec = int(dSec);
// int totalHour = hour + (day * 24);
// QString strTime;
// strTime = QString("%1:%2:%3").arg(totalHour).arg(min).arg(sec);
// ret = strTime;
// return ret;
// }
// return ret;
// */
}
if (hasFormula())
{
QString formulaString = this->formula().formulaText();
ret = formulaString;
return ret; // return formula string
}
return ret;
}
/*!
* Return the style used by this Cell. If no style used, 0 will be returned.
*/
Format Cell::format() const
{
Q_D(const Cell);
return d->format;
}
/*!
* Returns true if the cell has one formula.
*/
bool Cell::hasFormula() const
{
Q_D(const Cell);
return d->formula.isValid();
}
/*!
* Return the formula contents if the dataType is Formula
*/
CellFormula Cell::formula() const
{
Q_D(const Cell);
return d->formula;
}
/*!
* Returns whether the value is probably a dateTime or not
*/
bool Cell::isDateTime() const
{
Q_D(const Cell);
Cell::CellType cellType = d->cellType;
double dValue = d->value.toDouble(); // number
// QString strValue = d->value.toString().toUtf8();
bool isValidFormat = d->format.isValid();
bool isDateTimeFormat = d->format.isDateTimeFormat(); // datetime format
// dev67
if ( cellType == NumberType ||
cellType == DateType ||
cellType == CustomType )
{
if ( dValue >= 0 &&
isValidFormat &&
isDateTimeFormat )
{
return true;
}
}
return false;
}
/*!
* Return the data time value.
*/
/*
QDateTime Cell::dateTime() const
{
Q_D(const Cell);
if (!isDateTime())
return QDateTime();
return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904());
}
*/
QVariant Cell::dateTime() const
{
Q_D(const Cell);
if (!isDateTime())
{
return QVariant();
}
// dev57
QVariant ret;
double dValue = d->value.toDouble();
bool isDate1904 = d->parent->workbook()->isDate1904();
ret = datetimeFromNumber(dValue, isDate1904);
return ret;
}
/*!
* Returns whether the cell is probably a rich string or not
*/
bool Cell::isRichString() const
{
Q_D(const Cell);
if ( d->cellType != SharedStringType &&
d->cellType != InlineStringType &&
d->cellType != StringType )
{
return false;
}
return d->richString.isRichString();
}
qint32 Cell::styleNumber() const
{
Q_D(const Cell);
qint32 ret = d->styleNumber;
return ret;
}
bool Cell::isDateType(CellType cellType, const Format &format)
{
if ( cellType == NumberType ||
cellType == DateType ||
cellType == CustomType )
{
return format.isValid() && format.isDateTimeFormat();
}
return false;
}
QT_END_NAMESPACE_XLSX

453
src/QXlsx/xlsxcellformula.cpp

@ -0,0 +1,453 @@
// xlsxcellformula.cpp
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include "xlsxcellformula.h"
#include "xlsxcellformula_p.h"
#include "xlsxutility_p.h"
QT_BEGIN_NAMESPACE_XLSX
CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_)
:formula(formula_), type(type_), reference(ref_), ca(false), si(0)
{
//Remove the formula '=' sign if exists
if (formula.startsWith(QLatin1String("=")))
formula.remove(0,1);
else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}")))
formula = formula.mid(2, formula.length()-3);
}
CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other)
: QSharedData(other)
, formula(other.formula), type(other.type), reference(other.reference)
, ca(other.ca), si(other.si)
{
}
CellFormulaPrivate::~CellFormulaPrivate()
{
}
/*!
\class CellFormula
\inmodule QtXlsx
\brief The CellFormula class provides a API that is used to handle the cell formula.
*/
/*!
\enum CellFormula::FormulaType
\value NormalType
\value ArrayType
\value DataTableType
\value SharedType
*/
/*!
* Creates a new formula.
*/
CellFormula::CellFormula()
{
//The d pointer is initialized with a null pointer
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const char *formula, FormulaType type)
:d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const QString &formula, FormulaType type)
:d(new CellFormulaPrivate(formula, CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula, \a ref and \a type.
*/
CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type)
:d(new CellFormulaPrivate(formula, ref, type))
{
}
/*!
Creates a new formula with the same attributes as the \a other formula.
*/
CellFormula::CellFormula(const CellFormula &other)
:d(other.d)
{
}
/*!
Assigns the \a other formula to this formula, and returns a
reference to this formula.
*/
CellFormula &CellFormula::operator =(const CellFormula &other)
{
d = other.d;
return *this;
}
/*!
* Destroys this formula.
*/
CellFormula::~CellFormula()
{
}
/*!
* Returns the type of the formula.
*/
CellFormula::FormulaType CellFormula::formulaType() const
{
return d ? d->type : NormalType;
}
/*!
* Returns the contents of the formula.
*/
QString CellFormula::formulaText() const
{
return d ? d->formula : QString();
}
/*!
* Returns the reference cells of the formula. For normal formula,
* this will return an invalid CellRange object.
*/
CellRange CellFormula::reference() const
{
return d ? d->reference : CellRange();
}
/*!
* Returns whether the formula is valid.
*/
bool CellFormula::isValid() const
{
return d;
}
/*!
* Returns the shared index for shared formula.
*/
int CellFormula::sharedIndex() const
{
return d && d->type == SharedType ? d->si : (-1);
}
/* aca (Always Calculate Array) // not-implmented attribute
*
* Only applies to array formulas.
*
* true indicates that the entire array shall be calculated in full.
* If false the individual cells of the array shall be calculated as needed.
*
* The aca value shall be ignored unless the value of the corresponding
* t attribute is array.
*
* [Note: The primary case where an array formula must be calculated in
* part instead of in full is when some cells in the array depend on other
* cells that are semi-calculated, e.g., contains the function =(). end note]
*
* The possible values for this attribute are defined by the W3C XML Schema
* boolean datatype.
*/
/* bx (Assigns Value to Name) // not-implmented attribute
*
* Specifies that this formula assigns a value to a name.
*
* The possible values for this attribute are defined by the W3C XML
* Schema boolean datatype.
*/
/* del1 (Input 1 Deleted) // not-implmented attribute
*
* Whether the first input cell for data table has been deleted.
* Applies to data table formula only. Written on master cell of data table
* formula only.
*
* The possible values for this attribute are defined by the W3C XML Schema
* boolean datatype.
*/
/* del2 (Input 2 Deleted) // not-impplmented attribute
*
* Whether the second input cell for data table has been deleted.
* Applies to data table formula only. Written on master cell of data
* table formula only.
*
* The possible values for this attribute are defined by the W3C XML Schema
* boolean datatype.
*/
/* dt2D (Data Table 2-D) // not-implmented attribute
*
* Data table is two-dimentional. Only applies to the data tables function.
* Written on master cell of data table formula only.
*
* The possible values for this attribute are defined by the W3C XML Schema
* boolean datatype.
*/
/* dtr (Data Table Row) // not-implmented attribute
*
* true if one-dimentional data table is a row, otherwise it's a column.
* Only applies to the data tables function. Written on master cell of data
* table formula only.
*
* The possible values for this attribute are defined by the W3C XML Schema
* boolean datatype.
*/
/* r1 (Data Table Cell 1) // not-implmented attribute
*
* First input cell for data table. Only applies to the data tables array
* function "TABLE()". Written on master cell of data table formula only.
*
* The possible values for this attribute are defined by the ST_CellRef
* simple type (§18.18.7).
*/
/* r2 (Input Cell 2) // not-implmented attribute
*
* Second input cell for data table when dt2D is '1'. Only applies to the
* data tables array function "TABLE()".Written on master cell of data table
* formula only.
*
* The possible values for this attribute are defined by the ST_CellRef
* simple type (§18.18.7).
*/
/*!
* \internal
* \remark pair with loadFromXml()
*/
bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
{
// t (Formula Type)
//
// Type of formula.
// The possible values for this attribute are defined by the
// ST_CellFormulaType simple type (§18.18.6).
//
// 18.18.6 ST_CellFormulaType (Formula Type)
// array (Array Formula)
// dataTable (Table Formula)
// normal (Normal)
// shared (Shared Formula)
QString t;
switch (d->type)
{
case CellFormula::ArrayType:
t = QStringLiteral("array");
break;
case CellFormula::SharedType:
t = QStringLiteral("shared");
break;
case CellFormula::NormalType:
t = QStringLiteral("normal");
break;
case CellFormula::DataTableType:
t = QStringLiteral("dataTable");
break;
default: // undefined type
return false;
break;
}
// f (Formula)
//
// Formula for the cell. The formula expression is contained in the
// character node of this element.
writer.writeStartElement(QStringLiteral("f"));
if (!t.isEmpty())
{
writer.writeAttribute(QStringLiteral("t"), t); // write type(t)
}
// ref (Range of Cells)
//
// Range of cells which the formula applies to.
// Only required for shared formula, array formula or data table.
// Only written on the master formula,
// not subsequent formulas belonging to the same shared group, array,
// or data table.
// The possible values for this attribute are defined by the ST_Ref
// simple type (§18.18.62).
if ( d->type == CellFormula::SharedType ||
d->type == CellFormula::ArrayType ||
d->type == CellFormula::DataTableType )
{
if (d->reference.isValid())
{
writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
}
}
// ca (Calculate Cell)
//
// Indicates that this formula needs to be recalculated the next time
// calculation is performed. [Example: This is always set on volatile
// functions, like =(), and circular references. end example]
// The possible values for this attribute are defined by the W3C XML
// Schema boolean datatype.
//
// 3.2.2 boolean
// 3.2.2.1 Lexical representation
// An instance of a datatype that is defined as ·boolean· can have the
// following legal literals {true, false, 1, 0}.
if (d->ca)
{
writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
}
// si (Shared Group Index)
// Optional attribute to optimize load performance by sharing formulas.
//
// When a formula is a shared formula (t value is shared) then this value
// indicates the group to which this particular cell's formula belongs. The
// first formula in a group of shared formulas is saved in the f element.
// This is considered the 'master' formula cell. Subsequent cells sharing
// this formula need not have the formula written in their f element.
// Instead, the attribute si value for a particular cell is used to figure
// what the formula expression should be based on the cell's relative
// location to the master formula cell.
if (d->type == CellFormula::SharedType)
{
int si = d->si;
writer.writeAttribute(QStringLiteral("si"), QString::number(si));
}
if (!d->formula.isEmpty())
{
QString strFormula = d->formula;
writer.writeCharacters(strFormula); // write formula
}
writer.writeEndElement(); // f
return true;
}
/*!
* \internal
* \remark pair with saveToXml()
*/
bool CellFormula::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("f"));
if (!d)
d = new CellFormulaPrivate(QString(), CellRange(), NormalType);
QXmlStreamAttributes attributes = reader.attributes();
QString typeString = attributes.value(QLatin1String("t")).toString();
// branch: shared-formula
//
if (typeString == QLatin1String("array")) {
d->type = ArrayType;
}
else if (typeString == QLatin1String("shared")) {
d->type = SharedType;
}
else if (typeString == QLatin1String("normal")) {
d->type = NormalType;
}
else if (typeString == QLatin1String("dataTable")) {
d->type = DataTableType;
}
else {
/*
// undefined type
// qDebug() << "Undefined type" << typeString;
return false;
// */
// dev40 {{
// https://github.com/QtExcel/QXlsx/issues/38
d->type = NormalType; // Change: normal Type is not mentioned in the xml file!!!!!
// }}
}
// branch: shared-formula
//
// ref (Range of Cells)
// Range of cells which the formula applies to.
// Only required for shared formula, array formula or data table.
if ( d->type == CellFormula::SharedType ||
d->type == CellFormula::ArrayType ||
d->type == CellFormula::DataTableType )
{
if (attributes.hasAttribute(QLatin1String("ref")))
{
QString refString = attributes.value(QLatin1String("ref")).toString();
d->reference = CellRange(refString);
}
}
// branch: shared-formula
//
// si (Shared Group Index)
// Optional attribute to optimize load performance by sharing formulas.
// When a formula is a shared formula (t value is shared) then this value
// indicates the group to which this particular cell's formula belongs.
if ( d->type == CellFormula::SharedType )
{
QString ca = attributes.value(QLatin1String("si")).toString();
d->ca = parseXsdBoolean(ca, false);
if (attributes.hasAttribute(QLatin1String("si")))
{
d->si = attributes.value(QLatin1String("si")).toInt();
}
}
d->formula = reader.readElementText(); // read formula
return true;
}
/*!
* \internal
*/
bool CellFormula::operator ==(const CellFormula &formula) const
{
return d->formula == formula.d->formula && d->type == formula.d->type
&& d->si ==formula.d->si;
}
/*!
* \internal
*/
bool CellFormula::operator !=(const CellFormula &formula) const
{
return d->formula != formula.d->formula || d->type != formula.d->type
|| d->si !=formula.d->si;
}
QT_END_NAMESPACE_XLSX

23
src/QXlsx/xlsxcelllocation.cpp

@ -0,0 +1,23 @@
// xlsxcelllocation.cpp
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QVector>
#include <QList>
#include "xlsxglobal.h"
#include "xlsxcell.h"
#include "xlsxcelllocation.h"
QT_BEGIN_NAMESPACE_XLSX
CellLocation::CellLocation()
{
col = -1;
row = -1;
cell.reset();
}
QT_END_NAMESPACE_XLSX

127
src/QXlsx/xlsxcellrange.cpp

@ -0,0 +1,127 @@
// xlsxcellrange.cpp
#include <QtGlobal>
#include <QString>
#include <QPoint>
#include <QStringList>
#include "xlsxcellrange.h"
#include "xlsxcellreference.h"
QT_BEGIN_NAMESPACE_XLSX
/*!
\class CellRange
\brief For a range "A1:B2" or single cell "A1"
\inmodule QtXlsx
The CellRange class stores the top left and bottom
right rows and columns of a range in a worksheet.
*/
/*!
Constructs an range, i.e. a range
whose rowCount() and columnCount() are 0.
*/
CellRange::CellRange()
: top(-1), left(-1), bottom(-2), right(-2)
{
}
/*!
Constructs the range from the given \a top, \a
left, \a bottom and \a right rows and columns.
\sa topRow(), leftColumn(), bottomRow(), rightColumn()
*/
CellRange::CellRange(int top, int left, int bottom, int right)
: top(top), left(left), bottom(bottom), right(right)
{
}
CellRange::CellRange(const CellReference &topLeft, const CellReference &bottomRight)
: top(topLeft.row()), left(topLeft.column())
, bottom(bottomRight.row()), right(bottomRight.column())
{
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const QString &range)
{
init(range);
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const char *range)
{
init(QString::fromLatin1(range));
}
void CellRange::init(const QString &range)
{
QStringList rs = range.split(QLatin1Char(':'));
if (rs.size() == 2) {
CellReference start(rs[0]);
CellReference end(rs[1]);
top = start.row();
left = start.column();
bottom = end.row();
right = end.column();
} else {
CellReference p(rs[0]);
top = p.row();
left = p.column();
bottom = p.row();
right = p.column();
}
}
/*!
Constructs a the range by copying the given \a
other range.
*/
CellRange::CellRange(const CellRange &other)
: top(other.top), left(other.left), bottom(other.bottom), right(other.right)
{
}
/*!
Destroys the range.
*/
CellRange::~CellRange()
{
}
/*!
Convert the range to string notation, such as "A1:B5".
*/
QString CellRange::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
if (left == right && top == bottom) {
//Single cell
return CellReference(top, left).toString(row_abs, col_abs);
}
QString cell_1 = CellReference(top, left).toString(row_abs, col_abs);
QString cell_2 = CellReference(bottom, right).toString(row_abs, col_abs);
return cell_1 + QLatin1String(":") + cell_2;
}
/*!
* Returns true if the Range is valid.
*/
bool CellRange::isValid() const
{
return left <= right && top <= bottom;
}
QT_END_NAMESPACE_XLSX

154
src/QXlsx/xlsxcellreference.cpp

@ -0,0 +1,154 @@
// xlsxcellreference.cpp
#include "xlsxcellreference.h"
#include <QStringList>
#include <QMap>
#include <QRegularExpression>
QT_BEGIN_NAMESPACE_XLSX
namespace {
int intPow(int x, int p)
{
if (p == 0) return 1;
if (p == 1) return x;
int tmp = intPow(x, p/2);
if (p%2 == 0) return tmp * tmp;
else return x * tmp * tmp;
}
QString col_to_name(int col_num)
{
static thread_local QMap<int, QString> col_cache;
auto it = col_cache.find(col_num);
if (it == col_cache.end()) {
QString col_str;
int remainder;
while (col_num) {
remainder = col_num % 26;
if (remainder == 0)
remainder = 26;
col_str.prepend(QChar('A'+remainder-1));
col_num = (col_num - 1) / 26;
}
it = col_cache.insert(col_num, col_str);
}
return it.value();
}
int col_from_name(const QString &col_str)
{
int col = 0;
int expn = 0;
for (int i=col_str.size()-1; i>-1; --i) {
col += (col_str[i].unicode() - 'A' + 1) * intPow(26, expn);
expn++;
}
return col;
}
} //namespace
/*!
\class CellReference
\brief For one single cell such as "A1"
\inmodule QtXlsx
The CellReference class stores the cell location in a worksheet.
*/
/*!
Constructs an invalid Cell Reference
*/
CellReference::CellReference()
: _row(-1), _column(-1)
{
}
/*!
Constructs the Reference from the given \a row, and \a column.
*/
CellReference::CellReference(int row, int column)
: _row(row), _column(column)
{
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const QString &cell)
{
init(cell);
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const char *cell)
{
init(QString::fromLatin1(cell));
}
void CellReference::init(const QString &cell_str)
{
static thread_local QRegularExpression re(QStringLiteral("^\\$?([A-Z]{1,3})\\$?(\\d+)$"));
QRegularExpressionMatch match = re.match(cell_str);
if (match.hasMatch()) {
const QString col_str = match.captured(1);
const QString row_str = match.captured(2);
_row = row_str.toInt();
_column = col_from_name(col_str);
}
}
/*!
Constructs a Reference by copying the given \a
other Reference.
*/
CellReference::CellReference(const CellReference &other)
: _row(other._row), _column(other._column)
{
}
/*!
Destroys the Reference.
*/
CellReference::~CellReference()
{
}
/*!
Convert the Reference to string notation, such as "A1" or "$A$1".
If current object is invalid, an empty string will be returned.
*/
QString CellReference::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
QString cell_str;
if (col_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(col_to_name(_column));
if (row_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(QString::number(_row));
return cell_str;
}
/*!
* Returns true if the Reference is valid.
*/
bool CellReference::isValid() const
{
return _row > 0 && _column > 0;
}
QT_END_NAMESPACE_XLSX

2335
src/QXlsx/xlsxchart.cpp

File diff suppressed because it is too large

142
src/QXlsx/xlsxchartsheet.cpp

@ -0,0 +1,142 @@
// xlsxchartsheet.cpp
#include <QtGlobal>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDir>
#include "xlsxchartsheet.h"
#include "xlsxchartsheet_p.h"
#include "xlsxworkbook.h"
#include "xlsxutility_p.h"
#include "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxchart.h"
QT_BEGIN_NAMESPACE_XLSX
ChartsheetPrivate::ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag)
: AbstractSheetPrivate(p, flag), chart(0)
{
}
ChartsheetPrivate::~ChartsheetPrivate()
{
}
/*!
\class Chartsheet
\inmodule QtXlsx
\brief Represent one chartsheet in the workbook.
*/
/*!
* \internal
*/
Chartsheet::Chartsheet(const QString &name, int id, Workbook *workbook, CreateFlag flag)
: AbstractSheet( name, id, workbook, new ChartsheetPrivate(this, flag) )
{
setSheetType(ST_ChartSheet);
if (flag == Chartsheet::F_NewFromScratch)
{
d_func()->drawing = std::make_shared<Drawing>(this, flag);
DrawingAbsoluteAnchor *anchor = new DrawingAbsoluteAnchor(drawing(), DrawingAnchor::Picture);
anchor->pos = QPoint(0, 0);
anchor->ext = QSize(9293679, 6068786);
QSharedPointer<Chart> chart = QSharedPointer<Chart>(new Chart(this, flag));
chart->setChartType(Chart::CT_BarChart);
anchor->setObjectGraphicFrame(chart);
d_func()->chart = chart.data();
}
}
/*!
* \internal
*
* Make a copy of this sheet.
*/
Chartsheet *Chartsheet::copy(const QString &distName, int distId) const
{
//:Todo
Q_UNUSED(distName)
Q_UNUSED(distId)
return 0;
}
/*!
* Destroys this workssheet.
*/
Chartsheet::~Chartsheet()
{
}
/*!
* Returns the chart object of the sheet.
*/
Chart *Chartsheet::chart()
{
Q_D(Chartsheet);
return d->chart;
}
void Chartsheet::saveToXmlFile(QIODevice *device) const
{
Q_D(const Chartsheet);
d->relationships->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), QStringLiteral("r"));
writer.writeStartElement(QStringLiteral("chartsheet"));
writer.writeStartElement(QStringLiteral("sheetViews"));
writer.writeEmptyElement(QStringLiteral("sheetView"));
writer.writeAttribute(QStringLiteral("workbookViewId"), QString::number(0));
writer.writeAttribute(QStringLiteral("zoomToFit"), QStringLiteral("1"));
writer.writeEndElement(); //sheetViews
int idx = d->workbook->drawings().indexOf(d->drawing.get());
d->relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1));
writer.writeEmptyElement(QStringLiteral("drawing"));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
writer.writeEndElement();//chartsheet
writer.writeEndDocument();
}
bool Chartsheet::loadFromXmlFile(QIODevice *device)
{
Q_D(Chartsheet);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("drawing")) {
QString rId = reader.attributes().value(QStringLiteral("r:id")).toString();
QString name = d->relationships->getRelationshipById(rId).target;
const auto parts = splitPath(filePath());
QString path = QDir::cleanPath(parts.first() + QLatin1String("/") + name);
d->drawing = std::make_shared<Drawing>(this, F_LoadFromExists);
d->drawing->setFilePath(path);
}
}
}
return true;
}
QT_END_NAMESPACE_XLSX

196
src/QXlsx/xlsxcolor.cpp

@ -0,0 +1,196 @@
// xlsxcolor.cpp
#include <QDataStream>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include "xlsxcolor_p.h"
#include "xlsxstyles_p.h"
#include "xlsxutility_p.h"
QT_BEGIN_NAMESPACE_XLSX
XlsxColor::XlsxColor(const QColor &color)
{
if (color.isValid())
val.setValue(color);
}
XlsxColor::XlsxColor(const QString &theme, const QString &tint)
:val(QStringList()<<theme<<tint)
{
}
XlsxColor::XlsxColor(int index)
:val(index)
{
}
bool XlsxColor::isRgbColor() const
{
return val.userType() == qMetaTypeId<QColor>() && val.value<QColor>().isValid();
}
bool XlsxColor::isIndexedColor() const
{
return val.userType() == QMetaType::Int;
}
bool XlsxColor::isThemeColor() const
{
return val.userType() == QMetaType::QStringList;
}
bool XlsxColor::isInvalid() const
{
return !val.isValid();
}
QColor XlsxColor::rgbColor() const
{
return isRgbColor() ? val.value<QColor>() : QColor();
}
int XlsxColor::indexedColor() const
{
return isIndexedColor() ? val.toInt() : -1;
}
QStringList XlsxColor::themeColor() const
{
return isThemeColor() ? val.toStringList() : QStringList();
}
bool XlsxColor::saveToXml(QXmlStreamWriter &writer, const QString &node) const
{
if (!node.isEmpty())
writer.writeEmptyElement(node); //color, bgColor, fgColor
else
writer.writeEmptyElement(QStringLiteral("color"));
if (val.userType() == qMetaTypeId<QColor>()) {
writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(val.value<QColor>()));
} else if (val.userType() == QMetaType::QStringList) {
QStringList themes = val.toStringList();
writer.writeAttribute(QStringLiteral("theme"), themes[0]);
if (!themes[1].isEmpty())
writer.writeAttribute(QStringLiteral("tint"), themes[1]);
} else if (val.userType() == QMetaType::Int) {
writer.writeAttribute(QStringLiteral("indexed"), val.toString());
} else {
writer.writeAttribute(QStringLiteral("auto"), QStringLiteral("1"));
}
return true;
}
bool XlsxColor::loadFromXml(QXmlStreamReader &reader)
{
const auto& attributes = reader.attributes();
if (attributes.hasAttribute(QLatin1String("rgb"))) {
const auto& colorString = attributes.value(QLatin1String("rgb")).toString();
val.setValue(fromARGBString(colorString));
} else if (attributes.hasAttribute(QLatin1String("indexed"))) {
int index = attributes.value(QLatin1String("indexed")).toInt();
val.setValue(index);
} else if (attributes.hasAttribute(QLatin1String("theme"))) {
const auto& theme = attributes.value(QLatin1String("theme")).toString();
const auto& tint = attributes.value(QLatin1String("tint")).toString();
val.setValue(QStringList()<<theme<<tint);
}
return true;
}
XlsxColor::operator QVariant() const
{
const auto& cref
#if QT_VERSION >= 0x060000 // Qt 6.0 or over
= QMetaType::fromType<XlsxColor>();
#else
= qMetaTypeId<XlsxColor>() ;
#endif
return QVariant(cref, this);
}
QColor XlsxColor::fromARGBString(const QString &c)
{
QColor color;
if (c.startsWith(u'#')) {
color.setNamedColor(c);
} else {
color.setNamedColor(QLatin1Char('#') + c);
}
return color;
}
QString XlsxColor::toARGBString(const QColor &c)
{
return QString::asprintf("%02X%02X%02X%02X", c.alpha(), c.red(), c.green(), c.blue());
}
#if !defined(QT_NO_DATASTREAM)
QDataStream &operator<<(QDataStream &s, const XlsxColor &color)
{
if (color.isInvalid())
s<<0;
else if (color.isRgbColor())
s<<1<<color.rgbColor();
else if (color.isIndexedColor())
s<<2<<color.indexedColor();
else if (color.isThemeColor())
s<<3<<color.themeColor();
else
s<<4;
return s;
}
QDataStream &operator>>(QDataStream &s, XlsxColor &color)
{
int marker(4);
s>>marker;
if (marker == 0) {
color = XlsxColor();
} else if (marker == 1) {
QColor c;
s>>c;
color = XlsxColor(c);
} else if (marker == 2) {
int indexed;
s>>indexed;
color = XlsxColor(indexed);
} else if (marker == 3) {
QStringList list;
s>>list;
color = XlsxColor(list[0], list[1]);
}
return s;
}
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const XlsxColor &c)
{
if (c.isInvalid())
dbg.nospace() << "XlsxColor(invalid)";
else if (c.isRgbColor())
dbg.nospace() << c.rgbColor();
else if (c.isIndexedColor())
dbg.nospace() << "XlsxColor(indexed," << c.indexedColor() << ")";
else if (c.isThemeColor())
dbg.nospace() << "XlsxColor(theme," << c.themeColor().join(QLatin1Char(':')) << ')';
return dbg.space();
}
#endif
QT_END_NAMESPACE_XLSX

751
src/QXlsx/xlsxconditionalformatting.cpp

@ -0,0 +1,751 @@
// xlsxconditionalformatting.cpp
#include <QtGlobal>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include "xlsxconditionalformatting.h"
#include "xlsxconditionalformatting_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include "xlsxstyles_p.h"
QT_BEGIN_NAMESPACE_XLSX
ConditionalFormattingPrivate::ConditionalFormattingPrivate()
{
}
ConditionalFormattingPrivate::ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other)
:QSharedData(other)
{
}
ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
{
}
void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData &cfvo) const
{
writer.writeEmptyElement(QStringLiteral("cfvo"));
QString type;
switch(cfvo.type) {
case ConditionalFormatting::VOT_Formula: type=QStringLiteral("formula"); break;
case ConditionalFormatting::VOT_Max: type=QStringLiteral("max"); break;
case ConditionalFormatting::VOT_Min: type=QStringLiteral("min"); break;
case ConditionalFormatting::VOT_Num: type=QStringLiteral("num"); break;
case ConditionalFormatting::VOT_Percent: type=QStringLiteral("percent"); break;
case ConditionalFormatting::VOT_Percentile: type=QStringLiteral("percentile"); break;
default: break;
}
writer.writeAttribute(QStringLiteral("type"), type);
writer.writeAttribute(QStringLiteral("val"), cfvo.value);
if (!cfvo.gte)
writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0"));
}
/*!
* \class ConditionalFormatting
* \brief Conditional formatting for single cell or ranges
* \inmodule QtXlsx
*
* The conditional formatting can be applied to a single cell or ranges of cells.
*/
/*!
\enum ConditionalFormatting::HighlightRuleType
\value Highlight_LessThan
\value Highlight_LessThanOrEqual
\value Highlight_Equal
\value Highlight_NotEqual
\value Highlight_GreaterThanOrEqual
\value Highlight_GreaterThan
\value Highlight_Between
\value Highlight_NotBetween
\value Highlight_ContainsText
\value Highlight_NotContainsText
\value Highlight_BeginsWith
\value Highlight_EndsWith
\value Highlight_TimePeriod
\value Highlight_Duplicate
\value Highlight_Unique
\value Highlight_Blanks
\value Highlight_NoBlanks
\value Highlight_Errors
\value Highlight_NoErrors
\value Highlight_Top
\value Highlight_TopPercent
\value Highlight_Bottom
\value Highlight_BottomPercent
\value Highlight_AboveAverage
\value Highlight_AboveOrEqualAverage
\value Highlight_BelowAverage
\value Highlight_BelowOrEqualAverage
\value Highlight_AboveStdDev1
\value Highlight_AboveStdDev2
\value Highlight_AboveStdDev3
\value Highlight_BelowStdDev1
\value Highlight_BelowStdDev2
\value Highlight_BelowStdDev3
\value Highlight_Expression
*/
/*!
\enum ConditionalFormatting::ValueObjectType
\value VOT_Formula
\value VOT_Max
\value VOT_Min
\value VOT_Num
\value VOT_Percent
\value VOT_Percentile
*/
/*!
Construct a conditional formatting object
*/
ConditionalFormatting::ConditionalFormatting()
:d(new ConditionalFormattingPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other)
:d(other.d)
{
}
/*!
Assigns \a other to this conditional formatting and returns a reference to
this conditional formatting.
*/
ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other)
{
this->d = other.d;
return *this;
}
/*!
* Destroy the object.
*/
ConditionalFormatting::~ConditionalFormatting()
{
}
/*!
* Add a hightlight rule with the given \a type, \a formula1, \a formula2,
* \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue)
{
if (format.isEmpty())
return false;
bool skipFormula = false;
auto cfRule = std::make_shared<XlsxCfRuleData>();
if (type >= Highlight_LessThan && type <= Highlight_NotBetween) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs");
QString op;
switch (type) {
case Highlight_Between: op = QStringLiteral("between"); break;
case Highlight_Equal: op = QStringLiteral("equal"); break;
case Highlight_GreaterThan: op = QStringLiteral("greaterThan"); break;
case Highlight_GreaterThanOrEqual: op = QStringLiteral("greaterThanOrEqual"); break;
case Highlight_LessThan: op = QStringLiteral("lessThan"); break;
case Highlight_LessThanOrEqual: op = QStringLiteral("lessThanOrEqual"); break;
case Highlight_NotBetween: op = QStringLiteral("notBetween"); break;
case Highlight_NotEqual: op = QStringLiteral("notEqual"); break;
default: break;
}
cfRule->attrs[XlsxCfRuleData::A_operator] = op;
} else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) {
if (type == Highlight_ContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1);
} else if (type == Highlight_NotContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1);
} else if (type == Highlight_BeginsWith) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
} else {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
}
cfRule->attrs[XlsxCfRuleData::A_text] = formula1;
skipFormula = true;
} else if (type == Highlight_TimePeriod) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod");
//:Todo
return false;
} else if (type == Highlight_Duplicate) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues");
} else if (type == Highlight_Unique) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues");
} else if (type == Highlight_Errors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)");
skipFormula = true;
} else if (type == Highlight_NoErrors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))");
skipFormula = true;
} else if (type == Highlight_Blanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0");
skipFormula = true;
} else if (type == Highlight_NoBlanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0");
skipFormula = true;
} else if (type >= Highlight_Top && type <= Highlight_BottomPercent) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10");
if (type == Highlight_Bottom || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1");
if (type == Highlight_TopPercent || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1");
cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10");
skipFormula = true;
} else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage");
if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0");
if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage)
cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1");
if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1");
else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2");
else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3");
} else if (type == Highlight_Expression){
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression");
} else {
return false;
}
cfRule->dxfFormat = format;
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!skipFormula) {
if (!formula1.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula1] = formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1;
if (!formula2.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula2] = formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2;
}
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
*
* Add a hightlight rule with the given \a type \a format and \a stopIfTrue.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue)
{
if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3)
|| (type >= Highlight_Duplicate && type <= Highlight_NoErrors)) {
return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue);
}
return false;
}
/*!
* \overload
*
* Add a hightlight rule with the given \a type, \a formula, \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula, const Format &format, bool stopIfTrue)
{
if (type == Highlight_Between || type == Highlight_NotBetween)
return false;
return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue);
}
/*!
* Add a dataBar rule with the given \a color, \a type1, \a val1
* , \a type2, \a val2, \a showData and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue)
{
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!showData)
cfRule->attrs[XlsxCfRuleData::A_hideData] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
* Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue)
{
return addDataBarRule(color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue);
}
/*!
* Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("0");
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Percent;
ValueObjectType type3 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("50");
QString val3 = QStringLiteral("0");
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor);
cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
XlsxCfVoData cfvo3(type3, val3);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3);
d->cfRules.append(cfRule);
return true;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> ConditionalFormatting::ranges() const
{
return d->ranges;
}
/*!
Add the \a cell on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(int row, int col)
{
d->ranges.append(CellRange(row, col, row, col));
}
/*!
\overload
Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(const CellRange &range)
{
d->ranges.append(range);
}
bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *rule, Styles *styles)
{
Q_ASSERT(reader.name() == QLatin1String("cfRule"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("type")))
rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString();
if (attrs.hasAttribute(QLatin1String("dxfId"))) {
int id = attrs.value(QLatin1String("dxfId")).toInt();
if (styles)
rule->dxfFormat = styles->dxfFormat(id);
else
rule->dxfFormat.setDxfIndex(id);
}
rule->priority = attrs.value(QLatin1String("priority")).toInt();
if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1");
}
if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) {
//default is true
rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0");
}
if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1");
}
if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1");
}
if (attrs.hasAttribute(QLatin1String("operator")))
rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString();
if (attrs.hasAttribute(QLatin1String("text")))
rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString();
if (attrs.hasAttribute(QLatin1String("timePeriod")))
rule->attrs[XlsxCfRuleData::A_timePeriod] = attrs.value(QLatin1String("timePeriod")).toString();
if (attrs.hasAttribute(QLatin1String("rank")))
rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString();
if (attrs.hasAttribute(QLatin1String("stdDev")))
rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString();
if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1");
}
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula")) {
const QString f = reader.readElementText();
if (!rule->attrs.contains(XlsxCfRuleData::A_formula1))
rule->attrs[XlsxCfRuleData::A_formula1] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2))
rule->attrs[XlsxCfRuleData::A_formula2] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3))
rule->attrs[XlsxCfRuleData::A_formula3] = f;
} else if (reader.name() == QLatin1String("dataBar")) {
readCfDataBar(reader, rule);
} else if (reader.name() == QLatin1String("colorScale")) {
readCfColorScale(reader, rule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("dataBar"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.value(QLatin1String("showValue")) == QLatin1String("0"))
rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1");
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
rule->attrs[XlsxCfRuleData::A_color1] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("dataBar")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("colorScale"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2))
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
if (!rule->attrs.contains(XlsxCfRuleData::A_color1))
rule->attrs[XlsxCfRuleData::A_color1] = color;
else if (!rule->attrs.contains(XlsxCfRuleData::A_color2))
rule->attrs[XlsxCfRuleData::A_color2] = color;
else
rule->attrs[XlsxCfRuleData::A_color3] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("colorScale")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo)
{
Q_ASSERT(reader.name() == QStringLiteral("cfvo"));
QXmlStreamAttributes attrs = reader.attributes();
QString type = attrs.value(QLatin1String("type")).toString();
ConditionalFormatting::ValueObjectType t;
if (type == QLatin1String("formula"))
t = ConditionalFormatting::VOT_Formula;
else if (type == QLatin1String("max"))
t = ConditionalFormatting::VOT_Max;
else if (type == QLatin1String("min"))
t = ConditionalFormatting::VOT_Min;
else if (type == QLatin1String("num"))
t = ConditionalFormatting::VOT_Num;
else if (type == QLatin1String("percent"))
t = ConditionalFormatting::VOT_Percent;
else //if (type == QLatin1String("percentile"))
t = ConditionalFormatting::VOT_Percentile;
cfvo.type = t;
cfvo.value = attrs.value(QLatin1String("val")).toString();
if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) {
//default is true
cfvo.gte = false;
}
return true;
}
bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles)
{
Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting"));
d->ranges.clear();
d->cfRules.clear();
QXmlStreamAttributes attrs = reader.attributes();
const QString sqref = attrs.value(QLatin1String("sqref")).toString();
const auto sqrefParts = sqref.split(QLatin1Char(' '));
for (const QString &range : sqrefParts) {
this->addRange(range);
}
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfRule")) {
auto cfRule = std::make_shared<XlsxCfRuleData>();
d->readCfRule(reader, cfRule.get(), styles);
d->cfRules.append(cfRule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("conditionalFormatting"));
QStringList sqref;
const auto rangeList = ranges();
for (const CellRange &range : rangeList) {
sqref.append(range.toString());
}
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" ")));
for (int i=0; i<d->cfRules.size(); ++i) {
const std::shared_ptr<XlsxCfRuleData> &rule = d->cfRules[i];
writer.writeStartElement(QStringLiteral("cfRule"));
writer.writeAttribute(QStringLiteral("type"), rule->attrs[XlsxCfRuleData::A_type].toString());
if (rule->dxfFormat.dxfIndexValid())
writer.writeAttribute(QStringLiteral("dxfId"), QString::number(rule->dxfFormat.dxfIndex()));
writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority));
auto it = rule->attrs.constFind(XlsxCfRuleData::A_stopIfTrue);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("stopIfTrue"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_aboveAverage);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("aboveAverage"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_percent);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("percent"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_bottom);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("bottom"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_operator);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("operator"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_text);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("text"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_timePeriod);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("timePeriod"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_rank);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("rank"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_stdDev);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("stdDev"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_equalAverage);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("equalAverage"), it.value().toString());
if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) {
writer.writeStartElement(QStringLiteral("dataBar"));
if (rule->attrs.contains(XlsxCfRuleData::A_hideData))
writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
writer.writeEndElement();//dataBar
} else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) {
writer.writeStartElement(QStringLiteral("colorScale"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
it = rule->attrs.constFind(XlsxCfRuleData::A_cfvo3);
if (it != rule->attrs.constEnd())
d->writeCfVo(writer, it.value().value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer);
it = rule->attrs.constFind(XlsxCfRuleData::A_color3);
if (it != rule->attrs.constEnd())
it.value().value<XlsxColor>().saveToXml(writer);
writer.writeEndElement();//colorScale
}
it = rule->attrs.constFind(XlsxCfRuleData::A_formula1_temp);
if (it != rule->attrs.constEnd()) {
const auto _ranges = ranges();
const auto begin = _ranges.begin();
if (begin != _ranges.end()) {
QString str = begin->toString();
QString startCell = str.mid(0, str.indexOf(u':'));
writer.writeTextElement(QStringLiteral("formula"), it.value().toString().arg(startCell));
}
} else if ((it = rule->attrs.constFind(XlsxCfRuleData::A_formula1)) != rule->attrs.constEnd()) {
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
}
it = rule->attrs.constFind(XlsxCfRuleData::A_formula2);
if (it != rule->attrs.constEnd())
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_formula3);
if (it != rule->attrs.constEnd())
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
writer.writeEndElement(); //cfRule
}
writer.writeEndElement(); //conditionalFormatting
return true;
}
QT_END_NAMESPACE_XLSX

184
src/QXlsx/xlsxcontenttypes.cpp

@ -0,0 +1,184 @@
// xlsxcontenttypes.cpp
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QMapIterator>
#include <QBuffer>
#include <QDebug>
#include "xlsxcontenttypes_p.h"
QT_BEGIN_NAMESPACE_XLSX
ContentTypes::ContentTypes(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_package_prefix = QStringLiteral("application/vnd.openxmlformats-package.");
m_document_prefix = QStringLiteral("application/vnd.openxmlformats-officedocument.");
m_defaults.insert(QStringLiteral("rels"), m_package_prefix + QLatin1String("relationships+xml"));
m_defaults.insert(QStringLiteral("xml"), QStringLiteral("application/xml"));
}
void ContentTypes::addDefault(const QString &key, const QString &value)
{
m_defaults.insert(key, value);
}
void ContentTypes::addOverride(const QString &key, const QString &value)
{
m_overrides.insert(key, value);
}
void ContentTypes::addDocPropApp()
{
addOverride(QStringLiteral("/docProps/app.xml"), m_document_prefix + QLatin1String("extended-properties+xml"));
}
void ContentTypes::addDocPropCore()
{
addOverride(QStringLiteral("/docProps/core.xml"), m_package_prefix + QLatin1String("core-properties+xml"));
}
void ContentTypes::addStyles()
{
addOverride(QStringLiteral("/xl/styles.xml"), m_document_prefix + QLatin1String("spreadsheetml.styles+xml"));
}
void ContentTypes::addTheme()
{
addOverride(QStringLiteral("/xl/theme/theme1.xml"), m_document_prefix + QLatin1String("theme+xml"));
}
void ContentTypes::addWorkbook()
{
addOverride(QStringLiteral("/xl/workbook.xml"), m_document_prefix + QLatin1String("spreadsheetml.sheet.main+xml"));
}
void ContentTypes::addWorksheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/worksheets/%1.xml").arg(name), m_document_prefix + QLatin1String("spreadsheetml.worksheet+xml"));
}
void ContentTypes::addChartsheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/chartsheets/%1.xml").arg(name), m_document_prefix + QLatin1String("spreadsheetml.chartsheet+xml"));
}
void ContentTypes::addDrawingName(const QString &name)
{
addOverride(QStringLiteral("/xl/drawings/%1.xml").arg(name), m_document_prefix + QLatin1String("drawing+xml"));
}
void ContentTypes::addChartName(const QString &name)
{
addOverride(QStringLiteral("/xl/charts/%1.xml").arg(name), m_document_prefix + QLatin1String("drawingml.chart+xml"));
}
void ContentTypes::addCommentName(const QString &name)
{
addOverride(QStringLiteral("/xl/%1.xml").arg(name), m_document_prefix + QLatin1String("spreadsheetml.comments+xml"));
}
void ContentTypes::addTableName(const QString &name)
{
addOverride(QStringLiteral("/xl/tables/%1.xml").arg(name), m_document_prefix + QLatin1String("spreadsheetml.table+xml"));
}
void ContentTypes::addExternalLinkName(const QString &name)
{
addOverride(QStringLiteral("/xl/externalLinks/%1.xml").arg(name), m_document_prefix + QLatin1String("spreadsheetml.externalLink+xml"));
}
void ContentTypes::addSharedString()
{
addOverride(QStringLiteral("/xl/sharedStrings.xml"), m_document_prefix + QLatin1String("spreadsheetml.sharedStrings+xml"));
}
void ContentTypes::addVmlName()
{
addOverride(QStringLiteral("vml"), m_document_prefix + QLatin1String("vmlDrawing"));
}
void ContentTypes::addCalcChain()
{
addOverride(QStringLiteral("/xl/calcChain.xml"), m_document_prefix + QLatin1String("spreadsheetml.calcChain+xml"));
}
void ContentTypes::addVbaProject()
{
//:TODO
addOverride(QStringLiteral("bin"), QStringLiteral("application/vnd.ms-office.vbaProject"));
}
void ContentTypes::clearOverrides()
{
m_overrides.clear();
}
void ContentTypes::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Types"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/content-types"));
{
QMapIterator<QString, QString> it(m_defaults);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Default"));
writer.writeAttribute(QStringLiteral("Extension"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement();//Default
}
}
{
QMapIterator<QString, QString> it(m_overrides);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Override"));
writer.writeAttribute(QStringLiteral("PartName"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement(); //Override
}
}
writer.writeEndElement();//Types
writer.writeEndDocument();
}
bool ContentTypes::loadFromXmlFile(QIODevice *device)
{
m_defaults.clear();
m_overrides.clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Default")) {
QXmlStreamAttributes attrs = reader.attributes();
QString extension = attrs.value(QLatin1String("Extension")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_defaults.insert(extension, type);
} else if (reader.name() == QLatin1String("Override")) {
QXmlStreamAttributes attrs = reader.attributes();
QString partName = attrs.value(QLatin1String("PartName")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_overrides.insert(partName, type);
}
}
if (reader.hasError()) {
qDebug()<<reader.errorString();
}
}
return true;
}
QT_END_NAMESPACE_XLSX

537
src/QXlsx/xlsxdatavalidation.cpp

@ -0,0 +1,537 @@
// xlsxdatavalidation.cpp
#include <QtGlobal>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include "xlsxdatavalidation.h"
#include "xlsxdatavalidation_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
QT_BEGIN_NAMESPACE_XLSX
DataValidationPrivate::DataValidationPrivate()
:validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:validationType(type), validationOperator(op)
, errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true)
, isErrorMessageVisible(true), formula1(formula1), formula2(formula2)
{
}
DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other)
:QSharedData(other)
, validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::~DataValidationPrivate()
{
}
/*!
* \class DataValidation
* \brief Data validation for single cell or a range
* \inmodule QtXlsx
*
* The data validation can be applied to a single cell or a range of cells.
*/
/*!
* \enum DataValidation::ValidationType
*
* The enum type defines the type of data that you wish to validate.
*
* \value None the type of data is unrestricted. This is the same as not applying a data validation.
* \value Whole restricts the cell to integer values. Means "Whole number"?
* \value Decimal restricts the cell to decimal values.
* \value List restricts the cell to a set of user specified values.
* \value Date restricts the cell to date values.
* \value Time restricts the cell to time values.
* \value TextLength restricts the cell data based on an integer string length.
* \value Custom restricts the cell based on an external Excel formula that returns a true/false value.
*/
/*!
* \enum DataValidation::ValidationOperator
*
* The enum type defines the criteria by which the data in the
* cell is validated
*
* \value Between
* \value NotBetween
* \value Equal
* \value NotEqual
* \value LessThan
* \value LessThanOrEqual
* \value GreaterThan
* \value GreaterThanOrEqual
*/
/*!
* \enum DataValidation::ErrorStyle
*
* The enum type defines the type of error dialog that
* is displayed.
*
* \value Stop
* \value Warning
* \value Information
*/
/*!
* Construct a data validation object with the given \a type, \a op, \a formula1
* \a formula2, and \a allowBlank.
*/
DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank))
{
}
/*!
Construct a data validation object
*/
DataValidation::DataValidation()
:d(new DataValidationPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
DataValidation::DataValidation(const DataValidation &other)
:d(other.d)
{
}
/*!
Assigns \a other to this validation and returns a reference to this validation.
*/
DataValidation &DataValidation::operator=(const DataValidation &other)
{
this->d = other.d;
return *this;
}
/*!
* Destroy the object.
*/
DataValidation::~DataValidation()
{
}
/*!
Returns the validation type.
*/
DataValidation::ValidationType DataValidation::validationType() const
{
return d->validationType;
}
/*!
Returns the validation operator.
*/
DataValidation::ValidationOperator DataValidation::validationOperator() const
{
return d->validationOperator;
}
/*!
Returns the validation error style.
*/
DataValidation::ErrorStyle DataValidation::errorStyle() const
{
return d->errorStyle;
}
/*!
Returns the formula1.
*/
QString DataValidation::formula1() const
{
return d->formula1;
}
/*!
Returns the formula2.
*/
QString DataValidation::formula2() const
{
return d->formula2;
}
/*!
Returns whether blank is allowed.
*/
bool DataValidation::allowBlank() const
{
return d->allowBlank;
}
/*!
Returns the error message.
*/
QString DataValidation::errorMessage() const
{
return d->errorMessage;
}
/*!
Returns the error message title.
*/
QString DataValidation::errorMessageTitle() const
{
return d->errorMessageTitle;
}
/*!
Returns the prompt message.
*/
QString DataValidation::promptMessage() const
{
return d->promptMessage;
}
/*!
Returns the prompt message title.
*/
QString DataValidation::promptMessageTitle() const
{
return d->promptMessageTitle;
}
/*!
Returns the whether prompt message is shown.
*/
bool DataValidation::isPromptMessageVisible() const
{
return d->isPromptMessageVisible;
}
/*!
Returns the whether error message is shown.
*/
bool DataValidation::isErrorMessageVisible() const
{
return d->isErrorMessageVisible;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> DataValidation::ranges() const
{
return d->ranges;
}
/*!
Sets the validation type to \a type.
*/
void DataValidation::setValidationType(DataValidation::ValidationType type)
{
d->validationType = type;
}
/*!
Sets the validation operator to \a op.
*/
void DataValidation::setValidationOperator(DataValidation::ValidationOperator op)
{
d->validationOperator = op;
}
/*!
Sets the error style to \a es.
*/
void DataValidation::setErrorStyle(DataValidation::ErrorStyle es)
{
d->errorStyle = es;
}
/*!
Sets the formula1 to \a formula.
*/
void DataValidation::setFormula1(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula1 = formula.mid(1);
else
d->formula1 = formula;
}
/*!
Sets the formulas to \a formula.
*/
void DataValidation::setFormula2(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula2 = formula.mid(1);
else
d->formula2 = formula;
}
/*!
Sets the error message to \a error with title \a title.
*/
void DataValidation::setErrorMessage(const QString &error, const QString &title)
{
d->errorMessage = error;
d->errorMessageTitle = title;
}
/*!
Sets the prompt message to \a prompt with title \a title.
*/
void DataValidation::setPromptMessage(const QString &prompt, const QString &title)
{
d->promptMessage = prompt;
d->promptMessageTitle = title;
}
/*!
Enable/disabe blank allow based on \a enable.
*/
void DataValidation::setAllowBlank(bool enable)
{
d->allowBlank = enable;
}
/*!
Enable/disabe prompt message visible based on \a visible.
*/
void DataValidation::setPromptMessageVisible(bool visible)
{
d->isPromptMessageVisible = visible;
}
/*!
Enable/disabe error message visible based on \a visible.
*/
void DataValidation::setErrorMessageVisible(bool visible)
{
d->isErrorMessageVisible = visible;
}
/*!
Add the \a cell on which the DataValidation will apply to.
*/
void DataValidation::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the DataValidation will apply to.
*/
void DataValidation::addCell(int row, int col)
{
d->ranges.append(CellRange(row, col, row, col));
}
/*!
\overload
Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
which the DataValidation will apply to.
*/
void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the DataValidation will apply to.
*/
void DataValidation::addRange(const CellRange &range)
{
d->ranges.append(range);
}
/*!
* \internal
*/
bool DataValidation::saveToXml(QXmlStreamWriter &writer) const
{
static const QMap<DataValidation::ValidationType, QString> typeMap = {
{DataValidation::None, QStringLiteral("none")},
{DataValidation::Whole, QStringLiteral("whole")},
{DataValidation::Decimal, QStringLiteral("decimal")},
{DataValidation::List, QStringLiteral("list")},
{DataValidation::Date, QStringLiteral("date")},
{DataValidation::Time, QStringLiteral("time")},
{DataValidation::TextLength, QStringLiteral("textLength")},
{DataValidation::Custom, QStringLiteral("custom")}
};
static const QMap<DataValidation::ValidationOperator, QString> opMap = {
{DataValidation::Between, QStringLiteral("between")},
{DataValidation::NotBetween, QStringLiteral("notBetween")},
{DataValidation::Equal, QStringLiteral("equal")},
{DataValidation::NotEqual, QStringLiteral("notEqual")},
{DataValidation::LessThan, QStringLiteral("lessThan")},
{DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual")},
{DataValidation::GreaterThan, QStringLiteral("greaterThan")},
{DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual")}
};
static const QMap<DataValidation::ErrorStyle, QString> esMap = {
{DataValidation::Stop, QStringLiteral("stop")},
{DataValidation::Warning, QStringLiteral("warning")},
{DataValidation::Information, QStringLiteral("information")}
};
writer.writeStartElement(QStringLiteral("dataValidation"));
if (validationType() != DataValidation::None)
writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]);
if (errorStyle() != DataValidation::Stop)
writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]);
if (validationOperator() != DataValidation::Between)
writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]);
if (allowBlank())
writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1"));
// if (dropDownVisible())
// writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1"));
if (isPromptMessageVisible())
writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1"));
if (isErrorMessageVisible())
writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1"));
if (!errorMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle());
if (!errorMessage().isEmpty())
writer.writeAttribute(QStringLiteral("error"), errorMessage());
if (!promptMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle());
if (!promptMessage().isEmpty())
writer.writeAttribute(QStringLiteral("prompt"), promptMessage());
QStringList sqref;
const auto rangeList = ranges();
for (const CellRange &range : rangeList)
sqref.append(range.toString());
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" ")));
if (!formula1().isEmpty())
writer.writeTextElement(QStringLiteral("formula1"), formula1());
if (!formula2().isEmpty())
writer.writeTextElement(QStringLiteral("formula2"), formula2());
writer.writeEndElement(); //dataValidation
return true;
}
/*!
* \internal
*/
DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("dataValidation"));
static const QMap<QString, DataValidation::ValidationType> typeMap = {
{QStringLiteral("none"), DataValidation::None},
{QStringLiteral("whole"), DataValidation::Whole},
{QStringLiteral("decimal"), DataValidation::Decimal},
{QStringLiteral("list"), DataValidation::List},
{QStringLiteral("date"), DataValidation::Date},
{QStringLiteral("time"), DataValidation::Time},
{QStringLiteral("textLength"), DataValidation::TextLength},
{QStringLiteral("custom"), DataValidation::Custom}
};
static const QMap<QString, DataValidation::ValidationOperator> opMap = {
{QStringLiteral("between"), DataValidation::Between},
{QStringLiteral("notBetween"), DataValidation::NotBetween},
{QStringLiteral("equal"), DataValidation::Equal},
{QStringLiteral("notEqual"), DataValidation::NotEqual},
{QStringLiteral("lessThan"), DataValidation::LessThan},
{QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual},
{QStringLiteral("greaterThan"), DataValidation::GreaterThan},
{QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual}
};
static const QMap<QString, DataValidation::ErrorStyle> esMap = {
{QStringLiteral("stop"), DataValidation::Stop},
{QStringLiteral("warning"), DataValidation::Warning},
{QStringLiteral("information"), DataValidation::Information}
};
DataValidation validation;
QXmlStreamAttributes attrs = reader.attributes();
QString sqref = attrs.value(QLatin1String("sqref")).toString();
const auto sqrefParts = sqref.split(QLatin1Char(' '));
for (const QString &range : sqrefParts)
validation.addRange(range);
if (attrs.hasAttribute(QLatin1String("type"))) {
QString t = attrs.value(QLatin1String("type")).toString();
auto it = typeMap.constFind(t);
validation.setValidationType(it != typeMap.constEnd() ? it.value() : DataValidation::None);
}
if (attrs.hasAttribute(QLatin1String("errorStyle"))) {
QString es = attrs.value(QLatin1String("errorStyle")).toString();
auto it = esMap.constFind(es);
validation.setErrorStyle(it != esMap.constEnd() ? it.value() : DataValidation::Stop);
}
if (attrs.hasAttribute(QLatin1String("operator"))) {
QString op = attrs.value(QLatin1String("operator")).toString();
auto it = opMap.constFind(op);
validation.setValidationOperator(it != opMap.constEnd() ? it.value() : DataValidation::Between);
}
if (attrs.hasAttribute(QLatin1String("allowBlank"))) {
validation.setAllowBlank(true);
} else {
validation.setAllowBlank(false);
}
if (attrs.hasAttribute(QLatin1String("showInputMessage"))) {
validation.setPromptMessageVisible(true);
} else {
validation.setPromptMessageVisible(false);
}
if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) {
validation.setErrorMessageVisible(true);
} else {
validation.setErrorMessageVisible(false);
}
QString et = attrs.value(QLatin1String("errorTitle")).toString();
QString e = attrs.value(QLatin1String("error")).toString();
if (!e.isEmpty() || !et.isEmpty())
validation.setErrorMessage(e, et);
QString pt = attrs.value(QLatin1String("promptTitle")).toString();
QString p = attrs.value(QLatin1String("prompt")).toString();
if (!p.isEmpty() || !pt.isEmpty())
validation.setPromptMessage(p, pt);
//find the end
while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula1")) {
validation.setFormula1(reader.readElementText());
} else if (reader.name() == QLatin1String("formula2")) {
validation.setFormula2(reader.readElementText());
}
}
}
return validation;
}
QT_END_NAMESPACE_XLSX

85
src/QXlsx/xlsxdatetype.cpp

@ -0,0 +1,85 @@
// xlsxdatetype.cpp
#include <QtGlobal>
#include "xlsxglobal.h"
#include "xlsxutility_p.h"
#include "xlsxdatetype.h"
QT_BEGIN_NAMESPACE_XLSX
DateType::DateType()
{
}
/*
DateType::DateType(bool is1904)
{
isSet = false;
}
DateType::DateType(double d, bool is1904)
{
// TODO: check date
// int iVaue = (int) d;
// double surplus = d - double(iVaue);
dValue = d;
is1904Type = is1904;
isSet = true;
}
DateType::DateType(QDateTime qdt, bool is1904)
{
double ret = datetimeToNumber( qdt, is1904 );
dValue = ret;
is1904Type = is1904;
isSet = true;
}
DateType::DateType(QDate qd, bool is1904)
{
is1904Type = is1904;
isSet = true;
}
DateType::DateType(QTime qt, bool is1904)
{
double ret = timeToNumber( qt );
dValue = ret;
is1904Type = is1904;
isSet = true;
}
// enum currentDateType { DateAndTimeType, OnlyDateType, OnlyTimeType };
DateType::currentDateType DateType::getType()
{
}
bool DateType::getValue(QDateTime* pQdt)
{
}
bool DateType::getValue(QDate* pQd)
{
}
bool DateType::getValue(QTime* pQt)
{
}
bool DateType::getValue(double* pD)
{
}
*/
QT_END_NAMESPACE_XLSX

138
src/QXlsx/xlsxdocpropsapp.cpp

@ -0,0 +1,138 @@
// xlsxdocpropsapp.cpp
#include "xlsxdocpropsapp_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QVariant>
#include <QBuffer>
QT_BEGIN_NAMESPACE_XLSX
DocPropsApp::DocPropsApp(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void DocPropsApp::addPartTitle(const QString &title)
{
m_titlesOfPartsList.append(title);
}
void DocPropsApp::addHeadingPair(const QString &name, int value)
{
m_headingPairsList.append({ name, value });
}
bool DocPropsApp::setProperty(const QString &name, const QString &value)
{
static const QStringList validKeys = {
QStringLiteral("manager"), QStringLiteral("company")
};
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsApp::property(const QString &name) const
{
auto it = m_properties.constFind(name);
if (it != m_properties.constEnd())
return it.value();
return QString();
}
QStringList DocPropsApp::propertyNames() const
{
return m_properties.keys();
}
void DocPropsApp::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
QString vt = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Properties"));
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"));
writer.writeNamespace(vt, QStringLiteral("vt"));
writer.writeTextElement(QStringLiteral("Application"), QStringLiteral("Microsoft Excel"));
writer.writeTextElement(QStringLiteral("DocSecurity"), QStringLiteral("0"));
writer.writeTextElement(QStringLiteral("ScaleCrop"), QStringLiteral("false"));
writer.writeStartElement(QStringLiteral("HeadingPairs"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_headingPairsList.size()*2));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("variant"));
for (const auto &pair : m_headingPairsList) {
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("lpstr"), pair.first);
writer.writeEndElement(); //vt:variant
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("i4"), QString::number(pair.second));
writer.writeEndElement(); //vt:variant
}
writer.writeEndElement();//vt:vector
writer.writeEndElement();//HeadingPairs
writer.writeStartElement(QStringLiteral("TitlesOfParts"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_titlesOfPartsList.size()));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("lpstr"));
for (const QString &title : m_titlesOfPartsList)
writer.writeTextElement(vt, QStringLiteral("lpstr"), title);
writer.writeEndElement();//vt:vector
writer.writeEndElement();//TitlesOfParts
auto it = m_properties.constFind(QStringLiteral("manager"));
if (it != m_properties.constEnd())
writer.writeTextElement(QStringLiteral("Manager"), it.value());
//Not like "manager", "company" always exists for Excel generated file.
it = m_properties.constFind(QStringLiteral("company"));
writer.writeTextElement(QStringLiteral("Company"), it != m_properties.constEnd() ? it.value() : QString());
writer.writeTextElement(QStringLiteral("LinksUpToDate"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("SharedDoc"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("HyperlinksChanged"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("AppVersion"), QStringLiteral("12.0000"));
writer.writeEndElement(); //Properties
writer.writeEndDocument();
}
bool DocPropsApp::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Properties"))
continue;
if (reader.name() == QStringLiteral("Manager")) {
setProperty(QStringLiteral("manager"), reader.readElementText());
} else if (reader.name() == QStringLiteral("Company")) {
setProperty(QStringLiteral("company"), reader.readElementText());
}
}
if (reader.hasError()) {
qDebug("Error when read doc props app file.");
}
}
return true;
}
QT_END_NAMESPACE_XLSX

176
src/QXlsx/xlsxdocpropscore.cpp

@ -0,0 +1,176 @@
// xlsxdocpropscore.cpp
#include <QtGlobal>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QBuffer>
#include "xlsxdocpropscore_p.h"
QT_BEGIN_NAMESPACE_XLSX
DocPropsCore::DocPropsCore(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
bool DocPropsCore::setProperty(const QString &name, const QString &value)
{
static const QStringList validKeys = {
QStringLiteral("title"), QStringLiteral("subject"),
QStringLiteral("keywords"), QStringLiteral("description"),
QStringLiteral("category"), QStringLiteral("status"),
QStringLiteral("created"), QStringLiteral("creator")
};
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsCore::property(const QString &name) const
{
auto it = m_properties.constFind(name);
if (it != m_properties.constEnd())
return it.value();
return QString();
}
QStringList DocPropsCore::propertyNames() const
{
return m_properties.keys();
}
void DocPropsCore::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
const QString dcmitype = QStringLiteral("http://purl.org/dc/dcmitype/");
const QString xsi = QStringLiteral("http://www.w3.org/2001/XMLSchema-instance");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("cp:coreProperties"));
writer.writeNamespace(cp, QStringLiteral("cp"));
writer.writeNamespace(dc, QStringLiteral("dc"));
writer.writeNamespace(dcterms, QStringLiteral("dcterms"));
writer.writeNamespace(dcmitype, QStringLiteral("dcmitype"));
writer.writeNamespace(xsi, QStringLiteral("xsi"));
auto it = m_properties.constFind(QStringLiteral("title"));
if (it != m_properties.constEnd())
writer.writeTextElement(dc, QStringLiteral("title"), it.value());
it = m_properties.constFind(QStringLiteral("subject"));
if (it != m_properties.constEnd())
writer.writeTextElement(dc, QStringLiteral("subject"), it.value());
it = m_properties.constFind(QStringLiteral("creator"));
writer.writeTextElement(dc, QStringLiteral("creator"), it != m_properties.constEnd() ? it.value() : QStringLiteral("Qt Xlsx Library"));
it = m_properties.constFind(QStringLiteral("keywords"));
if (it != m_properties.constEnd())
writer.writeTextElement(cp, QStringLiteral("keywords"), it.value());
it = m_properties.constFind(QStringLiteral("description"));
if (it != m_properties.constEnd())
writer.writeTextElement(dc, QStringLiteral("description"), it.value());
it = m_properties.constFind(QStringLiteral("creator"));
writer.writeTextElement(cp, QStringLiteral("lastModifiedBy"), it != m_properties.constEnd() ? it.value() : QStringLiteral("Qt Xlsx Library"));
writer.writeStartElement(dcterms, QStringLiteral("created"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
it = m_properties.constFind(QStringLiteral("created"));
writer.writeCharacters(it != m_properties.constEnd() ? it.value() : QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
writer.writeStartElement(dcterms, QStringLiteral("modified"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
writer.writeCharacters(QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
it = m_properties.constFind(QStringLiteral("category"));
if (it != m_properties.constEnd())
writer.writeTextElement(cp, QStringLiteral("category"), it.value());
it = m_properties.constFind(QStringLiteral("status"));
if (it != m_properties.constEnd())
writer.writeTextElement(cp, QStringLiteral("contentStatus"), it.value());
writer.writeEndElement(); //cp:coreProperties
writer.writeEndDocument();
}
bool DocPropsCore::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
while (!reader.atEnd())
{
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement)
{
const auto& nsUri = reader.namespaceUri();
const auto& name = reader.name();
if (name == QStringLiteral("subject") && nsUri == dc)
{
setProperty(QStringLiteral("subject"), reader.readElementText());
}
else if (name == QStringLiteral("title") && nsUri == dc)
{
setProperty(QStringLiteral("title"), reader.readElementText());
}
else if (name == QStringLiteral("creator") && nsUri == dc)
{
setProperty(QStringLiteral("creator"), reader.readElementText());
}
else if (name == QStringLiteral("description") && nsUri == dc)
{
setProperty(QStringLiteral("description"), reader.readElementText());
}
else if (name == QStringLiteral("keywords") && nsUri == cp)
{
setProperty(QStringLiteral("keywords"), reader.readElementText());
}
else if (name == QStringLiteral("created") && nsUri == dcterms)
{
setProperty(QStringLiteral("created"), reader.readElementText());
}
else if (name == QStringLiteral("category") && nsUri == cp)
{
setProperty(QStringLiteral("category"), reader.readElementText());
}
else if (name == QStringLiteral("contentStatus") && nsUri == cp)
{
setProperty(QStringLiteral("status"), reader.readElementText());
}
}
if (reader.hasError())
{
qDebug() << "Error when read doc props core file." << reader.errorString();
}
}
return true;
}
QT_END_NAMESPACE_XLSX

1454
src/QXlsx/xlsxdocument.cpp

File diff suppressed because it is too large

84
src/QXlsx/xlsxdrawing.cpp

@ -0,0 +1,84 @@
// xlsxdrawing.cpp
#include <QtGlobal>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QBuffer>
#include "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxabstractsheet.h"
QT_BEGIN_NAMESPACE_XLSX
Drawing::Drawing(AbstractSheet *sheet, CreateFlag flag)
:AbstractOOXmlFile(flag), sheet(sheet)
{
workbook = sheet->workbook();
}
Drawing::~Drawing()
{
qDeleteAll(anchors);
}
void Drawing::saveToXmlFile(QIODevice *device) const
{
relationships()->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("xdr:wsDr"));
writer.writeAttribute(QStringLiteral("xmlns:xdr"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"));
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
for (DrawingAnchor *anchor : anchors)
anchor->saveToXml(writer);
writer.writeEndElement();//xdr:wsDr
writer.writeEndDocument();
}
// check point
bool Drawing::loadFromXmlFile(QIODevice *device)
{
/*
<xsd:group name="EG_Anchor">
<xsd:choice>
<xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/>
<xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/>
<xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/>
</xsd:choice>
</xsd:group>
*/
QXmlStreamReader reader(device);
while (!reader.atEnd())
{
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement)
{
if (reader.name() == QLatin1String("absoluteAnchor")) // CT_AbsoluteAnchor
{
DrawingAbsoluteAnchor * anchor = new DrawingAbsoluteAnchor(this);
anchor->loadFromXml(reader);
}
else if (reader.name() == QLatin1String("oneCellAnchor")) // CT_OneCellAnchor
{
DrawingOneCellAnchor * anchor = new DrawingOneCellAnchor(this);
anchor->loadFromXml(reader);
}
else if (reader.name() == QLatin1String("twoCellAnchor")) // CT_TwoCellAnchor
{
DrawingTwoCellAnchor * anchor = new DrawingTwoCellAnchor(this);
anchor->loadFromXml(reader);
}
}
}
return true;
}
QT_END_NAMESPACE_XLSX

1203
src/QXlsx/xlsxdrawinganchor.cpp

File diff suppressed because it is too large

1437
src/QXlsx/xlsxformat.cpp

File diff suppressed because it is too large

78
src/QXlsx/xlsxmediafile.cpp

@ -0,0 +1,78 @@
// xlsxmediafile.cpp
#include <QtGlobal>
#include <QCryptographicHash>
#include "xlsxmediafile_p.h"
QT_BEGIN_NAMESPACE_XLSX
MediaFile::MediaFile(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
: m_contents(bytes), m_suffix(suffix), m_mimeType(mimeType)
, m_index(0), m_indexValid(false)
{
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
}
MediaFile::MediaFile(const QString &fileName)
:m_fileName(fileName), m_index(0), m_indexValid(false)
{
}
void MediaFile::set(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
{
m_contents = bytes;
m_suffix = suffix;
m_mimeType = mimeType;
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
m_indexValid = false;
}
void MediaFile::setFileName(const QString &name)
{
m_fileName = name;
}
QString MediaFile::fileName() const
{
return m_fileName;
}
QString MediaFile::suffix() const
{
return m_suffix;
}
QString MediaFile::mimeType() const
{
return m_mimeType;
}
QByteArray MediaFile::contents() const
{
return m_contents;
}
int MediaFile::index() const
{
return m_index;
}
bool MediaFile::isIndexValid() const
{
return m_indexValid;
}
void MediaFile::setIndex(int idx)
{
m_index = idx;
m_indexValid = true;
}
QByteArray MediaFile::hashKey() const
{
return m_hashKey;
}
QT_END_NAMESPACE_XLSX

74
src/QXlsx/xlsxnumformatparser.cpp

@ -0,0 +1,74 @@
// xlsxnumformatparser.cpp
#include "xlsxnumformatparser_p.h"
#include <QtGlobal>
#include <QString>
QT_BEGIN_NAMESPACE_XLSX
bool NumFormatParser::isDateTime(const QString &formatCode)
{
for (int i = 0; i < formatCode.length(); ++i) {
const QChar &c = formatCode[i];
switch (c.unicode()) {
case '[':
// [h], [m], [s] are valid format for time
if (i < formatCode.length()-2 && formatCode[i+2] == QLatin1Char(']')) {
const QChar cc = formatCode[i+1].toLower();
if (cc == QLatin1Char('h') || cc == QLatin1Char('m') || cc == QLatin1Char('s'))
return true;
i+=2;
break;
} else {
// condition or color: don't care, ignore
while (i < formatCode.length() && formatCode[i] != QLatin1Char(']'))
++i;
break;
}
// quoted plain text block: don't care, ignore
case '"':
while (i < formatCode.length()-1 && formatCode[++i] != QLatin1Char('"'))
;
break;
// escaped char: don't care, ignore
case '\\':
if (i < formatCode.length() - 1)
++i;
break;
// date/time can only be positive number,
// so only the first section of the format make sense.
case '#': // this is new an working // https://github.com/QtExcel/QXlsx/issues/190
case ';':
return false;
break;
// days
case 'D':
case 'd':
// years
case 'Y':
case 'y':
// hours
case 'H':
case 'h':
// seconds
case 'S':
case 's':
// minutes or months, depending on context
case 'M':
case 'm':
return true;
default:
break;
}
}
return false;
}
QT_END_NAMESPACE_XLSX

169
src/QXlsx/xlsxrelationships.cpp

@ -0,0 +1,169 @@
// xlsxrelationships.cpp
#include <QtGlobal>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QBuffer>
#include "xlsxrelationships_p.h"
QT_BEGIN_NAMESPACE_XLSX
const QLatin1String schema_doc("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
const QLatin1String schema_msPackage("http://schemas.microsoft.com/office/2006/relationships");
const QLatin1String schema_package("http://schemas.openxmlformats.org/package/2006/relationships");
//const QString schema_worksheet = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
Relationships::Relationships()
{
}
QList<XlsxRelationship> Relationships::documentRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addDocumentRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_doc + relativeType, target);
}
QList<XlsxRelationship> Relationships::msPackageRelationships(const QString &relativeType) const
{
return relationships(schema_msPackage + relativeType);
}
void Relationships::addMsPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_msPackage + relativeType, target);
}
QList<XlsxRelationship> Relationships::packageRelationships(const QString &relativeType) const
{
return relationships(schema_package + relativeType);
}
void Relationships::addPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_package + relativeType, target);
}
QList<XlsxRelationship> Relationships::worksheetRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addWorksheetRelationship(const QString &relativeType, const QString &target, const QString &targetMode)
{
addRelationship(schema_doc + relativeType, target, targetMode);
}
QList<XlsxRelationship> Relationships::relationships(const QString &type) const
{
QList<XlsxRelationship> res;
for (const XlsxRelationship &ship : m_relationships) {
if (ship.type == type)
res.append(ship);
}
return res;
}
void Relationships::addRelationship(const QString &type, const QString &target, const QString &targetMode)
{
XlsxRelationship relation;
relation.id = QStringLiteral("rId%1").arg(m_relationships.size()+1);
relation.type = type;
relation.target = target;
relation.targetMode = targetMode;
m_relationships.append(relation);
}
void Relationships::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Relationships"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships"));
for (const XlsxRelationship &relation : m_relationships) {
writer.writeStartElement(QStringLiteral("Relationship"));
writer.writeAttribute(QStringLiteral("Id"), relation.id);
writer.writeAttribute(QStringLiteral("Type"), relation.type);
writer.writeAttribute(QStringLiteral("Target"), relation.target);
if (!relation.targetMode.isNull())
writer.writeAttribute(QStringLiteral("TargetMode"), relation.targetMode);
writer.writeEndElement();
}
writer.writeEndElement();//Relationships
writer.writeEndDocument();
}
QByteArray Relationships::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool Relationships::loadFromXmlFile(QIODevice *device)
{
clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QStringLiteral("Relationship")) {
QXmlStreamAttributes attributes = reader.attributes();
XlsxRelationship relationship;
relationship.id = attributes.value(QLatin1String("Id")).toString();
relationship.type = attributes.value(QLatin1String("Type")).toString();
relationship.target = attributes.value(QLatin1String("Target")).toString();
relationship.targetMode = attributes.value(QLatin1String("TargetMode")).toString();
m_relationships.append(relationship);
}
}
if (reader.hasError())
return false;
}
return true;
}
bool Relationships::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
XlsxRelationship Relationships::getRelationshipById(const QString &id) const
{
for (const XlsxRelationship &ship : m_relationships) {
if (ship.id == id)
return ship;
}
return XlsxRelationship();
}
void Relationships::clear()
{
m_relationships.clear();
}
int Relationships::count() const
{
return m_relationships.count();
}
bool Relationships::isEmpty() const
{
return m_relationships.isEmpty();
}
QT_END_NAMESPACE_XLSX

329
src/QXlsx/xlsxrichstring.cpp

@ -0,0 +1,329 @@
// xlsxrichstring.cpp
#include <QtGlobal>
#include <QDebug>
#include <QTextDocument>
#include <QTextFragment>
#include "xlsxrichstring.h"
#include "xlsxrichstring_p.h"
#include "xlsxformat_p.h"
QT_BEGIN_NAMESPACE_XLSX
RichStringPrivate::RichStringPrivate()
:_dirty(true)
{
}
RichStringPrivate::RichStringPrivate(const RichStringPrivate &other)
:QSharedData(other), fragmentTexts(other.fragmentTexts)
,fragmentFormats(other.fragmentFormats)
, _idKey(other.idKey()), _dirty(other._dirty)
{
}
RichStringPrivate::~RichStringPrivate()
{
}
/*!
\class RichString
\inmodule QtXlsx
\brief This class add support for the rich text string of the cell.
*/
/*!
Constructs a null string.
*/
RichString::RichString()
:d(new RichStringPrivate)
{
}
/*!
Constructs a plain string with the given \a text.
*/
RichString::RichString(const QString& text)
:d(new RichStringPrivate)
{
addFragment(text, Format());
}
/*!
Constructs a copy of \a other.
*/
RichString::RichString(const RichString &other)
:d(other.d)
{
}
/*!
Destructs the string.
*/
RichString::~RichString()
{
}
/*!
Assigns \a other to this string and returns a reference to this string
*/
RichString &RichString::operator =(const RichString &other)
{
this->d = other.d;
return *this;
}
/*!
Returns the rich string as a QVariant
*/
RichString::operator QVariant() const
{
const auto& cref
#if QT_VERSION >= 0x060000 // Qt 6.0 or over
= QMetaType::fromType<RichString>();
#else
= qMetaTypeId<RichString>() ;
#endif
return QVariant(cref, this);
}
/*!
Returns true if this is rich text string.
*/
bool RichString::isRichString() const
{
if (fragmentCount() > 1) //Is this enough??
return true;
return false;
}
/*!
Returns true is this is an Null string.
*/
bool RichString::isNull() const
{
return d->fragmentTexts.size() == 0;
}
/*!
Returns true is this is an empty string.
*/
bool RichString::isEmtpy() const
{
for (const auto& str : d->fragmentTexts) {
if (!str.isEmpty())
return false;
}
return true;
}
/*!
Converts to plain text string.
*/
QString RichString::toPlainString() const
{
if (isEmtpy())
return QString();
if (d->fragmentTexts.size() == 1)
return d->fragmentTexts[0];
return d->fragmentTexts.join(QString());
}
/*!
Converts to html string
*/
QString RichString::toHtml() const
{
//: Todo
return QString();
}
/*!
Replaces the entire contents of the document
with the given HTML-formatted text in the \a text string
*/
void RichString::setHtml(const QString &text)
{
QTextDocument doc;
doc.setHtml(text);
QTextBlock block = doc.firstBlock();
QTextBlock::iterator it;
for (it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment textFragment = it.fragment();
if (textFragment.isValid()) {
Format fmt;
fmt.setFont(textFragment.charFormat().font());
fmt.setFontColor(textFragment.charFormat().foreground().color());
addFragment(textFragment.text(), fmt);
}
}
}
/*!
Returns fragment count.
*/
int RichString::fragmentCount() const
{
return d->fragmentTexts.size();
}
/*!
Appends a fragment with the given \a text and \a format.
*/
void RichString::addFragment(const QString &text, const Format &format)
{
d->fragmentTexts.append(text);
d->fragmentFormats.append(format);
d->_dirty = true;
}
/*!
Returns fragment text at the position \a index.
*/
QString RichString::fragmentText(int index) const
{
if (index < 0 || index >= fragmentCount())
return QString();
return d->fragmentTexts[index];
}
/*!
Returns fragment format at the position \a index.
*/
Format RichString::fragmentFormat(int index) const
{
if (index < 0 || index >= fragmentCount())
return Format();
return d->fragmentFormats[index];
}
/*!
* \internal
*/
QByteArray RichStringPrivate::idKey() const
{
if (_dirty) {
RichStringPrivate *rs = const_cast<RichStringPrivate *>(this);
QByteArray bytes;
if (fragmentTexts.size() == 1) {
bytes = fragmentTexts[0].toUtf8();
} else {
//Generate a hash value base on QByteArray ?
bytes.append("@@QtXlsxRichString=");
for (int i=0; i<fragmentTexts.size(); ++i) {
bytes.append("@Text");
bytes.append(fragmentTexts[i].toUtf8());
bytes.append("@Format");
if (fragmentFormats[i].hasFontData())
bytes.append(fragmentFormats[i].fontKey());
}
}
rs->_idKey = bytes;
rs->_dirty = false;
}
return _idKey;
}
/*!
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator==(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return false;
return rs1.d->idKey() == rs2.d->idKey();
}
/*!
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator!=(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return true;
return rs1.d->idKey() != rs2.d->idKey();
}
/*!
* \internal
*/
bool operator<(const RichString &rs1, const RichString &rs2)
{
return rs1.d->idKey() < rs2.d->idKey();
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return true;
return false;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return false;
return true;
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const QString &rs1, const RichString &rs2)
{
return rs2 == rs1;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const QString &rs1, const RichString &rs2)
{
return rs2 != rs1;
}
uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
{
return qHash(rs.d->idKey(), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const RichString &rs)
{
dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")";
return dbg.space();
}
#endif
QT_END_NAMESPACE_XLSX

382
src/QXlsx/xlsxsharedstrings.cpp

@ -0,0 +1,382 @@
// xlsxsharedstrings.cpp
#include <QtGlobal>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QBuffer>
#include "xlsxrichstring.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxutility_p.h"
#include "xlsxformat_p.h"
#include "xlsxcolor_p.h"
QT_BEGIN_NAMESPACE_XLSX
/*
* Note that, when we open an existing .xlsx file (broken file?),
* duplicated string items may exist in the shared string table.
*
* In such case, the size of stringList will larger than stringTable.
* Duplicated items can be removed once we loaded all the worksheets.
*/
SharedStrings::SharedStrings(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_stringCount = 0;
}
int SharedStrings::count() const
{
return m_stringCount;
}
bool SharedStrings::isEmpty() const
{
return m_stringList.isEmpty();
}
int SharedStrings::addSharedString(const QString &string)
{
return addSharedString(RichString(string));
}
int SharedStrings::addSharedString(const RichString &string)
{
m_stringCount += 1;
auto it = m_stringTable.find(string);
if (it != m_stringTable.end()) {
it->count += 1;
return it->index;
}
int index = m_stringList.size();
m_stringTable[string] = XlsxSharedStringInfo(index);
m_stringList.append(string);
return index;
}
void SharedStrings::incRefByStringIndex(int idx)
{
if (idx <0 || idx >= m_stringList.size()) {
qDebug("SharedStrings: invlid index");
return;
}
addSharedString(m_stringList[idx]);
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const QString &string)
{
removeSharedString(RichString(string));
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const RichString &string)
{
auto it = m_stringTable.find(string);
if (it == m_stringTable.end())
return;
m_stringCount -= 1;
it->count -= 1;
if (it->count <= 0) {
for (int i=it->index+1; i<m_stringList.size(); ++i)
m_stringTable[m_stringList[i]].index -= 1;
m_stringList.removeAt(it->index);
m_stringTable.remove(string);
}
}
int SharedStrings::getSharedStringIndex(const QString &string) const
{
return getSharedStringIndex(RichString(string));
}
int SharedStrings::getSharedStringIndex(const RichString &string) const
{
auto it = m_stringTable.constFind(string);
if (it != m_stringTable.constEnd())
return it->index;
return -1;
}
RichString SharedStrings::getSharedString(int index) const
{
if (index < m_stringList.count() && index >= 0)
return m_stringList[index];
return RichString();
}
QList<RichString> SharedStrings::getSharedStrings() const
{
return m_stringList;
}
void SharedStrings::writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const
{
if (!format.hasFontData())
return;
if (format.fontBold())
writer.writeEmptyElement(QStringLiteral("b"));
if (format.fontItalic())
writer.writeEmptyElement(QStringLiteral("i"));
if (format.fontStrikeOut())
writer.writeEmptyElement(QStringLiteral("strike"));
if (format.fontOutline())
writer.writeEmptyElement(QStringLiteral("outline"));
if (format.boolProperty(FormatPrivate::P_Font_Shadow))
writer.writeEmptyElement(QStringLiteral("shadow"));
if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
Format::FontUnderline u = format.fontUnderline();
if (u != Format::FontUnderlineNone) {
writer.writeEmptyElement(QStringLiteral("u"));
if (u== Format::FontUnderlineDouble)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
else if (u == Format::FontUnderlineSingleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
else if (u == Format::FontUnderlineDoubleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Script)) {
Format::FontScript s = format.fontScript();
if (s != Format::FontScriptNormal) {
writer.writeEmptyElement(QStringLiteral("vertAlign"));
if (s == Format::FontScriptSuper)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
else
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Size)) {
writer.writeEmptyElement(QStringLiteral("sz"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
}
if (format.hasProperty(FormatPrivate::P_Font_Color)) {
XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
color.saveToXml(writer);
}
if (!format.fontName().isEmpty()) {
writer.writeEmptyElement(QStringLiteral("rFont"));
writer.writeAttribute(QStringLiteral("val"), format.fontName());
}
if (format.hasProperty(FormatPrivate::P_Font_Family)) {
writer.writeEmptyElement(QStringLiteral("family"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
}
if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
writer.writeEmptyElement(QStringLiteral("scheme"));
writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
}
}
void SharedStrings::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
if (m_stringList.size() != m_stringTable.size()) {
//Duplicated string items exist in m_stringList
//Clean up can not be done here, as the indices
//have been used when we save the worksheets part.
}
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("sst"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringList.size()));
for (const RichString &string : m_stringList) {
writer.writeStartElement(QStringLiteral("si"));
if (string.isRichString()) {
//Rich text string
for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("r"));
if (string.fragmentFormat(i).hasFontData()) {
writer.writeStartElement(QStringLiteral("rPr"));
writeRichStringPart_rPr(writer, string.fragmentFormat(i));
writer.writeEndElement();// rPr
}
writer.writeStartElement(QStringLiteral("t"));
if (isSpaceReserveNeeded(string.fragmentText(i)))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t
writer.writeEndElement(); //r
}
} else {
writer.writeStartElement(QStringLiteral("t"));
QString pString = string.toPlainString();
if (isSpaceReserveNeeded(pString))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(pString);
writer.writeEndElement();//t
}
writer.writeEndElement();//si
}
writer.writeEndElement(); //sst
writer.writeEndDocument();
}
void SharedStrings::readString(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("si"));
RichString richString;
while (!reader.atEnd() && !(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("r"))
readRichStringPart(reader, richString);
else if (reader.name() == QLatin1String("t"))
readPlainStringPart(reader, richString);
}
}
int idx = m_stringList.size();
m_stringTable[richString] = XlsxSharedStringInfo(idx, 0);
m_stringList.append(richString);
}
void SharedStrings::readRichStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("r"));
QString text;
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("rPr")) {
format = readRichStringPart_rPr(reader);
} else if (reader.name() == QLatin1String("t")) {
text = reader.readElementText();
}
}
}
richString.addFragment(text, format);
}
void SharedStrings::readPlainStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("t"));
//QXmlStreamAttributes attributes = reader.attributes();
// NOTICE: CHECK POINT
QString text = reader.readElementText();
richString.addFragment(text, Format());
}
Format SharedStrings::readRichStringPart_rPr(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("rPr"));
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QXmlStreamAttributes attributes = reader.attributes();
if (reader.name() == QLatin1String("rFont")) {
format.setFontName(attributes.value(QLatin1String("val")).toString());
} else if (reader.name() == QLatin1String("charset")) {
format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toInt());
} else if (reader.name() == QLatin1String("family")) {
format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toInt());
} else if (reader.name() == QLatin1String("b")) {
format.setFontBold(true);
} else if (reader.name() == QLatin1String("i")) {
format.setFontItalic(true);
} else if (reader.name() == QLatin1String("strike")) {
format.setFontStrikeOut(true);
} else if (reader.name() == QLatin1String("outline")) {
format.setFontOutline(true);
} else if (reader.name() == QLatin1String("shadow")) {
format.setProperty(FormatPrivate::P_Font_Shadow, true);
} else if (reader.name() == QLatin1String("condense")) {
format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toInt());
} else if (reader.name() == QLatin1String("extend")) {
format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toInt());
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
format.setProperty(FormatPrivate::P_Font_Color, color);
} else if (reader.name() == QLatin1String("sz")) {
format.setFontSize(attributes.value(QLatin1String("val")).toInt());
} else if (reader.name() == QLatin1String("u")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("double"))
format.setFontUnderline(Format::FontUnderlineDouble);
else if (value == QLatin1String("doubleAccounting"))
format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
else if (value == QLatin1String("singleAccounting"))
format.setFontUnderline(Format::FontUnderlineSingleAccounting);
else
format.setFontUnderline(Format::FontUnderlineSingle);
} else if (reader.name() == QLatin1String("vertAlign")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("superscript"))
format.setFontScript(Format::FontScriptSuper);
else if (value == QLatin1String("subscript"))
format.setFontScript(Format::FontScriptSub);
} else if (reader.name() == QLatin1String("scheme")) {
format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
}
}
}
return format;
}
bool SharedStrings::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
int count = 0;
bool hasUniqueCountAttr=true;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("sst")) {
QXmlStreamAttributes attributes = reader.attributes();
if ((hasUniqueCountAttr = attributes.hasAttribute(QLatin1String("uniqueCount"))))
count = attributes.value(QLatin1String("uniqueCount")).toInt();
} else if (reader.name() == QLatin1String("si")) {
readString(reader);
}
}
}
if (hasUniqueCountAttr && m_stringList.size() != count) {
qDebug("Error: Shared string count");
return false;
}
if (m_stringList.size() != m_stringTable.size()) {
//qDebug("Warning: Duplicated items exist in shared string table.");
//Nothing we can do here, as indices of the strings will be used when loading sheets.
}
return true;
}
QT_END_NAMESPACE_XLSX

37
src/QXlsx/xlsxsimpleooxmlfile.cpp

@ -0,0 +1,37 @@
// xlsxsimpleooxmlfile.cpp
#include "xlsxsimpleooxmlfile_p.h"
#include <QtGlobal>
#include <QIODevice>
QT_BEGIN_NAMESPACE_XLSX
SimpleOOXmlFile::SimpleOOXmlFile(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void SimpleOOXmlFile::saveToXmlFile(QIODevice *device) const
{
device->write(xmlData);
}
QByteArray SimpleOOXmlFile::saveToXmlData() const
{
return xmlData;
}
bool SimpleOOXmlFile::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool SimpleOOXmlFile::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
QT_END_NAMESPACE_XLSX

1409
src/QXlsx/xlsxstyles.cpp

File diff suppressed because it is too large

216
src/QXlsx/xlsxtheme.cpp

@ -0,0 +1,216 @@
// xlsxtheme.cpp
#include "xlsxtheme_p.h"
#include <QIODevice>
QT_BEGIN_NAMESPACE_XLSX
const char *defaultXmlData =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office \xe4\xb8\xbb\xe9\xa2\x98\">"
"<a:themeElements>"
"<a:clrScheme name=\"Office\">"
"<a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1>"
"<a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1>"
"<a:dk2><a:srgbClr val=\"1F497D\"/></a:dk2>"
"<a:lt2><a:srgbClr val=\"EEECE1\"/></a:lt2>"
"<a:accent1><a:srgbClr val=\"4F81BD\"/></a:accent1>"
"<a:accent2><a:srgbClr val=\"C0504D\"/></a:accent2>"
"<a:accent3><a:srgbClr val=\"9BBB59\"/></a:accent3>"
"<a:accent4><a:srgbClr val=\"8064A2\"/></a:accent4>"
"<a:accent5><a:srgbClr val=\"4BACC6\"/></a:accent5>"
"<a:accent6><a:srgbClr val=\"F79646\"/></a:accent6>"
"<a:hlink><a:srgbClr val=\"0000FF\"/></a:hlink>"
"<a:folHlink><a:srgbClr val=\"800080\"/></a:folHlink>"
"</a:clrScheme>"
"<a:fontScheme name=\"Office\">"
"<a:majorFont>"
"<a:latin typeface=\"Cambria\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Hebr\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"MoolBoran\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:majorFont>"
"<a:minorFont>"
"<a:latin typeface=\"Calibri\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Arial\"/>"
"<a:font script=\"Hebr\" typeface=\"Arial\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"DaunPenh\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Arial\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:minorFont>"
"</a:fontScheme>"
"<a:fmtScheme name=\"Office\">"
"<a:fillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"50000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"35000\"><a:schemeClr val=\"phClr\"><a:tint val=\"37000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:tint val=\"15000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"1\"/>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:shade val=\"51000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"80000\"><a:schemeClr val=\"phClr\"><a:shade val=\"93000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"94000\"/><a:satMod val=\"135000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"0\"/>"
"</a:gradFill>"
"</a:fillStyleLst>"
"<a:lnStyleLst>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"><a:shade val=\"95000\"/><a:satMod val=\"105000\"/></a:schemeClr></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"</a:lnStyleLst>"
"<a:effectStyleLst>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"38000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"<a:scene3d>"
"<a:camera prst=\"orthographicFront\"><a:rot lat=\"0\" lon=\"0\" rev=\"0\"/></a:camera>"
"<a:lightRig rig=\"threePt\" dir=\"t\"><a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/></a:lightRig>"
"</a:scene3d>"
"<a:sp3d><a:bevelT w=\"63500\" h=\"25400\"/></a:sp3d>"
"</a:effectStyle>"
"</a:effectStyleLst>"
"<a:bgFillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"40000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"40000\"><a:schemeClr val=\"phClr\"><a:tint val=\"45000\"/><a:shade val=\"99000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"20000\"/><a:satMod val=\"255000\"/></a:schemeClr></a:gs></a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/></a:path>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"80000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"30000\"/><a:satMod val=\"200000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/></a:path>"
"</a:gradFill>"
"</a:bgFillStyleLst>"
"</a:fmtScheme>"
"</a:themeElements>"
"<a:objectDefaults/>"
"<a:extraClrSchemeLst/>"
"</a:theme>"
;
Theme::Theme(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void Theme::saveToXmlFile(QIODevice *device) const
{
if (xmlData.isEmpty())
device->write(defaultXmlData);
else
device->write(xmlData);
}
QByteArray Theme::saveToXmlData() const
{
if (xmlData.isEmpty())
return defaultXmlData;
else
return xmlData;
}
bool Theme::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool Theme::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
QT_END_NAMESPACE_XLSX

291
src/QXlsx/xlsxutility.cpp

@ -0,0 +1,291 @@
// xlsxutility.cpp
#include "xlsxutility_p.h"
#include "xlsxcellreference.h"
#include <QString>
#include <QPoint>
#include <QRegularExpression>
#include <QMap>
#include <QStringList>
#include <QColor>
#include <QDateTime>
#include <QDebug>
#include <cmath>
#include <string>
QT_BEGIN_NAMESPACE_XLSX
bool parseXsdBoolean(const QString &value, bool defaultValue)
{
if (value == QLatin1String("1") || value == QLatin1String("true"))
return true;
if (value == QLatin1String("0") || value == QLatin1String("false"))
return false;
return defaultValue;
}
QStringList splitPath(const QString &path)
{
int idx = path.lastIndexOf(QLatin1Char('/'));
if (idx == -1)
return { QStringLiteral("."), path };
return { path.left(idx), path.mid(idx+1) };
}
/*
* Return the .rel file path based on filePath
*/
QString getRelFilePath(const QString &filePath)
{
QString ret;
int idx = filePath.lastIndexOf(QLatin1Char('/'));
if (idx == -1) // not found
{
// return QString();
// dev34
ret = QLatin1String("_rels/") + QStringLiteral("%0.rels").arg(filePath);
return ret;
}
ret = QString( filePath.left(idx) + QLatin1String("/_rels/") + filePath.mid(idx+1) + QLatin1String(".rels"));
return ret;
}
double datetimeToNumber(const QDateTime &dt, bool is1904)
{
//Note, for number 0, Excel2007 shown as 1900-1-0, which should be 1899-12-31
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
double excel_time = epoch.msecsTo(dt) / (1000*60*60*24.0);
if (dt.isDaylightTime()) // Add one hour if the date is Daylight
excel_time += 1.0 / 24.0;
if (!is1904 && excel_time > 59) {//31+28
//Account for Excel erroneously treating 1900 as a leap year.
excel_time += 1;
}
return excel_time;
}
double timeToNumber(const QTime &time)
{
return QTime(0,0).msecsTo(time) / (1000*60*60*24.0);
}
QVariant datetimeFromNumber(double num, bool is1904)
{
QDateTime dtRet; // return value
if (!is1904 && num > 60) // for mac os excel
{
num = num - 1;
}
qint64 msecs = static_cast<qint64>(num * 1000*60*60*24.0 + 0.5);
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
QDateTime dtOld = epoch.addMSecs(msecs);
dtRet = dtOld;
// Remove one hour to see whether the date is Daylight
QDateTime dtNew = dtRet.addMSecs( -3600000 ); // issue102
if ( dtNew.isDaylightTime() )
{
dtRet = dtNew;
}
double whole = 0;
double fractional = std::modf(num, &whole);
if ( num < double(1) )
{
// only time
QTime t = dtRet.time();
return QVariant(t);
}
if ( fractional == 0.0 )
{
// only date
QDate onlyDT = dtRet.date();
return QVariant(onlyDT);
}
return QVariant(dtRet);
}
/*
Creates a valid sheet name
minimum length is 1
maximum length is 31
doesn't contain special chars: / \ ? * ] [ :
Sheet names must not begin or end with ' (apostrophe)
Invalid characters are replaced by one space character ' '.
*/
QString createSafeSheetName(const QString &nameProposal)
{
if (nameProposal.isEmpty())
return QString();
QString ret = nameProposal;
if (nameProposal.length() > 2 && nameProposal.startsWith(QLatin1Char('\'')) && nameProposal.endsWith(QLatin1Char('\'')))
ret = unescapeSheetName(ret);
//Replace invalid chars with space.
static QRegularExpression invalidChars(QStringLiteral("[/\\\\?*\\][:]"));
if (nameProposal.contains(invalidChars)) {
static QRegularExpression validChars(QStringLiteral("[/\\\\?*\\][:]"));
ret.replace(validChars, QStringLiteral(" "));
}
if (ret.startsWith(QLatin1Char('\'')))
ret[0] = QLatin1Char(' ');
if (ret.endsWith(QLatin1Char('\'')))
ret[ret.size()-1] = QLatin1Char(' ');
if (ret.size() > 31)
ret = ret.left(31);
return ret;
}
/*
* When sheetName contains space or apostrophe, escaped is needed by cellFormula/definedName/chartSerials.
*/
QString escapeSheetName(const QString &sheetName)
{
//Already escaped.
Q_ASSERT(!sheetName.startsWith(QLatin1Char('\'')) && !sheetName.endsWith(QLatin1Char('\'')));
//These is no need to escape
static const auto escape = QRegularExpression(QStringLiteral("[ +\\-,%^=<>'&]"));
if (!sheetName.contains(escape))
return sheetName;
//OK, escape is needed.
QString name = sheetName;
name.replace(QLatin1Char('\''), QLatin1String("\'\'"));
return QLatin1Char('\'') + name + QLatin1Char('\'');
}
/*
*/
QString unescapeSheetName(const QString &sheetName)
{
Q_ASSERT(sheetName.length() > 2 && sheetName.startsWith(QLatin1Char('\'')) && sheetName.endsWith(QLatin1Char('\'')));
QString name = sheetName.mid(1, sheetName.length()-2);
name.replace(QLatin1String("\'\'"), QLatin1String("\'"));
return name;
}
/*
* whether the string s starts or ends with space
*/
bool isSpaceReserveNeeded(const QString &s)
{
QString spaces(QStringLiteral(" \t\n\r"));
return !s.isEmpty() && (spaces.contains(s.at(0))||spaces.contains(s.at(s.length()-1)));
}
/*
* Convert shared formula for non-root cells.
*
* For example, if "B1:B10" have shared formula "=A1*A1", this function will return "=A2*A2"
* for "B2" cell, "=A3*A3" for "B3" cell, etc.
*
* Note, the formula "=A1*A1" for B1 can also be written as "=RC[-1]*RC[-1]", which is the same
* for all other cells. In other words, this formula is shared.
*
* For long run, we need a formula parser.
*/
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell)
{
Q_UNUSED(rootCell)
Q_UNUSED(cell)
//Find all the "$?[A-Z]+$?[0-9]+" patterns in the rootFormula.
QVector<std::pair<QString, int> > segments;
QString segment;
bool inQuote = false;
enum RefState{INVALID, PRE_AZ, AZ, PRE_09, _09};
RefState refState = INVALID;
int refFlag = 0; // 0x00, 0x01, 0x02, 0x03 ==> A1, $A1, A$1, $A$1
for (QChar ch : rootFormula) {
if (inQuote) {
segment.append(ch);
if (ch == QLatin1Char('"'))
inQuote = false;
} else {
if (ch == QLatin1Char('"')) {
inQuote = true;
refState = INVALID;
segment.append(ch);
} else if (ch == QLatin1Char('$')) {
if (refState == AZ) {
segment.append(ch);
refState = PRE_09;
refFlag |= 0x02;
} else {
segments.append(std::make_pair(segment, refState==_09 ? refFlag : -1 ));
segment = QString(ch); //Start new segment.
refState = PRE_AZ;
refFlag = 0x01;
}
} else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) {
if (refState == PRE_AZ || refState == AZ) {
segment.append(ch);
} else {
segments.append(std::make_pair(segment, refState==_09 ? refFlag : -1 ));
segment = QString(ch); //Start new segment.
refFlag = 0x00;
}
refState = AZ;
} else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) {
segment.append(ch);
if (refState == AZ || refState == PRE_09 || refState == _09)
refState = _09;
else
refState = INVALID;
} else {
if (refState == _09) {
segments.append(std::make_pair(segment, refFlag ));
segment = QString(ch); //Start new segment.
} else {
segment.append(ch);
}
refState = INVALID;
}
}
}
if (!segment.isEmpty())
segments.append(std::make_pair(segment, refState==_09 ? refFlag : -1 ));
//Replace "A1", "$A1", "A$1" segment with proper one.
QStringList result;
for (const auto &p : segments) {
//qDebug()<<p.first<<p.second;
if (p.second != -1 && p.second != 3) {
CellReference oldRef(p.first);
int row = p.second & 0x02 ? oldRef.row() : oldRef.row()-rootCell.row()+cell.row();
int col = p.second & 0x01 ? oldRef.column() : oldRef.column()-rootCell.column()+cell.column();
result.append(CellReference(row, col).toString(p.second & 0x02, p.second & 0x01));
} else {
result.append(p.first);
}
}
//OK
return result.join(QString());
}
QT_END_NAMESPACE_XLSX

740
src/QXlsx/xlsxworkbook.cpp

@ -0,0 +1,740 @@
// xlsxworkbook.cpp
#include <QtGlobal>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QBuffer>
#include <QDir>
#include <QtDebug>
#include "xlsxworkbook.h"
#include "xlsxworkbook_p.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxworksheet.h"
#include "xlsxchartsheet.h"
#include "xlsxstyles_p.h"
#include "xlsxformat.h"
#include "xlsxworksheet_p.h"
#include "xlsxformat_p.h"
#include "xlsxmediafile_p.h"
#include "xlsxutility_p.h"
#include "xlsxchart.h"
QT_BEGIN_NAMESPACE_XLSX
WorkbookPrivate::WorkbookPrivate(Workbook *q, Workbook::CreateFlag flag) :
AbstractOOXmlFilePrivate(q, flag)
{
sharedStrings = QSharedPointer<SharedStrings> (new SharedStrings(flag));
styles = QSharedPointer<Styles>(new Styles(flag));
theme = QSharedPointer<Theme>(new Theme(flag));
x_window = 240;
y_window = 15;
window_width = 16095;
window_height = 9660;
strings_to_numbers_enabled = false;
strings_to_hyperlinks_enabled = true;
html_to_richstring_enabled = false;
date1904 = false;
defaultDateFormat = QStringLiteral("yyyy-mm-dd");
activesheetIndex = 0;
firstsheet = 0;
table_count = 0;
last_worksheet_index = 0;
last_chartsheet_index = 0;
last_sheet_id = 0;
}
Workbook::Workbook(CreateFlag flag)
: AbstractOOXmlFile(new WorkbookPrivate(this, flag))
{
}
Workbook::~Workbook()
{
}
bool Workbook::isDate1904() const
{
Q_D(const Workbook);
return d->date1904;
}
/*!
Excel for Windows uses a default epoch of 1900 and Excel
for Mac uses an epoch of 1904. However, Excel on either
platform will convert automatically between one system
and the other. Qt Xlsx stores dates in the 1900 format
by default.
\note This function should be called before any date/time
has been written.
*/
void Workbook::setDate1904(bool date1904)
{
Q_D(Workbook);
d->date1904 = date1904;
}
/*
Enable the worksheet.write() method to convert strings
to numbers, where possible, using float() in order to avoid
an Excel warning about "Numbers Stored as Text".
The default is false
*/
void Workbook::setStringsToNumbersEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_numbers_enabled = enable;
}
bool Workbook::isStringsToNumbersEnabled() const
{
Q_D(const Workbook);
return d->strings_to_numbers_enabled;
}
void Workbook::setStringsToHyperlinksEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_hyperlinks_enabled = enable;
}
bool Workbook::isStringsToHyperlinksEnabled() const
{
Q_D(const Workbook);
return d->strings_to_hyperlinks_enabled;
}
void Workbook::setHtmlToRichStringEnabled(bool enable)
{
Q_D(Workbook);
d->html_to_richstring_enabled = enable;
}
bool Workbook::isHtmlToRichStringEnabled() const
{
Q_D(const Workbook);
return d->html_to_richstring_enabled;
}
QString Workbook::defaultDateFormat() const
{
Q_D(const Workbook);
return d->defaultDateFormat;
}
void Workbook::setDefaultDateFormat(const QString &format)
{
Q_D(Workbook);
d->defaultDateFormat = format;
}
/*!
* \brief Create a defined name in the workbook.
* \param name The defined name
* \param formula The cell or range that the defined name refers to.
* \param comment
* \param scope The name of one worksheet, or empty which means golbal scope.
* \return Return false if the name invalid.
*/
bool Workbook::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope)
{
Q_D(Workbook);
//Remove the = sign from the formula if it exists.
QString formulaString = formula;
if (formulaString.startsWith(QLatin1Char('=')))
formulaString = formula.mid(1);
int id=-1;
if (!scope.isEmpty()) {
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == scope) {
id = d->sheets[i]->sheetId();
break;
}
}
}
d->definedNamesList.append(XlsxDefineNameData(name, formulaString, comment, id));
return true;
}
AbstractSheet *Workbook::addSheet(const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
return insertSheet(d->sheets.size(), name, type);
}
/*!
* \internal
*/
QStringList Workbook::worksheetNames() const
{
Q_D(const Workbook);
return d->sheetNames;
}
/*!
* \internal
* Used only when load the xlsx file!!
*/
AbstractSheet *Workbook::addSheet(const QString &name, int sheetId, AbstractSheet::SheetType type)
{
Q_D(Workbook);
if (sheetId > d->last_sheet_id)
d->last_sheet_id = sheetId;
AbstractSheet *sheet = NULL;
if (type == AbstractSheet::ST_WorkSheet)
{
// create work sheet (value sheet)
sheet = new Worksheet(name, sheetId, this, F_LoadFromExists);
}
else if (type == AbstractSheet::ST_ChartSheet)
{
// create chart sheet
sheet = new Chartsheet(name, sheetId, this, F_LoadFromExists);
}
else
{
qWarning("unsupported sheet type.");
Q_ASSERT(false);
}
d->sheets.append(QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.append(name);
return sheet;
}
AbstractSheet *Workbook::insertSheet(int index, const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
QString sheetName = createSafeSheetName(name);
if(index > d->last_sheet_id){
//User tries to insert, where no sheet has gone before.
return 0;
}
if (!sheetName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(sheetName))
return 0;
} else {
if (type == AbstractSheet::ST_WorkSheet) {
do {
++d->last_worksheet_index;
sheetName = QStringLiteral("Sheet%1").arg(d->last_worksheet_index);
} while (d->sheetNames.contains(sheetName));
} else if (type == AbstractSheet::ST_ChartSheet) {
do {
++d->last_chartsheet_index;
sheetName = QStringLiteral("Chart%1").arg(d->last_chartsheet_index);
} while (d->sheetNames.contains(sheetName));
} else {
qWarning("unsupported sheet type.");
return 0;
}
}
++d->last_sheet_id;
AbstractSheet *sheet = NULL;
if ( type == AbstractSheet::ST_WorkSheet )
{
sheet = new Worksheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
}
else if ( type == AbstractSheet::ST_ChartSheet )
{
sheet = new Chartsheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
}
else
{
qWarning("unsupported sheet type.");
Q_ASSERT(false);
}
d->sheets.insert(index, QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.insert(index, sheetName);
d->activesheetIndex = index;
return sheet;
}
/*!
* Returns current active worksheet.
*/
AbstractSheet *Workbook::activeSheet() const
{
Q_D(const Workbook);
if (d->sheets.isEmpty())
const_cast<Workbook*>(this)->addSheet();
return d->sheets[d->activesheetIndex].data();
}
bool Workbook::setActiveSheet(int index)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size()) {
//warning
return false;
}
d->activesheetIndex = index;
return true;
}
/*!
* Rename the worksheet at the \a index to \a newName.
*/
bool Workbook::renameSheet(int index, const QString &newName)
{
Q_D(Workbook);
QString name = createSafeSheetName(newName);
if (index < 0 || index >= d->sheets.size())
return false;
//If user given an already in-used name, return false
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == name)
return false;
}
d->sheets[index]->setSheetName(name);
d->sheetNames[index] = name;
return true;
}
/*!
* Remove the worksheet at pos \a index.
*/
bool Workbook::deleteSheet(int index)
{
Q_D(Workbook);
if (d->sheets.size() <= 1)
return false;
if (index < 0 || index >= d->sheets.size())
return false;
d->sheets.removeAt(index);
d->sheetNames.removeAt(index);
return true;
}
/*!
* Moves the worksheet form \a srcIndex to \a distIndex.
*/
bool Workbook::moveSheet(int srcIndex, int distIndex)
{
Q_D(Workbook);
if (srcIndex == distIndex)
return false;
if (srcIndex < 0 || srcIndex >= d->sheets.size())
return false;
QSharedPointer<AbstractSheet> sheet = d->sheets.takeAt(srcIndex);
d->sheetNames.takeAt(srcIndex);
if (distIndex >= 0 || distIndex <= d->sheets.size()) {
d->sheets.insert(distIndex, sheet);
d->sheetNames.insert(distIndex, sheet->sheetName());
} else {
d->sheets.append(sheet);
d->sheetNames.append(sheet->sheetName());
}
return true;
}
bool Workbook::copySheet(int index, const QString &newName)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size())
return false;
QString worksheetName = createSafeSheetName(newName);
if (!newName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(newName))
return false;
} else {
int copy_index = 1;
do {
++copy_index;
worksheetName = QStringLiteral("%1(%2)").arg(d->sheets[index]->sheetName()).arg(copy_index);
} while (d->sheetNames.contains(worksheetName));
}
++d->last_sheet_id;
AbstractSheet *sheet = d->sheets[index]->copy(worksheetName, d->last_sheet_id);
d->sheets.append(QSharedPointer<AbstractSheet> (sheet));
d->sheetNames.append(sheet->sheetName());
return true; // #162
}
/*!
* Returns count of worksheets.
*/
int Workbook::sheetCount() const
{
Q_D(const Workbook);
return d->sheets.count();
}
/*!
* Returns the sheet object at index \a sheetIndex.
*/
AbstractSheet *Workbook::sheet(int index) const
{
Q_D(const Workbook);
if (index < 0 || index >= d->sheets.size())
return 0;
return d->sheets.at(index).data();
}
SharedStrings *Workbook::sharedStrings() const
{
Q_D(const Workbook);
return d->sharedStrings.data();
}
Styles *Workbook::styles()
{
Q_D(Workbook);
return d->styles.data();
}
Theme *Workbook::theme()
{
Q_D(Workbook);
return d->theme.data();
}
/*!
* \internal
*
* Unlike media files, drawing file is a property of the sheet.
*/
QList<Drawing *> Workbook::drawings()
{
Q_D(Workbook);
QList<Drawing *> ds;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
if (sheet->drawing())
ds.append(sheet->drawing());
}
return ds;
}
/*!
* \internal
*/
QList<QSharedPointer<AbstractSheet> > Workbook::getSheetsByTypes(AbstractSheet::SheetType type) const
{
Q_D(const Workbook);
QList<QSharedPointer<AbstractSheet> > list;
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetType() == type)
list.append(d->sheets[i]);
}
return list;
}
void Workbook::saveToXmlFile(QIODevice *device) const
{
Q_D(const Workbook);
d->relationships->clear();
if (d->sheets.isEmpty())
const_cast<Workbook *>(this)->addSheet();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("workbook"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeEmptyElement(QStringLiteral("fileVersion"));
writer.writeAttribute(QStringLiteral("appName"), QStringLiteral("xl"));
writer.writeAttribute(QStringLiteral("lastEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("lowestEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("rupBuild"), QStringLiteral("4505"));
// writer.writeAttribute(QStringLiteral("codeName"), QStringLiteral("{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}"));
writer.writeEmptyElement(QStringLiteral("workbookPr"));
if (d->date1904)
writer.writeAttribute(QStringLiteral("date1904"), QStringLiteral("1"));
writer.writeAttribute(QStringLiteral("defaultThemeVersion"), QStringLiteral("124226"));
writer.writeStartElement(QStringLiteral("bookViews"));
writer.writeEmptyElement(QStringLiteral("workbookView"));
writer.writeAttribute(QStringLiteral("xWindow"), QString::number(d->x_window));
writer.writeAttribute(QStringLiteral("yWindow"), QString::number(d->y_window));
writer.writeAttribute(QStringLiteral("windowWidth"), QString::number(d->window_width));
writer.writeAttribute(QStringLiteral("windowHeight"), QString::number(d->window_height));
//Store the firstSheet when it isn't the default
//For example, when "the first sheet 0 is hidden", the first sheet will be 1
if (d->firstsheet > 0)
writer.writeAttribute(QStringLiteral("firstSheet"), QString::number(d->firstsheet + 1));
//Store the activeTab when it isn't the first sheet
if (d->activesheetIndex > 0)
writer.writeAttribute(QStringLiteral("activeTab"), QString::number(d->activesheetIndex));
writer.writeEndElement();//bookViews
writer.writeStartElement(QStringLiteral("sheets"));
int worksheetIndex = 0;
int chartsheetIndex = 0;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
writer.writeEmptyElement(QStringLiteral("sheet"));
writer.writeAttribute(QStringLiteral("name"), sheet->sheetName());
writer.writeAttribute(QStringLiteral("sheetId"), QString::number(sheet->sheetId()));
if (sheet->sheetState() == AbstractSheet::SS_Hidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("hidden"));
else if (sheet->sheetState() == AbstractSheet::SS_VeryHidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("veryHidden"));
if (sheet->sheetType() == AbstractSheet::ST_WorkSheet)
d->relationships->addDocumentRelationship(QStringLiteral("/worksheet"), QStringLiteral("worksheets/sheet%1.xml").arg(++worksheetIndex));
else
d->relationships->addDocumentRelationship(QStringLiteral("/chartsheet"), QStringLiteral("chartsheets/sheet%1.xml").arg(++chartsheetIndex));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//sheets
if (d->externalLinks.size() > 0) {
writer.writeStartElement(QStringLiteral("externalReferences"));
for (int i=0; i<d->externalLinks.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("externalReference"));
d->relationships->addDocumentRelationship(QStringLiteral("/externalLink"), QStringLiteral("externalLinks/externalLink%1.xml").arg(i+1));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//externalReferences
}
if (!d->definedNamesList.isEmpty()) {
writer.writeStartElement(QStringLiteral("definedNames"));
for (const XlsxDefineNameData &data : d->definedNamesList) {
writer.writeStartElement(QStringLiteral("definedName"));
writer.writeAttribute(QStringLiteral("name"), data.name);
if (!data.comment.isEmpty())
writer.writeAttribute(QStringLiteral("comment"), data.comment);
if (data.sheetId != -1) {
//find the local index of the sheet.
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetId() == data.sheetId) {
writer.writeAttribute(QStringLiteral("localSheetId"), QString::number(i));
break;
}
}
}
writer.writeCharacters(data.formula);
writer.writeEndElement();//definedName
}
writer.writeEndElement();//definedNames
}
writer.writeStartElement(QStringLiteral("calcPr"));
writer.writeAttribute(QStringLiteral("calcId"), QStringLiteral("124519"));
writer.writeEndElement(); //calcPr
writer.writeEndElement();//workbook
writer.writeEndDocument();
d->relationships->addDocumentRelationship(QStringLiteral("/theme"), QStringLiteral("theme/theme1.xml"));
d->relationships->addDocumentRelationship(QStringLiteral("/styles"), QStringLiteral("styles.xml"));
if (!sharedStrings()->isEmpty())
d->relationships->addDocumentRelationship(QStringLiteral("/sharedStrings"), QStringLiteral("sharedStrings.xml"));
}
bool Workbook::loadFromXmlFile(QIODevice *device)
{
Q_D(Workbook);
QXmlStreamReader reader(device);
while (!reader.atEnd())
{
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement)
{
if (reader.name() == QLatin1String("sheet"))
{
QXmlStreamAttributes attributes = reader.attributes();
const auto& name = attributes.value(QLatin1String("name")).toString();
int sheetId = attributes.value(QLatin1String("sheetId")).toInt();
const auto& rId = attributes.value(QLatin1String("r:id")).toString();
const auto& stateString = attributes.value(QLatin1String("state"));
AbstractSheet::SheetState state = AbstractSheet::SS_Visible;
if (stateString == QLatin1String("hidden"))
state = AbstractSheet::SS_Hidden;
else if (stateString == QLatin1String("veryHidden"))
state = AbstractSheet::SS_VeryHidden;
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet;
if (relationship.type.endsWith(QLatin1String("/worksheet")))
{
type = AbstractSheet::ST_WorkSheet;
}
else if (relationship.type.endsWith(QLatin1String("/chartsheet")))
{
type = AbstractSheet::ST_ChartSheet;
}
else if (relationship.type.endsWith(QLatin1String("/dialogsheet")))
{
type = AbstractSheet::ST_DialogSheet;
}
else if (relationship.type.endsWith(QLatin1String("/xlMacrosheet")))
{
type = AbstractSheet::ST_MacroSheet;
}
else
{
qWarning() << "unknown sheet type : " << relationship.type ;
}
AbstractSheet *sheet = addSheet(name, sheetId, type);
sheet->setSheetState(state);
QString strFilePath = filePath();
// const QString fullPath = QDir::cleanPath(splitPath(strFilePath).constFirst() + QLatin1String("/") + relationship.target);
const auto parts = splitPath(strFilePath);
QString fullPath = QDir::cleanPath(parts.first() + QLatin1String("/") + relationship.target);
sheet->setFilePath(fullPath);
}
else if (reader.name() == QLatin1String("workbookPr"))
{
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("date1904")))
d->date1904 = true;
}
else if (reader.name() == QLatin1String("bookviews"))
{
while (!(reader.name() == QLatin1String("bookviews") &&
reader.tokenType() == QXmlStreamReader::EndElement))
{
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement)
{
if (reader.name() == QLatin1String("workbookView"))
{
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("xWindow")))
d->x_window = attrs.value(QLatin1String("xWindow")).toInt();
if (attrs.hasAttribute(QLatin1String("yWindow")))
d->y_window = attrs.value(QLatin1String("yWindow")).toInt();
if (attrs.hasAttribute(QLatin1String("windowWidth")))
d->window_width = attrs.value(QLatin1String("windowWidth")).toInt();
if (attrs.hasAttribute(QLatin1String("windowHeight")))
d->window_height = attrs.value(QLatin1String("windowHeight")).toInt();
if (attrs.hasAttribute(QLatin1String("firstSheet")))
d->firstsheet = attrs.value(QLatin1String("firstSheet")).toInt();
if (attrs.hasAttribute(QLatin1String("activeTab")))
d->activesheetIndex = attrs.value(QLatin1String("activeTab")).toInt();
}
}
}
}
else if (reader.name() == QLatin1String("externalReference"))
{
QXmlStreamAttributes attributes = reader.attributes();
const QString rId = attributes.value(QLatin1String("r:id")).toString();
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
QSharedPointer<SimpleOOXmlFile> link(new SimpleOOXmlFile(F_LoadFromExists));
const auto parts = splitPath(filePath());
QString fullPath = QDir::cleanPath(parts.first() + QLatin1String("/") + relationship.target);
link->setFilePath(fullPath);
d->externalLinks.append(link);
} else if (reader.name() == QLatin1String("definedName")) {
QXmlStreamAttributes attrs = reader.attributes();
XlsxDefineNameData data;
data.name = attrs.value(QLatin1String("name")).toString();
if (attrs.hasAttribute(QLatin1String("comment")))
data.comment = attrs.value(QLatin1String("comment")).toString();
if (attrs.hasAttribute(QLatin1String("localSheetId"))) {
int localId = attrs.value(QLatin1String("localSheetId")).toInt();
int sheetId = d->sheets.at(localId)->sheetId();
data.sheetId = sheetId;
}
data.formula = reader.readElementText();
d->definedNamesList.append(data);
}
}
}
return true;
}
/*!
* \internal
*/
QList<std::shared_ptr<MediaFile> > Workbook::mediaFiles() const
{
Q_D(const Workbook);
return d->mediaFiles;
}
/*!
* \internal
*/
void Workbook::addMediaFile(std::shared_ptr<MediaFile> media, bool force)
{
Q_D(Workbook);
if (!force)
{
for (int i=0; i<d->mediaFiles.size(); ++i)
{
if (d->mediaFiles[i]->hashKey() == media->hashKey())
{
media->setIndex(i);
return;
}
}
}
media->setIndex(d->mediaFiles.size());
d->mediaFiles.append(media);
}
/*!
* \internal
*/
QList<QSharedPointer<Chart> > Workbook::chartFiles() const
{
Q_D(const Workbook);
return d->chartFiles;
}
/*!
* \internal
*/
void Workbook::addChartFile(QSharedPointer<Chart> chart)
{
Q_D(Workbook);
if (!d->chartFiles.contains(chart))
d->chartFiles.append(chart);
}
QT_END_NAMESPACE_XLSX

3083
src/QXlsx/xlsxworksheet.cpp

File diff suppressed because it is too large

50
src/QXlsx/xlsxzipreader.cpp

@ -0,0 +1,50 @@
// xlsxzipreader.cpp
#include "xlsxzipreader_p.h"
#include <private/qzipreader_p.h>
QT_BEGIN_NAMESPACE_XLSX
ZipReader::ZipReader(const QString &filePath) :
m_reader(new QZipReader(filePath))
{
init();
}
ZipReader::ZipReader(QIODevice *device) :
m_reader(new QZipReader(device))
{
init();
}
ZipReader::~ZipReader()
{
}
void ZipReader::init()
{
const auto& allFiles = m_reader->fileInfoList();
for (const auto &fi : allFiles) {
if (fi.isFile || (!fi.isDir && !fi.isFile && !fi.isSymLink))
m_filePaths.append(fi.filePath);
}
}
bool ZipReader::exists() const
{
return m_reader->exists();
}
QStringList ZipReader::filePaths() const
{
return m_filePaths;
}
QByteArray ZipReader::fileData(const QString &fileName) const
{
return m_reader->fileData(fileName);
}
QT_END_NAMESPACE_XLSX

48
src/QXlsx/xlsxzipwriter.cpp

@ -0,0 +1,48 @@
// xlsxzipwriter.cpp
#include "xlsxzipwriter_p.h"
#include <QtGlobal>
#include <QDebug>
#include <private/qzipwriter_p.h>
QT_BEGIN_NAMESPACE_XLSX
ZipWriter::ZipWriter(const QString &filePath)
{
m_writer = new QZipWriter(filePath, QIODevice::WriteOnly);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::ZipWriter(QIODevice *device)
{
m_writer = new QZipWriter(device);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::~ZipWriter()
{
delete m_writer;
}
bool ZipWriter::error() const
{
return m_writer->status() != QZipWriter::NoError;
}
void ZipWriter::addFile(const QString &filePath, QIODevice *device)
{
m_writer->addFile(filePath, device);
}
void ZipWriter::addFile(const QString &filePath, const QByteArray &data)
{
m_writer->addFile(filePath, data);
}
void ZipWriter::close()
{
m_writer->close();
}
QT_END_NAMESPACE_XLSX

61
src/XlsxReader.cpp

@ -0,0 +1,61 @@
#include "include/XlsxReader.h"
#include "include/QXlsx/xlsxdocument.h"
#include "include/QXlsx/xlsxcellrange.h"
#include "include/QXlsx/xlsxrichstring.h"
#include "include/QXlsx/xlsxworkbook.h"
#include "include/QXlsx/xlsxcellrange.h"
using namespace QXlsx;
XlsxReader::XlsxReader()
{
}
QList<QStringList> XlsxReader::ReadeXlsx(QString pathOfXlsx)
{
QList<QStringList> cellValues;
auto sheetCounter = 0;
QXlsx::Document xlsxDoc(pathOfXlsx);
//QXlsx::Document xlsxDoc("Test.xlsx");
int sheetIndexNumber = 0;
foreach(QString currentSheetName, xlsxDoc.sheetNames())
{
sheetCounter++;
//get current sheet
AbstractSheet* currentSheet = xlsxDoc.sheet(currentSheetName);
if(NULL == currentSheet)
{
continue;
}
//get full cells of current sheet
int maxRow = -1;
int maxCol = -1;
currentSheet->workbook()->setActiveSheet(sheetIndexNumber);
Worksheet* wsheet = (Worksheet*)currentSheet->workbook()->activeSheet();
if(NULL == wsheet)
{
continue;
}
QString strSheetName = wsheet->sheetName(); //sheet name
QVector<CellLocation> clList = wsheet->getFullCells(&maxRow, &maxCol);
//to do QList<QStringList> cellValues;
for(int rc = 1; rc <= maxRow; rc++)
{
QStringList tempValue = {};
for(int cc = 1; cc <= maxCol; cc++)
{
QVariant var = xlsxDoc.read(rc, cc);
tempValue.append(var.toString());
}
cellValues.append(tempValue);
}
//generateXML(cellValues, sheetCounter, fieldNames);
sheetIndexNumber++;
}
return cellValues;
}

38
src/XlsxXmlConverter.cpp

@ -0,0 +1,38 @@
#include "include/XlsxXmlConverter.h"
#include "include/XlsxReader.h"
#include "include/XmlTemplateReader.h"
#include "include/XmlGenerator.h"
XlsxXmlConverter::XlsxXmlConverter()
{
}
/*************************************************************************************************/
void XlsxXmlConverter::initPath(QString xlsxPath, QString patternFilePath, QString outputFilePath)
{
xlsxFilePath = xlsxPath;
xmlPatternFilePath = patternFilePath;
xmlOutPutFilePath = outputFilePath;
}
/*************************************************************************************************/
void XlsxXmlConverter::readXlsx()
{
XlsxReader xlsReader;
xlsxData = xlsReader.ReadeXlsx(xlsxFilePath);
}
/*************************************************************************************************/
void XlsxXmlConverter::readPattern()
{
XmlTemplateReader readPattern;
patternList = readPattern.readxmlPattern(xmlPatternFilePath);
}
/*************************************************************************************************/
void XlsxXmlConverter::wrtiteXMl()
{
XmlGenerator generatorXml;
qint16 sheetCounter = 1;
generatorXml.generateXML(xlsxData, sheetCounter, patternList, xmlOutPutFilePath);
}

44
src/XmlGenerator.cpp

@ -0,0 +1,44 @@
#include "include/XmlGenerator.h"
#include <QtXml>
#include <QTextStream>
XmlGenerator::XmlGenerator()
{
}
/*************************************************************************************************/
void XmlGenerator::generateXML(QList<QStringList> inputList,
qint16 sheetCounter,
QList<QString> patternList,
QString outputPath)
{
QFile xmlFile("xmlSample" + QString::number(sheetCounter) + ".xml");
if(!xmlFile.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "Already opened or there is another issue";
xmlFile.close();
}
QXmlStreamWriter xmlWriter(&xmlFile);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement(patternList[0]);
xmlWriter.writeAttribute("name", patternList[1]);
for(int rc = 1; rc < inputList.count(); rc++)
{
xmlWriter.writeStartElement(patternList[2]);
for(int cc = 0; cc < inputList.at(0).count(); cc++)
{
if(patternList.contains(inputList.at(0).at(cc)))
{
xmlWriter.writeStartElement(patternList[3]);
xmlWriter.writeAttribute("name", inputList.at(0).at(cc));
xmlWriter.writeAttribute("value", inputList.at(rc).at(cc));
xmlWriter.writeEndElement();
}
}
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
xmlFile.close();
}

71
src/XmlTemplateReader.cpp

@ -0,0 +1,71 @@
#include "include/XmlTemplateReader.h"
#include <QtXml>
#include <QTextStream>
XmlTemplateReader::XmlTemplateReader()
{
}
/*************************************************************************************************/
QList<QString> XmlTemplateReader::readxmlPattern(QString pathOfPattern)
{
QList<QString> fieldNamelist;
//------------------------------------------
/* Open the file for reading by using the path specified in lineEditWrite */
QFile xmlPatternFile(pathOfPattern);
//The QDomDocument class represents an XML document.
if(!xmlPatternFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Already opened or there is another issue";
xmlPatternFile.close();
}
else
{
QDomDocument xmlPattern;
xmlPattern.setContent(&xmlPatternFile);
xmlPatternFile.close();
//_________________________
//::: Read the root tag :::
QDomElement root = xmlPattern.documentElement();
//Get root names and attributes
QString rootName = root.tagName();
auto rootAttValue = root.attributes().item(0).nodeValue();
//::: Read data :::
//Get the first child of the root (Markup COMPONENT is expected)
QDomElement entity = root.firstChild().toElement();
auto entityName = entity.tagName();
QDomElement field = entity.firstChild().toElement();
auto fieldName = field.tagName();
fieldNamelist.append(rootName);
fieldNamelist.append(rootAttValue);
fieldNamelist.append(entityName);
fieldNamelist.append(fieldName);
//Loop while there is a child
while(!entity.isNull())
{
//Get the first child of the component
field = entity.firstChild().toElement();
//Read each child of the component node
while(!field.isNull())
{
auto secondattName = field.attributes().item(0).nodeName();
auto secondattValue = field.attributes().item(0).nodeValue();
fieldNamelist.append(secondattValue);
//Next child
field = field.nextSibling().toElement();
}
entity = entity.nextSibling().toElement();
}
}
return fieldNamelist;
}
Loading…
Cancel
Save