File indexing completed on 2024-05-12 16:35:39

0001 /* This file is part of the KDE project
0002    Copyright 1998-2016 The Calligra Team <calligra-devel@kde.org>
0003    Copyright 2016 Tomas Mecir <mecirt@gmail.com>
0004    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0005    Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0006    Copyright 2007 Thorsten Zachmann <zachmann@kde.org>
0007    Copyright 2005-2006 Inge Wallin <inge@lysator.liu.se>
0008    Copyright 2004 Ariya Hidayat <ariya@kde.org>
0009    Copyright 2002-2003 Norbert Andres <nandres@web.de>
0010    Copyright 2000-2002 Laurent Montel <montel@kde.org>
0011    Copyright 2002 John Dailey <dailey@vt.edu>
0012    Copyright 2002 Phillip Mueller <philipp.mueller@gmx.de>
0013    Copyright 2000 Werner Trobin <trobin@kde.org>
0014    Copyright 1999-2000 Simon Hausmann <hausmann@kde.org>
0015    Copyright 1999 David Faure <faure@kde.org>
0016    Copyright 1998-2000 Torben Weis <weis@kde.org>
0017 
0018    This library is free software; you can redistribute it and/or
0019    modify it under the terms of the GNU Library General Public
0020    License as published by the Free Software Foundation; either
0021    version 2 of the License, or (at your option) any later version.
0022 
0023    This library is distributed in the hope that it will be useful,
0024    but WITHOUT ANY WARRANTY; without even the implied warranty of
0025    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0026    Library General Public License for more details.
0027 
0028    You should have received a copy of the GNU Library General Public License
0029    along with this library; see the file COPYING.LIB.  If not, write to
0030    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0031    Boston, MA 02110-1301, USA.
0032 */
0033 
0034 #include "SheetsOdf.h"
0035 #include "SheetsOdfPrivate.h"
0036 #include "Region.h"
0037 
0038 // This file contains functionality to load/save regions
0039 
0040 namespace Calligra {
0041 namespace Sheets {
0042 
0043 static void append(const QChar *from, const QChar *to, QChar **dest)
0044 {
0045     while (from < to) {
0046         **dest = *from;
0047         ++from;
0048         ++*dest;
0049     }
0050 }
0051 
0052 void Odf::loadRegion(const QChar *&data, const QChar *&end, QChar *&out)
0053 {
0054     enum { Start, InQuotes } state = Start;
0055 
0056     if (*data == QChar('$', 0)) {
0057         ++data;
0058     }
0059 
0060     bool isRange = false;
0061 
0062     const QChar *pos = data;
0063     while (data < end) {
0064         switch (state) {
0065         case Start:
0066             switch (data->unicode()) {
0067             case '\'': // quoted sheet name or named area
0068                 state = InQuotes;
0069                 break;
0070             case '.': // sheet name separator
0071                 if (pos != data && !isRange) {
0072                     append(pos, data, &out);
0073                     *out = QChar('!', 0);
0074                     ++out;
0075                 }
0076                 pos = data;
0077                 ++pos;
0078                 break;
0079             case ':': { // cell separator
0080                 isRange = true;
0081                 append(pos, data, &out);
0082                 *out = *data; // append :
0083                 ++out;
0084                 const QChar * next = data + 1;
0085                 if (!next->isNull()) {
0086                     const QChar * nextnext = next + 1;
0087                     if (!nextnext->isNull() && *next == QChar('$', 0) && *nextnext != QChar('.', 0)) {
0088                         ++data;
0089                     }
0090                 }
0091                 pos = data + 1;
0092             }   break;
0093             case ' ': // range separator
0094                 append(pos, data, &out);
0095                 *out = QChar(';', 0);
0096                 ++out;
0097                 pos = data;
0098                 break;
0099             default:
0100                 break;
0101             }
0102             break;
0103         case InQuotes:
0104             if (data->unicode() == '\'') {
0105                 // an escaped apostrophe?
0106                 // As long as Calligra Sheets does not support fixed sheets eat the dollar sign.
0107                 const QChar * next = data + 1;
0108                 if (!next->isNull() && *next == QChar('\'', 0)) {
0109                     ++data;
0110                 }
0111                 else { // the end
0112                     state = Start;
0113                 }
0114             }
0115             break;
0116         }
0117         ++data;
0118     }
0119     append(pos, data, &out);
0120 }
0121 
0122 QString Odf::loadRegion(const QString& expression)
0123 {
0124     QString result;
0125     QString temp;
0126     bool isRange = false;
0127     enum { Start, InQuotes } state = Start;
0128     int i = 0;
0129     // NOTE Stefan: As long as Calligra Sheets does not support fixed sheets eat the dollar sign.
0130     if (expression[i] == '$')
0131         ++i;
0132     while (i < expression.count()) {
0133         switch (state) {
0134         case Start: {
0135             if (expression[i] == '\'') { // quoted sheet name or named area
0136                 temp.append(expression[i]);
0137                 state = InQuotes;
0138             } else if (expression[i] == '.') { // sheet name separator
0139                 // was there already a sheet name?
0140                 if (!temp.isEmpty() && !isRange) {
0141                     result.append(temp);
0142                     result.append('!');
0143                 }
0144                 temp.clear();
0145             } else if (expression[i] == ':') { // cell separator
0146                 isRange = true;
0147                 result.append(temp);
0148                 result.append(':');
0149                 temp.clear();
0150                 // NOTE Stefan: As long as Calligra Sheets does not support fixed sheets eat the dollar sign.
0151                 if (i + 2 < expression.count() && expression[i+1] == '$' && expression[i+2] != '.')
0152                     ++i;
0153             } else if (expression[i] == ' ') { // range separator
0154                 result.append(temp);
0155                 result.append(';');
0156                 temp.clear();
0157             } else
0158                 temp.append(expression[i]);
0159             ++i;
0160             break;
0161         }
0162         case InQuotes: {
0163             temp.append(expression[i]);
0164             if (expression[i] == '\'') {
0165                 // an escaped apostrophe?
0166                 if (i + 1 < expression.count() && expression[i+1] == '\'')
0167                     ++i; // eat it
0168                 else // the end
0169                     state = Start;
0170             }
0171             ++i;
0172             break;
0173         }
0174         }
0175     }
0176     return result + temp;
0177 }
0178 
0179 QString Odf::saveRegion(const QString& expression)
0180 {
0181     QString result;
0182     QString sheetName;
0183     QString temp;
0184     enum { Start, InQuotes } state = Start;
0185     int i = 0;
0186     while (i < expression.count()) {
0187         switch (state) {
0188         case Start: {
0189             if (expression[i] == '\'') {
0190                 temp.append(expression[i]);
0191                 state = InQuotes;
0192             } else if (expression[i] == '!') { // sheet name separator
0193                 // There has to be a sheet name.
0194                 if (temp.isEmpty())
0195                     return expression; // error
0196                 if (temp.count() > 2 && (temp[0] != '\'' && temp[temp.count()-1] != '\'')) {
0197                     temp.replace('\'', "''");
0198                     if (temp.contains(' ') || temp.contains('.') ||
0199                             temp.contains(';') || temp.contains('!') ||
0200                             temp.contains('$') || temp.contains(']'))
0201                         temp = '\'' + temp + '\'';
0202                 }
0203                 sheetName = temp;
0204                 result.append(temp);
0205                 result.append('.');
0206                 temp.clear();
0207             } else if (expression[i] == ':') { // cell separator
0208                 if (result.isEmpty())
0209                     result = '.';
0210                 result.append(temp);
0211                 result.append(':');
0212                 result.append(sheetName);
0213                 result.append('.');
0214                 temp.clear();
0215             } else if (expression[i] == ';') { // range separator
0216                 result.append(temp);
0217                 result.append(' ');
0218                 temp.clear();
0219             } else
0220                 temp.append(expression[i]);
0221             ++i;
0222             break;
0223         }
0224         case InQuotes: {
0225             temp.append(expression[i]);
0226             if (expression[i] == '\'') {
0227                 // an escaped apostrophe?
0228                 if (i + 1 < expression.count() && expression[i+1] == '\'')
0229                     ++i; // eat it
0230                 else // the end
0231                     state = Start;
0232             }
0233             ++i;
0234             break;
0235         }
0236         }
0237     }
0238     if (result.isEmpty())
0239         result = '.';
0240     return result + temp;
0241 }
0242 
0243 QString Odf::saveRegion(Region *region)
0244 {
0245     return saveRegion(region->name());
0246 }
0247 
0248 
0249 }  // Sheets
0250 }  // Calligra
0251