From 07ea0d92d9c749223df086e5fffad2ef3ef6c99f Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Fri, 27 Dec 2013 14:22:20 +0800 Subject: [PATCH] Code refactoring: Make Cell::isDateTime() reliable --- README.md | 9 +++ src/xlsx/qtxlsx.pri | 6 +- src/xlsx/xlsxcell.cpp | 4 +- src/xlsx/xlsxformat.cpp | 12 ++-- src/xlsx/xlsxnumformatparser.cpp | 94 ++++++++++++++++++++++++++++ src/xlsx/xlsxnumformatparser_p.h | 51 +++++++++++++++ tests/auto/format/tst_formattest.cpp | 5 ++ 7 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 src/xlsx/xlsxnumformatparser.cpp create mode 100644 src/xlsx/xlsxnumformatparser_p.h diff --git a/README.md b/README.md index 1cea012..ba94dcc 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ The package contains a **qtxlsx.pri** file that allows you to integrate the comp ## References +### General + * https://github.com/jmcnamara/XlsxWriter * http://openpyxl.readthedocs.org * http://officeopenxml.com/anatomyofOOXML-xlsx.php @@ -122,3 +124,10 @@ The package contains a **qtxlsx.pri** file that allows you to integrate the comp * http://excelpackage.codeplex.com/ * http://spreadsheetlight.com/ * http://www.schemacentral.com/sc/ooxml/ + +### Number formats + +* http://msdn.microsoft.com/en-us/library/ff529356%28v=office.12%29.aspx +* http://www.ozgrid.com/Excel/excel-custom-number-formats.htm +* http://stackoverflow.com/questions/894805/excel-number-format-what-is-409 +* http://office.microsoft.com/en-001/excel-help/create-a-custom-number-format-HP010342372.aspx diff --git a/src/xlsx/qtxlsx.pri b/src/xlsx/qtxlsx.pri index 43437ae..b9d3364 100755 --- a/src/xlsx/qtxlsx.pri +++ b/src/xlsx/qtxlsx.pri @@ -34,7 +34,8 @@ HEADERS += $$PWD/xlsxdocpropscore_p.h \ $$PWD/xlsxrichstring.h \ $$PWD/xlsxconditionalformatting.h \ $$PWD/xlsxconditionalformatting_p.h \ - $$PWD/xlsxcolor_p.h + $$PWD/xlsxcolor_p.h \ + $$PWD/xlsxnumformatparser_p.h SOURCES += $$PWD/xlsxdocpropscore.cpp \ $$PWD/xlsxdocpropsapp.cpp \ @@ -57,4 +58,5 @@ SOURCES += $$PWD/xlsxdocpropscore.cpp \ $$PWD/xlsxcellrange.cpp \ $$PWD/xlsxrichstring.cpp \ $$PWD/xlsxconditionalformatting.cpp \ - $$PWD/xlsxcolor.cpp + $$PWD/xlsxcolor.cpp \ + $$PWD/xlsxnumformatparser.cpp diff --git a/src/xlsx/xlsxcell.cpp b/src/xlsx/xlsxcell.cpp index c1d44a0..b8a6cd4 100644 --- a/src/xlsx/xlsxcell.cpp +++ b/src/xlsx/xlsxcell.cpp @@ -122,8 +122,10 @@ QString Cell::formula() const bool Cell::isDateTime() const { Q_D(const Cell); - if (d->dataType == Numeric && d->format.isValid() && d->format.isDateTimeFormat()) + if (d->dataType == Numeric && d->value.toDouble() >=0 + && d->format.isValid() && d->format.isDateTimeFormat()) { return true; + } return false; } diff --git a/src/xlsx/xlsxformat.cpp b/src/xlsx/xlsxformat.cpp index 56e34f2..c572c07 100755 --- a/src/xlsx/xlsxformat.cpp +++ b/src/xlsx/xlsxformat.cpp @@ -25,8 +25,8 @@ #include "xlsxformat.h" #include "xlsxformat_p.h" #include "xlsxcolor_p.h" +#include "xlsxnumformatparser_p.h" #include -#include #include QT_BEGIN_NAMESPACE_XLSX @@ -266,16 +266,16 @@ bool Format::isDateTimeFormat() const if (hasProperty(FormatPrivate::P_NumFmt_FormatCode)) { //Custom numFmt, so //Gauss from the number string - QString formatCode = numberFormat(); - formatCode.remove(QRegularExpression(QStringLiteral("\\[(Green|White|Blue|Magenta|Yellow|Cyan|Red)\\]"))); - if (formatCode.contains(QRegularExpression(QStringLiteral("[dmhys]")))) - return true; + return NumFormatParser::isDateTime(numberFormat()); } else if (hasProperty(FormatPrivate::P_NumFmt_Id)){ //Non-custom numFmt int idx = numberFormatIndex(); //Is built-in date time number id? - if ((idx >= 15 && idx <= 22) || (idx >= 45 && idx <= 47)) + if ((idx >= 14 && idx <= 22) || (idx >= 45 && idx <= 47)) + return true; + + if ((idx >= 27 && idx <= 36) || (idx >= 50 && idx <= 58)) //Used in CHS\CHT\JPN\KOR return true; } diff --git a/src/xlsx/xlsxnumformatparser.cpp b/src/xlsx/xlsxnumformatparser.cpp new file mode 100644 index 0000000..4132e44 --- /dev/null +++ b/src/xlsx/xlsxnumformatparser.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** Copyright (c) 2013 Debao Zhang +** 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. +** +****************************************************************************/ +#include "xlsxnumformatparser_p.h" + +#include + +namespace QXlsx { + +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 ';': + 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; +} + +} // namespace QXlsx diff --git a/src/xlsx/xlsxnumformatparser_p.h b/src/xlsx/xlsxnumformatparser_p.h new file mode 100644 index 0000000..d68364f --- /dev/null +++ b/src/xlsx/xlsxnumformatparser_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** Copyright (c) 2013 Debao Zhang +** 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" + +namespace QXlsx { + +class NumFormatParser +{ +public: + static bool isDateTime(const QString &formatCode); +}; + +} // namespace QXlsx + +#endif // QXLSX_NUMFORMATPARSER_H diff --git a/tests/auto/format/tst_formattest.cpp b/tests/auto/format/tst_formattest.cpp index 9c9599e..fcedc9d 100644 --- a/tests/auto/format/tst_formattest.cpp +++ b/tests/auto/format/tst_formattest.cpp @@ -43,8 +43,13 @@ void FormatTest::testDateTimeFormat_data() QTest::newRow("4") << QString("[h]:mm:ss")<