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

0001 /* This file is part of the KDE project
0002    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003    Copyright 1998, 1999 Torben Weis <weis@kde.org>
0004    Copyright 1999- 2006 The KSpread Team <calligra-devel@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "SheetsOdf.h"
0023 #include "SheetsOdfPrivate.h"
0024 
0025 #include "Condition.h"
0026 #include "Util.h"
0027 #include "StyleManager.h"
0028 #include "ValueConverter.h"
0029 #include "ValueParser.h"
0030 
0031 #include <KoGenStyles.h>
0032 #include <KoXmlNS.h>
0033 
0034 // This file contains functionality to load/save a Condition
0035 
0036 namespace Calligra {
0037 namespace Sheets {
0038 
0039 namespace Odf {
0040     void loadCondition(QString &valExpression, Conditional &newCondition, const ValueParser *parser);
0041     void loadConditionValue(const QString &styleCondition, Conditional &newCondition, const ValueParser *parser);
0042     void loadValidationValue(const QStringList &listVal, Conditional &newCondition, const ValueParser *parser);
0043     QString saveConditionValue(const Conditional &conditionalStyle, ValueConverter *converter);
0044 }
0045 
0046 void Odf::saveConditions(const Conditions *conditions, KoGenStyle &currentCellStyle, ValueConverter *converter)
0047 {
0048     //todo fix me with kspread old format!!!
0049     if (conditions->isEmpty())
0050         return;
0051     const QLinkedList<Conditional> list = conditions->conditionList();
0052     QLinkedList<Conditional>::const_iterator it;
0053     int i = 0;
0054     for (it = list.begin(); it != list.end(); ++it, ++i) {
0055         Conditional conditional = *it;
0056         //<style:map style:condition="cell-content()=45" style:apply-style-name="Default" style:base-cell-address="Sheet1.E10"/>
0057         QMap<QString, QString> map;
0058         map.insert("style:condition", saveConditionValue(conditional, converter));
0059         map.insert("style:apply-style-name", conditional.styleName);
0060         if (!conditional.baseCellAddress.isEmpty())
0061             map.insert("style:base-cell-address", conditional.baseCellAddress);
0062         currentCellStyle.addStyleMap(map);
0063     }
0064 }
0065 
0066 QString Odf::saveConditionValue(const Conditional &conditional, ValueConverter* converter)
0067 {
0068     //we can also compare text value.
0069     //todo adapt it.
0070     QString v1 = converter->asString(conditional.value1).asStringWithDoubleQuotes();
0071     QString v2 = converter->asString(conditional.value2).asStringWithDoubleQuotes();
0072     QString value;
0073     switch (conditional.cond) {
0074     case Conditional::None:
0075         break;
0076     case Conditional::Equal:
0077         value = "cell-content()=" + v1;
0078         break;
0079     case Conditional::Superior:
0080         value = "cell-content()>" + v1;
0081         break;
0082     case Conditional::Inferior:
0083         value = "cell-content()<" + v1;
0084         break;
0085     case Conditional::SuperiorEqual:
0086         value = "cell-content()>=" + v1;
0087         break;
0088     case Conditional::InferiorEqual:
0089         value = "cell-content()<=" + v1;
0090         break;
0091     case Conditional::Between:
0092         value = "cell-content-is-between(" + v1 + ',' + v2 + ')';
0093         break;
0094     case Conditional::DifferentTo:
0095         value = "cell-content()!=" + v1;
0096         break;
0097     case Conditional::Different:
0098         value = "cell-content-is-not-between(" + v1 + ',' + v2 + ')';
0099         break;
0100     case Conditional::IsTrueFormula:
0101         value = "is-true-formula(" +
0102                 Odf::encodeFormula(conditional.value1.asString()) +
0103                 ')';
0104     }
0105     return value;
0106 }
0107 
0108 Conditional Odf::loadCondition(Conditions *condition, const QString &conditionValue, const QString &applyStyleName,
0109                                          const QString& baseCellAddress, const ValueParser *parser)
0110 {
0111     //debugSheetsODF << "\tcondition:" << conditionValue;
0112     Conditional newCondition;
0113     loadConditionValue(conditionValue, newCondition, parser);
0114     if (!applyStyleName.isNull()) {
0115         //debugSheetsODF << "\tstyle:" << applyStyleName;
0116         newCondition.styleName = applyStyleName;
0117     }
0118     newCondition.baseCellAddress = baseCellAddress;
0119     condition->addCondition(newCondition);
0120     return newCondition;
0121 }
0122 
0123 void Odf::loadConditions(Conditions *condition, const KoXmlElement &element, const ValueParser *parser, const StyleManager *styleManager)
0124 {
0125     debugSheetsODF << "Loading conditional styles";
0126     KoXmlNode node(element);
0127 
0128     while (!node.isNull()) {
0129         KoXmlElement elementItem = node.toElement();
0130         if (elementItem.tagName() == "map" && elementItem.namespaceURI() == KoXmlNS::style) {
0131             QString conditionValue = elementItem.attributeNS(KoXmlNS::style, "condition", QString());
0132             QString applyStyleName;
0133             if (elementItem.hasAttributeNS(KoXmlNS::style, "apply-style-name"))
0134                 applyStyleName = elementItem.attributeNS(KoXmlNS::style, "apply-style-name", QString());
0135             if (!applyStyleName.isEmpty() && styleManager) {
0136                 QString odfStyle = styleManager->openDocumentName(applyStyleName);
0137                 if (!odfStyle.isEmpty()) applyStyleName = odfStyle;
0138             }
0139             QString baseCellAddress = elementItem.attributeNS(KoXmlNS::style, "base-cell-address");
0140             loadCondition(condition, conditionValue, applyStyleName, baseCellAddress, parser);
0141         }
0142         node = node.nextSibling();
0143     }
0144 }
0145 
0146 void Odf::loadConditionValue(const QString &styleCondition, Conditional &newCondition, const ValueParser *parser)
0147 {
0148     QString val(styleCondition);
0149     if (val.contains("cell-content()")) {
0150         val.remove("cell-content()");
0151         loadCondition(val, newCondition, parser);
0152     } else if (val.contains("value()")) {
0153         val.remove("value()");
0154         loadCondition(val, newCondition, parser);
0155     }
0156 
0157     //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
0158     //for the moment we support just int/double value, not text/date/time :(
0159     if (val.contains("cell-content-is-between(")) {
0160         val.remove("cell-content-is-between(");
0161         val.remove(')');
0162         QStringList listVal = val.split(',', QString::SkipEmptyParts);
0163         loadValidationValue(listVal, newCondition, parser);
0164         newCondition.cond = Conditional::Between;
0165     } else if (val.contains("cell-content-is-not-between(")) {
0166         val.remove("cell-content-is-not-between(");
0167         val.remove(')');
0168         QStringList listVal = val.split(',', QString::SkipEmptyParts);
0169         loadValidationValue(listVal, newCondition, parser);
0170         newCondition.cond = Conditional::Different;
0171     } else if (val.startsWith(QLatin1String("is-true-formula("))) {
0172         val.remove(0, 16);
0173         if (val.endsWith(QLatin1Char(')'))) val.chop(1);
0174         newCondition.cond = Conditional::IsTrueFormula;
0175         newCondition.value1 = Value(Odf::decodeFormula(val));
0176     }
0177 }
0178 
0179 void Odf::loadCondition(QString &valExpression, Conditional &newCondition, const ValueParser *parser)
0180 {
0181     QString value;
0182     if (valExpression.indexOf("<=") == 0) {
0183         value = valExpression.remove(0, 2);
0184         newCondition.cond = Conditional::InferiorEqual;
0185     } else if (valExpression.indexOf(">=") == 0) {
0186         value = valExpression.remove(0, 2);
0187         newCondition.cond = Conditional::SuperiorEqual;
0188     } else if (valExpression.indexOf("!=") == 0) {
0189         //add Differentto attribute
0190         value = valExpression.remove(0, 2);
0191         newCondition.cond = Conditional::DifferentTo;
0192     } else if (valExpression.indexOf('<') == 0) {
0193         value = valExpression.remove(0, 1);
0194         newCondition.cond = Conditional::Inferior;
0195     } else if (valExpression.indexOf('>') == 0) {
0196         value = valExpression.remove(0, 1);
0197         newCondition.cond = Conditional::Superior;
0198     } else if (valExpression.indexOf('=') == 0) {
0199         value = valExpression.remove(0, 1);
0200         newCondition.cond = Conditional::Equal;
0201     } else {
0202         warnSheets << " I don't know how to parse it :" << valExpression;
0203     }
0204     //debugSheetsODF << "\tvalue:" << value;
0205 
0206     if (value.length() > 1 && value[0] == '"' && value[value.length()-1] == '"') {
0207         newCondition.value1 = Value(value.mid(1, value.length()-2));
0208     } else {
0209         newCondition.value1 = parser->parse(value);
0210     }
0211 }
0212 
0213 void Odf::loadValidationValue(const QStringList &listVal, Conditional &newCondition, const ValueParser *parser)
0214 {
0215     debugSheetsODF << " listVal[0] :" << listVal[0] << " listVal[1] :" << listVal[1];
0216     newCondition.value1 = parser->parse(listVal[0]);
0217     newCondition.value2 = parser->parse(listVal[1]);
0218 }
0219 
0220 
0221 
0222 
0223 }  // Sheets
0224 }  // Calligra
0225