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

0001 /* This file is part of the KDE project
0002    Copyright 2016 Tomas Mecir <mecirt@gmail.com>
0003    Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "SheetsOdf.h"
0022 #include "SheetsOdfPrivate.h"
0023 
0024 #include "Cell.h"
0025 #include "Map.h"
0026 #include "Sheet.h"
0027 #include "Validity.h"
0028 #include "ValueParser.h"
0029 
0030 #include <KoXmlReader.h>
0031 #include <KoXmlNS.h>
0032 
0033 #include "OdfLoadingContext.h"
0034 
0035 namespace Calligra {
0036 namespace Sheets {
0037 
0038 namespace Odf {
0039     void loadValidationCondition(Validity *validity, QString &valExpression, const ValueParser *parser);
0040     void loadValidationValue(Validity *validity, const QStringList &listVal, const ValueParser *parser);
0041 }
0042 
0043 void Odf::loadValidation(Validity *validity, Cell* const cell, const QString& validationName,
0044                                  OdfLoadingContext& tableContext)
0045 {
0046     KoXmlElement element = tableContext.validities.value(validationName);
0047     if (element.hasAttributeNS(KoXmlNS::table, "condition")) {
0048         QString valExpression = element.attributeNS(KoXmlNS::table, "condition", QString());
0049         debugSheetsODF << " element.attribute( table:condition )" << valExpression;
0050         //Condition ::= ExtendedTrueCondition | TrueFunction 'and' TrueCondition
0051         //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
0052         //ExtendedTrueCondition ::= ExtendedGetFunction | cell-content-text-length() Operator Value
0053         //TrueCondition ::= GetFunction | cell-content() Operator Value
0054         //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
0055         //ExtendedGetFunction ::= cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value)
0056         //Operator ::= '<' | '>' | '<=' | '>=' | '=' | '!='
0057         //Value ::= NumberValue | String | Formula
0058         //A Formula is a formula without an equals (=) sign at the beginning. See section 8.1.3 for more information.
0059         //A String comprises one or more characters surrounded by quotation marks.
0060         //A NumberValue is a whole or decimal number. It must not contain comma separators for numbers of 1000 or greater.
0061 
0062         //ExtendedTrueCondition
0063         if (valExpression.contains("cell-content-text-length()")) {
0064             //"cell-content-text-length()>45"
0065             valExpression = valExpression.remove("oooc:cell-content-text-length()");
0066             debugSheetsODF << " valExpression = :" << valExpression;
0067             validity->setRestriction(Validity::TextLength);
0068 
0069             loadValidationCondition(validity, valExpression, cell->sheet()->map()->parser());
0070         } else if (valExpression.contains("cell-content-is-text()")) {
0071             validity->setRestriction(Validity::Text);
0072         }
0073         //cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value) | cell-content-is-in-list( StringList )
0074         else if (valExpression.contains("cell-content-text-length-is-between")) {
0075             validity->setRestriction(Validity::TextLength);
0076             validity->setCondition(Conditional::Between);
0077             valExpression.remove("oooc:cell-content-text-length-is-between(");
0078             debugSheetsODF << " valExpression :" << valExpression;
0079             valExpression.remove(')');
0080             QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
0081             loadValidationValue(validity, listVal, cell->sheet()->map()->parser());
0082         } else if (valExpression.contains("cell-content-text-length-is-not-between")) {
0083             validity->setRestriction(Validity::TextLength);
0084             validity->setCondition(Conditional::Different);
0085             valExpression.remove("oooc:cell-content-text-length-is-not-between(");
0086             debugSheetsODF << " valExpression :" << valExpression;
0087             valExpression.remove(')');
0088             debugSheetsODF << " valExpression :" << valExpression;
0089             QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
0090             loadValidationValue(validity, listVal, cell->sheet()->map()->parser());
0091         } else if (valExpression.contains("cell-content-is-in-list(")) {
0092             validity->setRestriction(Validity::List);
0093             valExpression.remove("oooc:cell-content-is-in-list(");
0094             debugSheetsODF << " valExpression :" << valExpression;
0095             valExpression.remove(')');
0096             validity->setValidityList(valExpression.split(';',  QString::SkipEmptyParts));
0097         }
0098         //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
0099         else {
0100             if (valExpression.contains("cell-content-is-whole-number()")) {
0101                 validity->setRestriction(Validity::Number);
0102                 valExpression.remove("oooc:cell-content-is-whole-number() and ");
0103             } else if (valExpression.contains("cell-content-is-decimal-number()")) {
0104                 validity->setRestriction(Validity::Integer);
0105                 valExpression.remove("oooc:cell-content-is-decimal-number() and ");
0106             } else if (valExpression.contains("cell-content-is-date()")) {
0107                 validity->setRestriction(Validity::Date);
0108                 valExpression.remove("oooc:cell-content-is-date() and ");
0109             } else if (valExpression.contains("cell-content-is-time()")) {
0110                 validity->setRestriction(Validity::Time);
0111                 valExpression.remove("oooc:cell-content-is-time() and ");
0112             }
0113             debugSheetsODF << "valExpression :" << valExpression;
0114 
0115             if (valExpression.contains("cell-content()")) {
0116                 valExpression.remove("cell-content()");
0117                 loadValidationCondition(validity, valExpression, cell->sheet()->map()->parser());
0118             }
0119             //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
0120             //for the moment we support just int/double value, not text/date/time :(
0121             if (valExpression.contains("cell-content-is-between(")) {
0122                 valExpression.remove("cell-content-is-between(");
0123                 valExpression.remove(')');
0124                 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
0125                 loadValidationValue(validity, listVal, cell->sheet()->map()->parser());
0126                 validity->setCondition(Conditional::Between);
0127             }
0128             if (valExpression.contains("cell-content-is-not-between(")) {
0129                 valExpression.remove("cell-content-is-not-between(");
0130                 valExpression.remove(')');
0131                 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
0132                 loadValidationValue(validity, listVal, cell->sheet()->map()->parser());
0133                 validity->setCondition(Conditional::Different);
0134             }
0135         }
0136     }
0137     if (element.hasAttributeNS(KoXmlNS::table, "allow-empty-cell")) {
0138         debugSheetsODF << " element.hasAttribute( table:allow-empty-cell ) :" << element.hasAttributeNS(KoXmlNS::table, "allow-empty-cell");
0139         validity->setAllowEmptyCell(((element.attributeNS(KoXmlNS::table, "allow-empty-cell", QString()) == "true") ? true : false));
0140     }
0141     if (element.hasAttributeNS(KoXmlNS::table, "base-cell-address")) {
0142         //todo what is it ?
0143     }
0144 
0145     KoXmlElement help = KoXml::namedItemNS(element, KoXmlNS::table, "help-message");
0146     if (!help.isNull()) {
0147         if (help.hasAttributeNS(KoXmlNS::table, "title")) {
0148             debugSheetsODF << "help.attribute( table:title ) :" << help.attributeNS(KoXmlNS::table, "title", QString());
0149             validity->setTitleInfo(help.attributeNS(KoXmlNS::table, "title", QString()));
0150         }
0151         if (help.hasAttributeNS(KoXmlNS::table, "display")) {
0152             debugSheetsODF << "help.attribute( table:display ) :" << help.attributeNS(KoXmlNS::table, "display", QString());
0153             validity->setDisplayValidationInformation(((help.attributeNS(KoXmlNS::table, "display", QString()) == "true") ? true : false));
0154         }
0155         KoXmlElement attrText = KoXml::namedItemNS(help, KoXmlNS::text, "p");
0156         if (!attrText.isNull()) {
0157             debugSheetsODF << "help text :" << attrText.text();
0158             validity->setMessageInfo(attrText.text());
0159         }
0160     }
0161 
0162     KoXmlElement error = KoXml::namedItemNS(element, KoXmlNS::table, "error-message");
0163     if (!error.isNull()) {
0164         if (error.hasAttributeNS(KoXmlNS::table, "title"))
0165             validity->setTitle(error.attributeNS(KoXmlNS::table, "title", QString()));
0166         if (error.hasAttributeNS(KoXmlNS::table, "message-type")) {
0167             QString str = error.attributeNS(KoXmlNS::table, "message-type", QString());
0168             if (str == "warning")
0169                 validity->setAction(Validity::Warning);
0170             else if (str == "information")
0171                 validity->setAction(Validity::Information);
0172             else if (str == "stop")
0173                 validity->setAction(Validity::Stop);
0174             else
0175                 debugSheetsODF << "validation : message type unknown  :" << str;
0176         }
0177 
0178         if (error.hasAttributeNS(KoXmlNS::table, "display")) {
0179             debugSheetsODF << " display message :" << error.attributeNS(KoXmlNS::table, "display", QString());
0180             validity->setDisplayMessage((error.attributeNS(KoXmlNS::table, "display", QString()) == "true"));
0181         }
0182         KoXmlElement attrText = KoXml::namedItemNS(error, KoXmlNS::text, "p");
0183         if (!attrText.isNull())
0184             validity->setMessage(attrText.text());
0185     }
0186 }
0187 
0188 void Odf::loadValidationValue(Validity *validity, const QStringList &listVal, const ValueParser *parser)
0189 {
0190     bool ok = false;
0191     debugSheetsODF << " listVal[0] :" << listVal[0] << " listVal[1] :" << listVal[1];
0192 
0193     if (validity->restriction() == Validity::Date) {
0194         validity->setMinimumValue(parser->tryParseDate(listVal[0]));
0195         validity->setMaximumValue(parser->tryParseDate(listVal[1]));
0196     } else if (validity->restriction() == Validity::Time) {
0197         validity->setMinimumValue(parser->tryParseTime(listVal[0]));
0198         validity->setMaximumValue(parser->tryParseTime(listVal[1]));
0199     } else {
0200         validity->setMinimumValue(Value(listVal[0].toDouble(&ok)));
0201         if (!ok) {
0202             validity->setMinimumValue(Value(listVal[0].toInt(&ok)));
0203             if (!ok)
0204                 debugSheetsODF << " Try to parse this value :" << listVal[0];
0205 
0206 #if 0
0207             if (!ok)
0208                 validity->setMinimumValue(listVal[0]);
0209 #endif
0210         }
0211         ok = false;
0212         validity->setMaximumValue(Value(listVal[1].toDouble(&ok)));
0213         if (!ok) {
0214             validity->setMaximumValue(Value(listVal[1].toInt(&ok)));
0215             if (!ok)
0216                 debugSheetsODF << " Try to parse this value :" << listVal[1];
0217 
0218 #if 0
0219             if (!ok)
0220                 validity->setMaximumValue(listVal[1]);
0221 #endif
0222         }
0223     }
0224 }
0225 
0226 void Odf::loadValidationCondition(Validity *validity, QString &valExpression, const ValueParser *parser)
0227 {
0228     if (validity->isEmpty()) return;
0229     QString value;
0230     if (valExpression.indexOf("<=") == 0) {
0231         value = valExpression.remove(0, 2);
0232         validity->setCondition(Conditional::InferiorEqual);
0233     } else if (valExpression.indexOf(">=") == 0) {
0234         value = valExpression.remove(0, 2);
0235         validity->setCondition(Conditional::SuperiorEqual);
0236     } else if (valExpression.indexOf("!=") == 0) {
0237         //add Differentto attribute
0238         value = valExpression.remove(0, 2);
0239         validity->setCondition(Conditional::DifferentTo);
0240     } else if (valExpression.indexOf('<') == 0) {
0241         value = valExpression.remove(0, 1);
0242         validity->setCondition(Conditional::Inferior);
0243     } else if (valExpression.indexOf('>') == 0) {
0244         value = valExpression.remove(0, 1);
0245         validity->setCondition(Conditional::Superior);
0246     } else if (valExpression.indexOf('=') == 0) {
0247         value = valExpression.remove(0, 1);
0248         validity->setCondition(Conditional::Equal);
0249     } else
0250         debugSheetsODF << " I don't know how to parse it :" << valExpression;
0251     if (validity->restriction() == Validity::Date) {
0252         validity->setMinimumValue(parser->tryParseDate(value));
0253     } else if (validity->restriction() == Validity::Date) {
0254         validity->setMinimumValue(parser->tryParseTime(value));
0255     } else {
0256         bool ok = false;
0257         validity->setMinimumValue(Value(value.toDouble(&ok)));
0258         if (!ok) {
0259             validity->setMinimumValue(Value(value.toInt(&ok)));
0260             if (!ok)
0261                 debugSheetsODF << " Try to parse this value :" << value;
0262 
0263 #if 0
0264             if (!ok)
0265                 validity->setMinimumValue(value);
0266 #endif
0267         }
0268     }
0269 }
0270 
0271 
0272 }  // Sheets
0273 }  // Calligra