diff --git a/src/xlsx/xlsxchart.cpp b/src/xlsx/xlsxchart.cpp index d66f866..a69f5c2 100644 --- a/src/xlsx/xlsxchart.cpp +++ b/src/xlsx/xlsxchart.cpp @@ -104,8 +104,8 @@ void Chart::addSeries(const CellRange &range, AbstractSheet *sheet) return; QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName(); - if (sheetName.contains(QLatin1Char(' '))) - sheetName = QLatin1Char('\'') + sheetName + QLatin1Char('\''); + //In case sheetName contains space or ' + sheetName = escapeSheetName(sheetName); if (range.columnCount() == 1 || range.rowCount() == 1) { QSharedPointer series = QSharedPointer(new XlsxSeries); diff --git a/src/xlsx/xlsxutility.cpp b/src/xlsx/xlsxutility.cpp index 92d7fde..d2abadb 100755 --- a/src/xlsx/xlsxutility.cpp +++ b/src/xlsx/xlsxutility.cpp @@ -127,16 +127,51 @@ QString createSafeSheetName(const QString &nameProposal) return QString(); QString ret = nameProposal; - if (nameProposal.contains(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]+")))) - ret.replace(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]+")), QStringLiteral(" ")); - while(ret.contains(QRegularExpression(QStringLiteral("^\\s*'\\s*|\\s*'\\s*$")))) - ret.remove(QRegularExpression(QStringLiteral("^\\s*'\\s*|\\s*'\\s*$"))); - ret = ret.trimmed(); + 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 */ diff --git a/src/xlsx/xlsxutility_p.h b/src/xlsx/xlsxutility_p.h index fcd7cc6..fd563be 100755 --- a/src/xlsx/xlsxutility_p.h +++ b/src/xlsx/xlsxutility_p.h @@ -57,6 +57,9 @@ XLSX_AUTOTEST_EXPORT QDateTime datetimeFromNumber(double num, bool is1904=false) XLSX_AUTOTEST_EXPORT double timeToNumber(const QTime &t); XLSX_AUTOTEST_EXPORT QString createSafeSheetName(const QString &nameProposal); +XLSX_AUTOTEST_EXPORT QString escapeSheetName(const QString &sheetName); +XLSX_AUTOTEST_EXPORT QString unescapeSheetName(const QString &sheetName); + XLSX_AUTOTEST_EXPORT bool isSpaceReserveNeeded(const QString &string); XLSX_AUTOTEST_EXPORT QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell); diff --git a/src/xlsx/xlsxworkbook.cpp b/src/xlsx/xlsxworkbook.cpp index c8716f7..3eb7cd7 100755 --- a/src/xlsx/xlsxworkbook.cpp +++ b/src/xlsx/xlsxworkbook.cpp @@ -285,12 +285,12 @@ bool Workbook::setActiveSheet(int index) } /*! - * Rename the worksheet at the \a index to \a name. + * Rename the worksheet at the \a index to \a newName. */ -bool Workbook::renameSheet(int index, const QString &name) +bool Workbook::renameSheet(int index, const QString &newName) { Q_D(Workbook); - + QString name = createSafeSheetName(newName); if (index < 0 || index >= d->sheets.size()) return false; @@ -350,7 +350,7 @@ bool Workbook::copySheet(int index, const QString &newName) if (index < 0 || index >= d->sheets.size()) return false; - QString worksheetName = newName; + QString worksheetName = createSafeSheetName(newName); if (!newName.isEmpty()) { //If user given an already in-used name, we should not continue any more! if (d->sheetNames.contains(newName)) diff --git a/tests/auto/utility/tst_utilitytest.cpp b/tests/auto/utility/tst_utilitytest.cpp index c3f3640..892b41a 100644 --- a/tests/auto/utility/tst_utilitytest.cpp +++ b/tests/auto/utility/tst_utilitytest.cpp @@ -48,6 +48,9 @@ private Q_SLOTS: void test_createSafeSheetName_data(); void test_createSafeSheetName(); + void test_escapeSheetName_data(); + void test_escapeSheetName(); + void test_convertSharedFormula_data(); void test_convertSharedFormula(); }; @@ -131,17 +134,19 @@ void UtilityTest::test_createSafeSheetName_data() QTest::addColumn("original"); QTest::addColumn("result"); - QTest::newRow("[Hello]") << QString("[Hello]")<("original"); + QTest::addColumn("result"); + + QTest::newRow("HelloQt") << QString("HelloQt")<Qt") << QString("Hello<>Qt")<Qt'"); + QTest::newRow("Hello,Qt") << QString("Hello,Qt")<("original");