From abb991c212e3d88c6e01c29ff237f082c2c7c790 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Tue, 27 Aug 2013 10:23:11 +0800 Subject: [PATCH] Add font format support for cell data --- README.md | 9 +++ examples/examples.pro | 3 + examples/hello/main.cpp | 2 + examples/style/main.cpp | 32 +++++++++++ examples/style/style.pro | 5 ++ src/xlsxformat.cpp | 120 +++++++++++++++++++++++++++------------ src/xlsxformat.h | 94 +++++++++++++++++++++++------- src/xlsxstyles.cpp | 31 +++++++--- src/xlsxworksheet.cpp | 45 ++++++++------- src/xlsxworksheet.h | 18 +++--- src/zipwriter.cpp | 1 - 11 files changed, 264 insertions(+), 96 deletions(-) create mode 100644 README.md create mode 100644 examples/style/main.cpp create mode 100644 examples/style/style.pro diff --git a/README.md b/README.md new file mode 100644 index 0000000..68a63b6 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ + + +## References + +* https://github.com/jmcnamara/XlsxWriter +* http://officeopenxml.com/anatomyofOOXML-xlsx.php +* http://www.libxl.com +* http://closedxml.codeplex.com/ +* http://search.cpan.org/~jmcnamara/Excel-Writer-XLSX-0.71/ diff --git a/examples/examples.pro b/examples/examples.pro index bf12ebe..8492073 100755 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -1,3 +1,6 @@ TEMPLATE = subdirs SUBDIRS = hello +SUBDIRS += \ + style + diff --git a/examples/hello/main.cpp b/examples/hello/main.cpp index b4b1c62..29f89eb 100755 --- a/examples/hello/main.cpp +++ b/examples/hello/main.cpp @@ -18,6 +18,8 @@ int main() sheet->write("D7", true); QXlsx::Worksheet *sheet2 = workbook.addWorksheet(); + //Rows and columns are zero indexed. + //The first cell in a worksheet, "A1", is (0, 0). sheet2->write(0, 0, "First"); sheet2->write(1, 0, "Second"); sheet2->write(2, 0, "Third"); diff --git a/examples/style/main.cpp b/examples/style/main.cpp new file mode 100644 index 0000000..7ada464 --- /dev/null +++ b/examples/style/main.cpp @@ -0,0 +1,32 @@ +#include +#include "xlsxworkbook.h" +#include "xlsxworksheet.h" +#include "xlsxformat.h" + +#ifdef Q_OS_MAC +# define DATA_PATH "../../../" +#else +# define DATA_PATH "./" +#endif + +int main() +{ + QXlsx::Workbook workbook; + QXlsx::Worksheet *sheet = workbook.addWorksheet(); + + QXlsx::Format *format1 = workbook.addFormat(); + format1->setFontColor(QColor(Qt::red)); + format1->setFontSize(15); + sheet->write("A1", "Hello Qt!", format1); + sheet->write("B3", 12345, format1); + + QXlsx::Format *format2 = workbook.addFormat(); + format2->setFontBold(true); + format2->setFontUnderline(QXlsx::Format::FontUnderlineDouble); + sheet->write("C5", "=44+33", format2); + sheet->write("D7", true, format2); + + workbook.save(DATA_PATH"TestStyle.xlsx"); + workbook.save(DATA_PATH"TestStyle.zip"); + return 0; +} diff --git a/examples/style/style.pro b/examples/style/style.pro new file mode 100644 index 0000000..7308607 --- /dev/null +++ b/examples/style/style.pro @@ -0,0 +1,5 @@ +TARGET = style + +include(../../src/qtxlsxwriter.pri) + +SOURCES += main.cpp diff --git a/src/xlsxformat.cpp b/src/xlsxformat.cpp index a08cca1..cd047e4 100755 --- a/src/xlsxformat.cpp +++ b/src/xlsxformat.cpp @@ -26,24 +26,32 @@ namespace QXlsx { -Format::Format(QObject *parent) : - QObject(parent) +Format::Format() { + m_font.bold = false; + m_font.color = QColor(Qt::black); + m_font.italic = false; + m_font.name = "Calibri"; + m_font.scirpt = FontScriptNormal; + m_font.size = 11; + m_font.strikeOut = false; + m_font.underline = FontUnderlineNone; + m_font.shadow = false; + m_font.outline = false; + m_font.family = 2; + m_font.scheme = "minor"; + m_font.charset = 0; + m_font.condense = 0; + m_font.extend = 0; + m_font.redundant = false; + m_font.index = 0; + m_is_dxf_fomat = false; m_xf_index = 0; m_dxf_index = 0; m_num_format_index = 0; - - m_has_font = false; - m_font_index = 0; - m_font_family = 2; - m_font_scheme = "minor"; - - m_font.setFamily("Calibri"); - m_font.setPointSize(11); - m_theme = 0; m_color_indexed = 0; @@ -54,70 +62,110 @@ Format::Format(QObject *parent) : m_border_index = false; } -bool Format::isDxfFormat() const +int Format::fontSize() const { - return m_is_dxf_fomat; + return m_font.size; } -void Format::setFont(const QFont &font) +void Format::setFontSize(int size) { - m_font = font; + m_font.size = size; } -void Format::setForegroundColor(const QColor &color) +bool Format::fontItalic() const { - m_fg_color = color; + return m_font.italic; } -void Format::setBackgroundColor(const QColor &color) +void Format::setFontItalic(bool italic) { - m_bg_color = color; + m_font.italic = italic; } -QString Format::fontName() const +bool Format::fontStrikeOut() const +{ + return m_font.strikeOut; +} + +void Format::setFontStricOut(bool stricOut) +{ + m_font.strikeOut = stricOut; +} + +QColor Format::fontColor() const +{ + return m_font.color; +} + +void Format::setFontColor(const QColor &color) +{ + m_font.color = color; +} + +bool Format::fontBold() const +{ + return m_font.bold; +} + +void Format::setFontBold(bool bold) +{ + m_font.bold = bold; +} + +Format::FontScript Format::fontScript() const +{ + return m_font.scirpt; +} + +void Format::setFontScript(FontScript script) { - return m_font.family(); + m_font.scirpt = script; } -bool Format::bold() const +Format::FontUnderline Format::fontUnderline() const { - return m_font.weight() == QFont::Bold; + return m_font.underline; } -bool Format::italic() const +void Format::setFontUnderline(FontUnderline underline) { - return m_font.italic(); + m_font.underline = underline; } bool Format::fontOutline() const { - return false; + return m_font.outline; } -bool Format::fontShadow() const +void Format::setFontOutline(bool outline) { - return false; + m_font.outline = outline; } -bool Format::fontStrikout() const +QString Format::fontName() const { - return m_font.strikeOut(); + return m_font.name; } -bool Format::fontUnderline() const +void Format::setFontName(const QString &name) { - return m_font.underline(); + m_font.name = name; } -QColor Format::fontColor() const +bool Format::isDxfFormat() const { - return m_font_color; + return m_is_dxf_fomat; } -int Format::fontSize() const + +void Format::setForegroundColor(const QColor &color) { - return m_font.pointSize(); + m_fg_color = color; } +void Format::setBackgroundColor(const QColor &color) +{ + m_bg_color = color; +} } // namespace QXlsx diff --git a/src/xlsxformat.h b/src/xlsxformat.h index 51e2702..2597e7e 100755 --- a/src/xlsxformat.h +++ b/src/xlsxformat.h @@ -25,48 +25,100 @@ #ifndef QXLSX_FORMAT_H #define QXLSX_FORMAT_H -#include #include #include namespace QXlsx { class Styles; +class Worksheet; -class Format : public QObject +class Format { - Q_OBJECT public: - void setFont(const QFont &font); + enum FontScript + { + FontScriptNormal, + FontScriptSuper, + FontScriptSub + }; + + enum FontUnderline + { + FontUnderlineNone, + FontUnderlineSingle, + FontUnderlineDouble, + FontUnderlineSingleAccounting, + FontUnderlineDoubleAccounting + }; + + int fontSize() const; + void setFontSize(int size); + bool fontItalic() const; + void setFontItalic(bool italic); + bool fontStrikeOut() const; + void setFontStricOut(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 &); + void setForegroundColor(const QColor &color); void setBackgroundColor(const QColor &color); private: friend class Styles; - explicit Format(QObject *parent = 0); + friend class Worksheet; + explicit Format(); + + struct Font + { + int size; + bool italic; + bool strikeOut; + QColor color; + bool bold; + FontScript scirpt; + FontUnderline underline; + bool outline; + bool shadow; + QString name; + int family; + int charset; + QString scheme; + int condense; + int extend; + + //helper member + bool redundant; //same with the fonts used by some other Formats + int index; //index in the Font list + } m_font; + + bool hasFont() const {return !m_font.redundant;} + int fontIndex() const {return m_font.index;} + void setFontIndex(int index) {m_font.index = index;} + int fontFamily() const{return m_font.family;} + bool fontShadow() const {return m_font.shadow;} + QString fontScheme() const {return m_font.scheme;} + bool isDxfFormat() const; + int xfIndex() const {return m_xf_index;} + void setXfIndex(int index) {m_xf_index = index; m_font.index=index;} //num int numFormatIndex() const {return m_num_format_index;} - //fonts - bool hasFont() const {return m_has_font;} - int fontIndex() const {return m_font_index;} - QString fontName() const; - bool bold() const; - bool italic() const; - bool fontStrikout() const; - bool fontOutline() const; - bool fontShadow() const; - bool fontUnderline() const; - QColor fontColor() const; - int fontSize() const; - int fontFamily() const{return m_font_family;} int theme() const {return m_theme;} int colorIndexed() const {return m_color_indexed;} - QString fontScheme() const {return m_font_scheme;} - void setHasFont(bool has) {m_has_font=has;} //fills bool hasFill() const {return m_has_fill;} @@ -86,10 +138,8 @@ private: bool m_has_font; int m_font_index; - QFont m_font; int m_font_family; QString m_font_scheme; - QColor m_font_color; QColor m_bg_color; QColor m_fg_color; int m_theme; diff --git a/src/xlsxstyles.cpp b/src/xlsxstyles.cpp index 3dfb5ea..69d753d 100755 --- a/src/xlsxstyles.cpp +++ b/src/xlsxstyles.cpp @@ -35,17 +35,19 @@ Styles::Styles(QObject *parent) : { m_fill_count = 2; //Starts from 2 m_borders_count = 1; - m_font_count = 1; + m_font_count = 0; //Add the default cell format Format *format = addFormat(); - format->setHasFont(true); format->setHasBorder(true); } Format *Styles::addFormat() { - Format *format = new Format(this); + Format *format = new Format(); + format->setXfIndex(m_formats.size()); + m_font_count += 1; + m_formats.append(format); return format; } @@ -109,18 +111,33 @@ void Styles::writeFonts(XmlStreamWriter &writer) foreach (Format *format, m_xf_formats) { if (format->hasFont()) { writer.writeStartElement("font"); - if (format->bold()) + if (format->fontBold()) writer.writeEmptyElement("b"); - if (format->italic()) + if (format->fontItalic()) writer.writeEmptyElement("i"); - if (format->fontStrikout()) + if (format->fontStrikeOut()) writer.writeEmptyElement("strike"); if (format->fontOutline()) writer.writeEmptyElement("outline"); if (format->fontShadow()) writer.writeEmptyElement("shadow"); - if (format->fontUnderline()) //More option + if (format->fontUnderline() != Format::FontUnderlineNone) { writer.writeEmptyElement("u"); + if (format->fontUnderline() == Format::FontUnderlineDouble) + writer.writeAttribute("val", "double"); + else if (format->fontUnderline() == Format::FontUnderlineSingleAccounting) + writer.writeAttribute("val", "singleAccounting"); + else if (format->fontUnderline() == Format::FontUnderlineDoubleAccounting) + writer.writeAttribute("val", "doubleAccounting"); + } + if (format->fontScript() != Format::FontScriptNormal) { + writer.writeEmptyElement("vertAligh"); + if (format->fontScript() == Format::FontScriptSuper) + writer.writeAttribute("val", "superscript"); + else + writer.writeAttribute("val", "subscript"); + } + if (!format->isDxfFormat()) { writer.writeEmptyElement("sz"); writer.writeAttribute("val", QString::number(format->fontSize())); diff --git a/src/xlsxworksheet.cpp b/src/xlsxworksheet.cpp index c4a80be..f9d147d 100755 --- a/src/xlsxworksheet.cpp +++ b/src/xlsxworksheet.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "xlsxworksheet.h" #include "xlsxworkbook.h" +#include "xlsxformat.h" #include "xlsxutility_p.h" #include "xlsxsharedstrings_p.h" #include "xmlstreamwriter_p.h" @@ -124,34 +125,34 @@ void Worksheet::setZeroValuesHidden(bool enable) m_show_zeros = !enable; } -int Worksheet::write(int row, int column, const QVariant &value) +int Worksheet::write(int row, int column, const QVariant &value, Format *format) { bool ok; int ret = 0; if (value.isNull()) { //blank - ret = writeBlank(row, column); + ret = writeBlank(row, column, format); } else if (value.type() == QMetaType::Bool) { //Bool - ret = writeBool(row,column, value.toBool()); + ret = writeBool(row,column, value.toBool(), format); } else if (value.toDateTime().isValid()) { //DateTime } else if (value.toDouble(&ok), ok) { //Number if (!m_workbook->isStringsToNumbersEnabled() && value.type() == QMetaType::QString) { //Don't convert string to number if the flag not enabled. - ret = writeString(row, column, value.toString()); + ret = writeString(row, column, value.toString(), format); } else { - ret = writeNumber(row, column, value.toDouble()); + ret = writeNumber(row, column, value.toDouble(), format); } } else if (value.type() == QMetaType::QUrl) { //url } else if (value.type() == QMetaType::QString) { //string QString token = value.toString(); if (token.startsWith("=")) { - ret = writeFormula(row, column, token); + ret = writeFormula(row, column, token, format); } else if (token.startsWith("{") && token.endsWith("}")) { } else { - ret = writeString(row, column, token); + ret = writeString(row, column, token, format); } } else { //Wrong type @@ -162,16 +163,16 @@ int Worksheet::write(int row, int column, const QVariant &value) } //convert the "A1" notation to row/column notation -int Worksheet::write(const QString row_column, const QVariant &value) +int Worksheet::write(const QString row_column, const QVariant &value, Format *format) { QPoint pos = xl_cell_to_rowcol(row_column); if (pos == QPoint(-1, -1)) { return -1; } - return write(pos.x(), pos.y(), value); + return write(pos.x(), pos.y(), value, format); } -int Worksheet::writeString(int row, int column, const QString &value) +int Worksheet::writeString(int row, int column, const QString &value, Format *format) { int error = 0; QString content = value; @@ -186,20 +187,20 @@ int Worksheet::writeString(int row, int column, const QString &value) SharedStrings *sharedStrings = m_workbook->sharedStrings(); int index = sharedStrings->addSharedString(content); - m_table[row][column] = XlsxCellData(index, XlsxCellData::String); + m_table[row][column] = XlsxCellData(index, XlsxCellData::String, format); return error; } -int Worksheet::writeNumber(int row, int column, double value) +int Worksheet::writeNumber(int row, int column, double value, Format *format) { if (checkDimensions(row, column)) return -1; - m_table[row][column] = XlsxCellData(value, XlsxCellData::Number); + m_table[row][column] = XlsxCellData(value, XlsxCellData::Number, format); return 0; } -int Worksheet::writeFormula(int row, int column, const QString &content, double result) +int Worksheet::writeFormula(int row, int column, const QString &content, Format *format, double result) { int error = 0; QString formula = content; @@ -210,28 +211,28 @@ int Worksheet::writeFormula(int row, int column, const QString &content, double if (formula.startsWith("=")) formula.remove(0,1); - XlsxCellData data(result, XlsxCellData::Formula); + XlsxCellData data(result, XlsxCellData::Formula, format); data.formula = formula; m_table[row][column] = data; return error; } -int Worksheet::writeBlank(int row, int column) +int Worksheet::writeBlank(int row, int column, Format *format) { if (checkDimensions(row, column)) return -1; - m_table[row][column] = XlsxCellData(QVariant(), XlsxCellData::Blank); + m_table[row][column] = XlsxCellData(QVariant(), XlsxCellData::Blank, format); return 0; } -int Worksheet::writeBool(int row, int column, bool value) +int Worksheet::writeBool(int row, int column, bool value, Format *format) { if (checkDimensions(row, column)) return -1; - m_table[row][column] = XlsxCellData(value, XlsxCellData::Boolean); + m_table[row][column] = XlsxCellData(value, XlsxCellData::Boolean, format); return 0; } @@ -386,8 +387,10 @@ void Worksheet::writeCellData(XmlStreamWriter &writer, int row, int col, const X writer.writeStartElement("c"); writer.writeAttribute("r", cell_range); - //Style used by the cell, row /col - // writer.writeAttribute("s", QString::number("")); + + //Style used by the cell, row or col + if (data.format) + writer.writeAttribute("s", QString::number(data.format->xfIndex())); if (data.dataType == XlsxCellData::String) { //data.data: Index of the string in sharedStringTable diff --git a/src/xlsxworksheet.h b/src/xlsxworksheet.h index db8b266..0deee22 100755 --- a/src/xlsxworksheet.h +++ b/src/xlsxworksheet.h @@ -47,8 +47,8 @@ struct XlsxCellData ArrayFormula, Boolean }; - XlsxCellData(const QVariant &data=QVariant(), CellDataType type=Blank) : - value(data), dataType(type), format(0) + XlsxCellData(const QVariant &data=QVariant(), CellDataType type=Blank, Format *format=0) : + value(data), dataType(type), format(format) { } @@ -63,13 +63,13 @@ class Worksheet : public QObject { Q_OBJECT public: - int write(const QString row_column, const QVariant &value); - int write(int row, int column, const QVariant &value); - int writeString(int row, int column, const QString &value); - int writeNumber(int row, int column, double value); - int writeFormula(int row, int column, const QString &formula, double result=0); - int writeBlank(int row, int column); - int writeBool(int row, int column, bool value); + int write(const QString row_column, const QVariant &value, Format *format=0); + int write(int row, int column, const QVariant &value, Format *format=0); + int writeString(int row, int column, const QString &value, Format *format=0); + int writeNumber(int row, int column, double value, Format *format=0); + int writeFormula(int row, int column, const QString &formula, Format *format=0, double result=0); + int writeBlank(int row, int column, Format *format=0); + int writeBool(int row, int column, bool value, Format *format=0); void setRightToLeft(bool enable); void setZeroValuesHidden(bool enable); diff --git a/src/zipwriter.cpp b/src/zipwriter.cpp index 3e20f4a..45f8650 100644 --- a/src/zipwriter.cpp +++ b/src/zipwriter.cpp @@ -47,7 +47,6 @@ void ZipWriter::addFile(const QString &filePath, QIODevice *device) void ZipWriter::addFile(const QString &filePath, const QByteArray &data) { - qDebug()<addFile(filePath, data); }