Browse Source

Add custom number format support

master
Debao Zhang 12 years ago
parent
commit
b4d9c5f2dd
  1. 52
      examples/xlsx/numberformat/main.cpp
  2. 12
      examples/xlsx/numberformat/numberformat.pro
  3. 2
      examples/xlsx/style/main.cpp
  4. 3
      examples/xlsx/xlsx.pro
  5. 35
      src/xlsx/xlsxformat.cpp
  6. 9
      src/xlsx/xlsxformat.h
  7. 5
      src/xlsx/xlsxformat_p.h
  8. 74
      src/xlsx/xlsxstyles.cpp
  9. 5
      src/xlsx/xlsxstyles_p.h
  10. 18
      tests/auto/styles/tst_stylestest.cpp

52
examples/xlsx/numberformat/main.cpp

@ -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;
}

12
examples/xlsx/numberformat/numberformat.pro

@ -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

2
examples/xlsx/style/main.cpp

@ -43,7 +43,7 @@ int main()
xlsx.setColumn(8, 15, 5.0, format4);
QXlsx::Format *format5 = xlsx.createFormat();
format5->setNumberFormat(22);
format5->setNumberFormatIndex(22);
xlsx.write("A5", QDate(2013, 8, 29), format5);
QXlsx::Format *format6 = xlsx.createFormat();

3
examples/xlsx/xlsx.pro

@ -3,5 +3,6 @@ SUBDIRS = hello style \
documentproperty \
image \
mergecells \
rowcolumn
rowcolumn \
numberformat

35
src/xlsx/xlsxformat.cpp

@ -68,19 +68,50 @@ Format::~Format()
delete d_ptr;
}
int Format::numberFormat() const
int Format::numberFormatIndex() const
{
Q_D(const Format);
return d->numberData.formatIndex;
}
void Format::setNumberFormat(int format)
void Format::setNumberFormatIndex(int format)
{
Q_D(Format);
d->dirty = true;
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
{
Q_D(const Format);

9
src/xlsx/xlsxformat.h

@ -129,8 +129,10 @@ public:
~Format();
int numberFormat() const;
void setNumberFormat(int format);
int numberFormatIndex() const;
void setNumberFormatIndex(int format);
QString numberFormat() const;
void setNumberFormat(const QString &format);
int fontSize() const;
void setFontSize(int size);
@ -210,6 +212,9 @@ private:
friend class WorksheetPrivate;
Format();
bool numFmtIndexValid() const;
void setNumFmt(int index, const QString &string);
bool fontIndexValid() const;
int fontIndex() const;
void setFontIndex(int index);

5
src/xlsx/xlsxformat_p.h

@ -30,9 +30,12 @@ namespace QXlsx {
struct NumberData
{
NumberData() : formatIndex(0) {}
NumberData() : formatIndex(0), _valid(true) {}
int formatIndex;
QString formatString;
bool _valid;
};
struct FontData

74
src/xlsx/xlsxstyles.cpp

@ -65,6 +65,61 @@ void Styles::addFormat(Format *format)
if (!format)
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
if (!format->fontIndexValid()) {
if (!m_fontsHash.contains(format->fontKey())) {
@ -140,9 +195,7 @@ void Styles::saveToXmlFile(QIODevice *device)
writer.writeStartElement(QStringLiteral("styleSheet"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
// writer.writeStartElement(QStringLiteral("numFmts"));
// writer.writeEndElement();//numFmts
writeNumFmts(writer);
writeFonts(writer);
writeFills(writer);
writeBorders(writer);
@ -180,6 +233,17 @@ void Styles::saveToXmlFile(QIODevice *device)
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.
*/
@ -394,7 +458,7 @@ void Styles::writeCellXfs(XmlStreamWriter &writer)
writer.writeStartElement(QStringLiteral("cellXfs"));
writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size()));
foreach (Format *format, m_xf_formatsList) {
int num_fmt_id = format->numberFormat();
int num_fmt_id = format->numberFormatIndex();
int font_id = format->fontIndex();
int fill_id = format->fillIndex();
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("borderId"), QString::number(border_id));
writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id));
if (format->numberFormat() > 0)
if (format->numberFormatIndex() > 0)
writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1"));
if (format->fontIndex() > 0)
writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1"));

5
src/xlsx/xlsxstyles_p.h

@ -29,6 +29,7 @@
#include <QSharedPointer>
#include <QHash>
#include <QList>
#include <QStringList>
class QIODevice;
@ -56,6 +57,7 @@ public:
private:
friend class Format;
void writeNumFmts(XmlStreamWriter &writer);
void writeFonts(XmlStreamWriter &writer);
void writeFills(XmlStreamWriter &writer);
void writeFill(XmlStreamWriter &writer, FillData *fill);
@ -64,6 +66,9 @@ private:
void writeCellXfs(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<FillData> > m_fillsList; //Keep a copy of unique fills
QList<QSharedPointer<BorderData> > m_bordersList; //Keep a copy of unique borders

18
tests/auto/styles/tst_stylestest.cpp

@ -13,6 +13,7 @@ public:
private Q_SLOTS:
void testEmptyStyle();
void testAddFormat();
void testAddFormat2();
void testSolidFillBackgroundColor();
};
@ -42,6 +43,23 @@ void StylesTest::testAddFormat()
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
void StylesTest::testSolidFillBackgroundColor()
{

Loading…
Cancel
Save