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