diff src/xlsx/xlsxutility.cpp @ 1:93d3106bb9a4

Add qt xlsx library
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 22 Mar 2016 10:38:08 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xlsx/xlsxutility.cpp	Tue Mar 22 10:38:08 2016 +0100
@@ -0,0 +1,276 @@
+/****************************************************************************
+** 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.
+**
+****************************************************************************/
+#include "xlsxutility_p.h"
+#include "xlsxcellreference.h"
+
+#include <QString>
+#include <QPoint>
+#include <QRegularExpression>
+#include <QMap>
+#include <QStringList>
+#include <QColor>
+#include <QDateTime>
+#include <QDebug>
+
+namespace QXlsx {
+
+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 QStringList()<<QStringLiteral(".")<<path;
+
+    return QStringList()<<path.left(idx)<<path.mid(idx+1);
+}
+
+/*
+ * Return the .rel file path based on filePath
+ */
+QString getRelFilePath(const QString &filePath)
+{
+    int idx = filePath.lastIndexOf(QLatin1Char('/'));
+    if (idx == -1)
+        return QString();
+
+    return QString(filePath.left(idx) + QLatin1String("/_rels/")
+                   + filePath.mid(idx+1) + QLatin1String(".rels"));
+}
+
+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 QT_VERSION >= 0x050200
+    if (dt.isDaylightTime())    // Add one hour if the date is Daylight
+        excel_time += 1.0 / 24.0;
+#endif
+
+    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);
+}
+
+QDateTime datetimeFromNumber(double num, bool is1904)
+{
+    if (!is1904 && num > 60)
+        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 dt = epoch.addMSecs(msecs);
+
+#if QT_VERSION >= 0x050200
+    // Remove one hour to see whether the date is Daylight
+    QDateTime dt2 = dt.addMSecs(-3600);
+    if (dt2.isDaylightTime())
+        return dt2;
+#endif
+
+    return dt;
+}
+
+/*
+  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.
+    if (nameProposal.contains(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]"))))
+        ret.replace(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]")), 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
+    if (!sheetName.contains(QRegularExpression(QStringLiteral("[ +\\-,%^=<>'&]"))))
+        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)
+{
+    //Find all the "$?[A-Z]+$?[0-9]+" patterns in the rootFormula.
+    QList<QPair<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
+    foreach (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(qMakePair(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(qMakePair(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(qMakePair(segment, refFlag));
+                    segment = QString(ch); //Start new segment.
+                } else {
+                    segment.append(ch);
+                }
+                refState = INVALID;
+            }
+        }
+    }
+
+    if (!segment.isEmpty())
+        segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
+
+    //Replace "A1", "$A1", "A$1" segment with proper one.
+    QStringList result;
+    typedef QPair<QString, int> PairType;
+    foreach (PairType 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());
+}
+
+} //namespace QXlsx
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)