Add custom number format support
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
#include <QtGui>
|
||||||
|
#include "xlsxdocument.h"
|
||||||
|
#include "xlsxformat.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
QGuiApplication(argc, argv);
|
||||||
|
|
||||||
|
QXlsx::Document xlsx;
|
||||||
|
xlsx.setColumn(0, 4, 20.0);
|
||||||
|
|
||||||
|
QXlsx::Format *header = xlsx.createFormat();
|
||||||
|
header->setFontBold(true);
|
||||||
|
header->setFontSize(20);
|
||||||
|
|
||||||
|
//Custom number formats
|
||||||
|
QStringList numFormats;
|
||||||
|
numFormats<<"Qt #"
|
||||||
|
<<"yyyy-mmm-dd"
|
||||||
|
<<"$ #,##0.00"
|
||||||
|
<<"[red]0.00";
|
||||||
|
xlsx.write(0, 0, "Raw data", header);
|
||||||
|
xlsx.write(0, 1, "Format", header);
|
||||||
|
xlsx.write(0, 2, "Shown value", header);
|
||||||
|
for (int i=0; i<numFormats.size(); ++i) {
|
||||||
|
int row = i+1;
|
||||||
|
xlsx.write(row, 0, 100.0);
|
||||||
|
xlsx.write(row, 1, numFormats[i]);
|
||||||
|
QXlsx::Format *format = xlsx.createFormat();
|
||||||
|
format->setNumberFormat(numFormats[i]);
|
||||||
|
xlsx.write(row, 2, 100.0, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Builtin number formats
|
||||||
|
xlsx.addWorksheet();
|
||||||
|
xlsx.setColumn(0, 4, 20.0);
|
||||||
|
xlsx.write(0, 0, "Raw data", header);
|
||||||
|
xlsx.write(0, 1, "Builtin Format", header);
|
||||||
|
xlsx.write(0, 2, "Shown value", header);
|
||||||
|
for (int i=0; i<50; ++i) {
|
||||||
|
int row = i+1;
|
||||||
|
int numFmt = i;
|
||||||
|
xlsx.write(row, 0, 100.0);
|
||||||
|
xlsx.write(row, 1, numFmt);
|
||||||
|
QXlsx::Format *format = xlsx.createFormat();
|
||||||
|
format->setNumberFormatIndex(numFmt);
|
||||||
|
xlsx.write(row, 2, 100.0, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
xlsx.save();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
TARGET = mergecells
|
||||||
|
|
||||||
|
#include(../../../src/xlsx/qtxlsx.pri)
|
||||||
|
QT += xlsx
|
||||||
|
|
||||||
|
TARGET = numberformat
|
||||||
|
CONFIG += console
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
||||||
@@ -43,7 +43,7 @@ int main()
|
|||||||
xlsx.setColumn(8, 15, 5.0, format4);
|
xlsx.setColumn(8, 15, 5.0, format4);
|
||||||
|
|
||||||
QXlsx::Format *format5 = xlsx.createFormat();
|
QXlsx::Format *format5 = xlsx.createFormat();
|
||||||
format5->setNumberFormat(22);
|
format5->setNumberFormatIndex(22);
|
||||||
xlsx.write("A5", QDate(2013, 8, 29), format5);
|
xlsx.write("A5", QDate(2013, 8, 29), format5);
|
||||||
|
|
||||||
QXlsx::Format *format6 = xlsx.createFormat();
|
QXlsx::Format *format6 = xlsx.createFormat();
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ SUBDIRS = hello style \
|
|||||||
documentproperty \
|
documentproperty \
|
||||||
image \
|
image \
|
||||||
mergecells \
|
mergecells \
|
||||||
rowcolumn
|
rowcolumn \
|
||||||
|
numberformat
|
||||||
|
|
||||||
|
|||||||
+33
-2
@@ -68,19 +68,50 @@ Format::~Format()
|
|||||||
delete d_ptr;
|
delete d_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Format::numberFormat() const
|
int Format::numberFormatIndex() const
|
||||||
{
|
{
|
||||||
Q_D(const Format);
|
Q_D(const Format);
|
||||||
return d->numberData.formatIndex;
|
return d->numberData.formatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Format::setNumberFormat(int format)
|
void Format::setNumberFormatIndex(int format)
|
||||||
{
|
{
|
||||||
Q_D(Format);
|
Q_D(Format);
|
||||||
d->dirty = true;
|
d->dirty = true;
|
||||||
d->numberData.formatIndex = format;
|
d->numberData.formatIndex = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Format::numberFormat() const
|
||||||
|
{
|
||||||
|
Q_D(const Format);
|
||||||
|
return d->numberData.formatString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Format::setNumberFormat(const QString &format)
|
||||||
|
{
|
||||||
|
Q_D(Format);
|
||||||
|
d->dirty = true;
|
||||||
|
d->numberData.formatString = format;
|
||||||
|
d->numberData._valid = false; //formatIndex must be re-generated
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Format::numFmtIndexValid() const
|
||||||
|
{
|
||||||
|
Q_D(const Format);
|
||||||
|
return d->numberData._valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
*/
|
||||||
|
void Format::setNumFmt(int index, const QString &string)
|
||||||
|
{
|
||||||
|
Q_D(Format);
|
||||||
|
d->numberData.formatIndex = index;
|
||||||
|
d->numberData.formatString = string;
|
||||||
|
d->numberData._valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
int Format::fontSize() const
|
int Format::fontSize() const
|
||||||
{
|
{
|
||||||
Q_D(const Format);
|
Q_D(const Format);
|
||||||
|
|||||||
@@ -129,8 +129,10 @@ public:
|
|||||||
|
|
||||||
~Format();
|
~Format();
|
||||||
|
|
||||||
int numberFormat() const;
|
int numberFormatIndex() const;
|
||||||
void setNumberFormat(int format);
|
void setNumberFormatIndex(int format);
|
||||||
|
QString numberFormat() const;
|
||||||
|
void setNumberFormat(const QString &format);
|
||||||
|
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
void setFontSize(int size);
|
void setFontSize(int size);
|
||||||
@@ -210,6 +212,9 @@ private:
|
|||||||
friend class WorksheetPrivate;
|
friend class WorksheetPrivate;
|
||||||
Format();
|
Format();
|
||||||
|
|
||||||
|
bool numFmtIndexValid() const;
|
||||||
|
void setNumFmt(int index, const QString &string);
|
||||||
|
|
||||||
bool fontIndexValid() const;
|
bool fontIndexValid() const;
|
||||||
int fontIndex() const;
|
int fontIndex() const;
|
||||||
void setFontIndex(int index);
|
void setFontIndex(int index);
|
||||||
|
|||||||
@@ -30,9 +30,12 @@ namespace QXlsx {
|
|||||||
|
|
||||||
struct NumberData
|
struct NumberData
|
||||||
{
|
{
|
||||||
NumberData() : formatIndex(0) {}
|
NumberData() : formatIndex(0), _valid(true) {}
|
||||||
|
|
||||||
int formatIndex;
|
int formatIndex;
|
||||||
|
QString formatString;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontData
|
struct FontData
|
||||||
|
|||||||
+69
-5
@@ -65,6 +65,61 @@ void Styles::addFormat(Format *format)
|
|||||||
if (!format)
|
if (!format)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//numFmt
|
||||||
|
if (!format->numFmtIndexValid()) {
|
||||||
|
if (m_builtinNumFmtsHash.isEmpty()) {
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("# ??/??"), 13);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22);
|
||||||
|
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48);
|
||||||
|
m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49);
|
||||||
|
}
|
||||||
|
const QString str = format->numberFormat();
|
||||||
|
//Assign proper number format index
|
||||||
|
if (m_builtinNumFmtsHash.contains(str)) {
|
||||||
|
format->setNumFmt(m_builtinNumFmtsHash[str], str);
|
||||||
|
} else if (m_customNumFmtsHash.contains(str)) {
|
||||||
|
format->setNumFmt(m_customNumFmtsHash[str], str);
|
||||||
|
} else {
|
||||||
|
int idx = 164 + m_customNumFmts.size();
|
||||||
|
m_customNumFmts.append(str);
|
||||||
|
m_customNumFmtsHash.insert(str, idx);
|
||||||
|
format->setNumFmt(idx, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Font
|
//Font
|
||||||
if (!format->fontIndexValid()) {
|
if (!format->fontIndexValid()) {
|
||||||
if (!m_fontsHash.contains(format->fontKey())) {
|
if (!m_fontsHash.contains(format->fontKey())) {
|
||||||
@@ -140,9 +195,7 @@ void Styles::saveToXmlFile(QIODevice *device)
|
|||||||
writer.writeStartElement(QStringLiteral("styleSheet"));
|
writer.writeStartElement(QStringLiteral("styleSheet"));
|
||||||
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
|
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
|
||||||
|
|
||||||
// writer.writeStartElement(QStringLiteral("numFmts"));
|
writeNumFmts(writer);
|
||||||
// writer.writeEndElement();//numFmts
|
|
||||||
|
|
||||||
writeFonts(writer);
|
writeFonts(writer);
|
||||||
writeFills(writer);
|
writeFills(writer);
|
||||||
writeBorders(writer);
|
writeBorders(writer);
|
||||||
@@ -180,6 +233,17 @@ void Styles::saveToXmlFile(QIODevice *device)
|
|||||||
writer.writeEndDocument();
|
writer.writeEndDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Styles::writeNumFmts(XmlStreamWriter &writer)
|
||||||
|
{
|
||||||
|
writer.writeStartElement(QStringLiteral("numFmts"));
|
||||||
|
for (int i=0; i<m_customNumFmts.size(); ++i) {
|
||||||
|
writer.writeEmptyElement(QStringLiteral("numFmt"));
|
||||||
|
writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(164 + i));
|
||||||
|
writer.writeAttribute(QStringLiteral("formatCode"), m_customNumFmts[i]);
|
||||||
|
}
|
||||||
|
writer.writeEndElement();//numFmts
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
not consider dxf format.
|
not consider dxf format.
|
||||||
*/
|
*/
|
||||||
@@ -394,7 +458,7 @@ void Styles::writeCellXfs(XmlStreamWriter &writer)
|
|||||||
writer.writeStartElement(QStringLiteral("cellXfs"));
|
writer.writeStartElement(QStringLiteral("cellXfs"));
|
||||||
writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size()));
|
writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size()));
|
||||||
foreach (Format *format, m_xf_formatsList) {
|
foreach (Format *format, m_xf_formatsList) {
|
||||||
int num_fmt_id = format->numberFormat();
|
int num_fmt_id = format->numberFormatIndex();
|
||||||
int font_id = format->fontIndex();
|
int font_id = format->fontIndex();
|
||||||
int fill_id = format->fillIndex();
|
int fill_id = format->fillIndex();
|
||||||
int border_id = format->borderIndex();
|
int border_id = format->borderIndex();
|
||||||
@@ -405,7 +469,7 @@ void Styles::writeCellXfs(XmlStreamWriter &writer)
|
|||||||
writer.writeAttribute(QStringLiteral("fillId"), QString::number(fill_id));
|
writer.writeAttribute(QStringLiteral("fillId"), QString::number(fill_id));
|
||||||
writer.writeAttribute(QStringLiteral("borderId"), QString::number(border_id));
|
writer.writeAttribute(QStringLiteral("borderId"), QString::number(border_id));
|
||||||
writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id));
|
writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id));
|
||||||
if (format->numberFormat() > 0)
|
if (format->numberFormatIndex() > 0)
|
||||||
writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1"));
|
writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1"));
|
||||||
if (format->fontIndex() > 0)
|
if (format->fontIndex() > 0)
|
||||||
writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1"));
|
writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1"));
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class Format;
|
friend class Format;
|
||||||
|
|
||||||
|
void writeNumFmts(XmlStreamWriter &writer);
|
||||||
void writeFonts(XmlStreamWriter &writer);
|
void writeFonts(XmlStreamWriter &writer);
|
||||||
void writeFills(XmlStreamWriter &writer);
|
void writeFills(XmlStreamWriter &writer);
|
||||||
void writeFill(XmlStreamWriter &writer, FillData *fill);
|
void writeFill(XmlStreamWriter &writer, FillData *fill);
|
||||||
@@ -64,6 +66,9 @@ private:
|
|||||||
void writeCellXfs(XmlStreamWriter &writer);
|
void writeCellXfs(XmlStreamWriter &writer);
|
||||||
void writeDxfs(XmlStreamWriter &writer);
|
void writeDxfs(XmlStreamWriter &writer);
|
||||||
|
|
||||||
|
QHash<QString, int> m_builtinNumFmtsHash;
|
||||||
|
QStringList m_customNumFmts;
|
||||||
|
QHash<QString, int> m_customNumFmtsHash;
|
||||||
QList<QSharedPointer<FontData> > m_fontsList; //Keep a copy of unique fonts
|
QList<QSharedPointer<FontData> > m_fontsList; //Keep a copy of unique fonts
|
||||||
QList<QSharedPointer<FillData> > m_fillsList; //Keep a copy of unique fills
|
QList<QSharedPointer<FillData> > m_fillsList; //Keep a copy of unique fills
|
||||||
QList<QSharedPointer<BorderData> > m_bordersList; //Keep a copy of unique borders
|
QList<QSharedPointer<BorderData> > m_bordersList; //Keep a copy of unique borders
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void testEmptyStyle();
|
void testEmptyStyle();
|
||||||
void testAddFormat();
|
void testAddFormat();
|
||||||
|
void testAddFormat2();
|
||||||
void testSolidFillBackgroundColor();
|
void testSolidFillBackgroundColor();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,6 +43,23 @@ void StylesTest::testAddFormat()
|
|||||||
QVERIFY2(xmlData.contains("<cellXfs count=\"2\">"), ""); //Note we have a default one
|
QVERIFY2(xmlData.contains("<cellXfs count=\"2\">"), ""); //Note we have a default one
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StylesTest::testAddFormat2()
|
||||||
|
{
|
||||||
|
QXlsx::Styles styles;
|
||||||
|
|
||||||
|
QXlsx::Format *format = styles.createFormat();
|
||||||
|
format->setNumberFormat("h:mm:ss AM/PM"); //builtin 19
|
||||||
|
styles.addFormat(format);
|
||||||
|
|
||||||
|
QCOMPARE(format->numberFormatIndex(), 19);
|
||||||
|
|
||||||
|
QXlsx::Format *format2 = styles.createFormat();
|
||||||
|
format2->setNumberFormat("aaaaa h:mm:ss AM/PM"); //custom
|
||||||
|
styles.addFormat(format2);
|
||||||
|
|
||||||
|
QCOMPARE(format2->numberFormatIndex(), 164);
|
||||||
|
}
|
||||||
|
|
||||||
// For a solid fill, Excel reverses the role of foreground and background colours
|
// For a solid fill, Excel reverses the role of foreground and background colours
|
||||||
void StylesTest::testSolidFillBackgroundColor()
|
void StylesTest::testSolidFillBackgroundColor()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user