File indexing completed on 2024-05-12 16:35:15
0001 /* This file is part of the KDE project 0002 Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "Filter.h" 0021 0022 #include <QList> 0023 #include <QRect> 0024 0025 #include <KoXmlNS.h> 0026 #include <KoXmlWriter.h> 0027 0028 #include "CellStorage.h" 0029 #include "Database.h" 0030 #include "Map.h" 0031 #include "Region.h" 0032 #include "Sheet.h" 0033 #include "Value.h" 0034 #include "ValueConverter.h" 0035 #include "odf/SheetsOdf.h" 0036 0037 using namespace Calligra::Sheets; 0038 0039 class Calligra::Sheets::AbstractCondition 0040 { 0041 public: 0042 virtual ~AbstractCondition() {} 0043 enum Type { And, Or, Condition }; 0044 virtual Type type() const = 0; 0045 virtual bool loadOdf(const KoXmlElement& element) = 0; 0046 virtual void saveOdf(KoXmlWriter& xmlWriter) = 0; 0047 virtual bool evaluate(const Database& database, int index) const = 0; 0048 virtual bool isEmpty() const = 0; 0049 virtual QHash<QString, Filter::Comparison> conditions(int fieldNumber) const = 0; 0050 virtual void removeConditions(int fieldNumber) = 0; 0051 virtual QString dump() const = 0; 0052 0053 static bool listsAreEqual(const QList<AbstractCondition*>& a, const QList<AbstractCondition*>& b); 0054 }; 0055 0056 /** 0057 * OpenDocument, 8.7.2 Filter And 0058 */ 0059 class Filter::And : public AbstractCondition 0060 { 0061 public: 0062 And() {} 0063 And(const And& other); 0064 And& operator=(const And& other); 0065 ~And() override { 0066 qDeleteAll(list); 0067 } 0068 Type type() const override { 0069 return AbstractCondition::And; 0070 } 0071 bool loadOdf(const KoXmlElement& parent) override; 0072 void saveOdf(KoXmlWriter& xmlWriter) override { 0073 if (!list.count()) 0074 return; 0075 xmlWriter.startElement("table:filter-and"); 0076 for (int i = 0; i < list.count(); ++i) 0077 list[i]->saveOdf(xmlWriter); 0078 xmlWriter.endElement(); 0079 } 0080 bool evaluate(const Database& database, int index) const override { 0081 for (int i = 0; i < list.count(); ++i) { 0082 // lazy evaluation, stop on first false 0083 if (!list[i]->evaluate(database, index)) 0084 return false; 0085 } 0086 return true; 0087 } 0088 bool isEmpty() const override { 0089 return list.isEmpty(); 0090 } 0091 QHash<QString, Filter::Comparison> conditions(int fieldNumber) const override { 0092 QHash<QString, Filter::Comparison> result; 0093 for (int i = 0; i < list.count(); ++i) 0094 result.unite(list[i]->conditions(fieldNumber)); 0095 return result; 0096 } 0097 void removeConditions(int fieldNumber) override { 0098 QList<AbstractCondition*> newList; 0099 for (int i = 0; i < list.count(); ++i) { 0100 list[i]->removeConditions(fieldNumber); 0101 if (!list[i]->isEmpty()) 0102 newList.append(list[i]); 0103 else 0104 delete list[i]; 0105 } 0106 list = newList; 0107 } 0108 bool operator!=(const And& other) const { 0109 return !listsAreEqual(list, other.list); 0110 } 0111 QString dump() const override { 0112 QString result = "\t"; 0113 for (int i = 0; i < list.count(); ++i) { 0114 if (i) 0115 result += "AND\t"; 0116 result += list[i]->dump(); 0117 } 0118 return result; 0119 } 0120 0121 public: 0122 QList<AbstractCondition*> list; // allowed: Or or Condition 0123 }; 0124 0125 /** 0126 * OpenDocument, 8.7.3 Filter Or 0127 */ 0128 class Filter::Or : public AbstractCondition 0129 { 0130 public: 0131 Or() {} 0132 Or(const Or& other); 0133 Or& operator=(const Or& other); 0134 ~Or() override { 0135 qDeleteAll(list); 0136 } 0137 Type type() const override { 0138 return AbstractCondition::Or; 0139 } 0140 bool loadOdf(const KoXmlElement& element) override; 0141 void saveOdf(KoXmlWriter& xmlWriter) override { 0142 if (!list.count()) 0143 return; 0144 xmlWriter.startElement("table:filter-or"); 0145 for (int i = 0; i < list.count(); ++i) 0146 list[i]->saveOdf(xmlWriter); 0147 xmlWriter.endElement(); 0148 } 0149 bool evaluate(const Database& database, int index) const override { 0150 for (int i = 0; i < list.count(); ++i) { 0151 // lazy evaluation, stop on first true 0152 if (list[i]->evaluate(database, index)) 0153 return true; 0154 } 0155 return false; 0156 } 0157 bool isEmpty() const override { 0158 return list.isEmpty(); 0159 } 0160 QHash<QString, Filter::Comparison> conditions(int fieldNumber) const override { 0161 QHash<QString, Filter::Comparison> result; 0162 for (int i = 0; i < list.count(); ++i) 0163 result.unite(list[i]->conditions(fieldNumber)); 0164 return result; 0165 } 0166 void removeConditions(int fieldNumber) override { 0167 QList<AbstractCondition*> newList; 0168 for (int i = 0; i < list.count(); ++i) { 0169 list[i]->removeConditions(fieldNumber); 0170 if (!list[i]->isEmpty()) 0171 newList.append(list[i]); 0172 else 0173 delete list[i]; 0174 } 0175 list = newList; 0176 } 0177 bool operator!=(const Or& other) const { 0178 return !listsAreEqual(list, other.list); 0179 } 0180 QString dump() const override { 0181 QString result = "\t"; 0182 for (int i = 0; i < list.count(); ++i) { 0183 if (i) 0184 result += "OR\t"; 0185 result += list[i]->dump(); 0186 } 0187 return result; 0188 } 0189 0190 public: 0191 QList<AbstractCondition*> list; // allowed: And or Condition 0192 }; 0193 0194 /** 0195 * OpenDocument, 8.7.4 Filter Condition 0196 */ 0197 class Filter::Condition : public AbstractCondition 0198 { 0199 public: 0200 Condition() 0201 : fieldNumber(-1) 0202 , operation(Match) 0203 , caseSensitivity(Qt::CaseInsensitive) 0204 , dataType(Text) { 0205 } 0206 Condition(int _fieldNumber, Comparison _comparison, const QString& _value, 0207 Qt::CaseSensitivity _caseSensitivity, Mode _mode) 0208 : fieldNumber(_fieldNumber) 0209 , value(_value) 0210 , operation(_comparison) 0211 , caseSensitivity(_caseSensitivity) 0212 , dataType(_mode) { 0213 } 0214 Condition(const Condition& other) 0215 : AbstractCondition() 0216 , fieldNumber(other.fieldNumber) 0217 , value(other.value) 0218 , operation(other.operation) 0219 , caseSensitivity(other.caseSensitivity) 0220 , dataType(other.dataType) { 0221 } 0222 Condition& operator=(const Condition& other); 0223 ~Condition() override {} 0224 0225 Type type() const override { 0226 return AbstractCondition::Condition; 0227 } 0228 bool loadOdf(const KoXmlElement& element) override { 0229 if (element.hasAttributeNS(KoXmlNS::table, "field-number")) { 0230 bool ok = false; 0231 fieldNumber = element.attributeNS(KoXmlNS::table, "field-number", QString()).toInt(&ok); 0232 if (!ok || fieldNumber < 0) 0233 return false; 0234 } 0235 if (element.hasAttributeNS(KoXmlNS::table, "value")) 0236 value = element.attributeNS(KoXmlNS::table, "value", QString()); 0237 if (element.hasAttributeNS(KoXmlNS::table, "operator")) { 0238 const QString string = element.attributeNS(KoXmlNS::table, "operator", QString()); 0239 if (string == "match") 0240 operation = Match; 0241 else if (string == "!match") 0242 operation = NotMatch; 0243 else if (string == "=") 0244 operation = Equal; 0245 else if (string == "!=") 0246 operation = NotEqual; 0247 else if (string == "<") 0248 operation = Less; 0249 else if (string == ">") 0250 operation = Greater; 0251 else if (string == "<=") 0252 operation = LessOrEqual; 0253 else if (string == ">=") 0254 operation = GreaterOrEqual; 0255 else if (string == "empty") 0256 operation = Empty; 0257 else if (string == "!empty") 0258 operation = NotEmpty; 0259 else if (string == "top values") 0260 operation = TopValues; 0261 else if (string == "bottom values") 0262 operation = BottomValues; 0263 else if (string == "top percent") 0264 operation = TopPercent; 0265 else if (string == "bottom percent") 0266 operation = BottomPercent; 0267 else { 0268 debugSheets << "table:operator: unknown value"; 0269 return false; 0270 } 0271 } 0272 if (element.hasAttributeNS(KoXmlNS::table, "case-sensitive")) { 0273 if (element.attributeNS(KoXmlNS::table, "case-sensitive", "false") == "true") 0274 caseSensitivity = Qt::CaseSensitive; 0275 else 0276 caseSensitivity = Qt::CaseInsensitive; 0277 } 0278 if (element.hasAttributeNS(KoXmlNS::table, "data-type")) { 0279 if (element.attributeNS(KoXmlNS::table, "data-type", "text") == "number") 0280 dataType = Number; 0281 else 0282 dataType = Text; 0283 } 0284 return true; 0285 } 0286 void saveOdf(KoXmlWriter& xmlWriter) override { 0287 if (fieldNumber < 0) 0288 return; 0289 xmlWriter.startElement("table:filter-condition"); 0290 xmlWriter.addAttribute("table:field-number", fieldNumber); 0291 xmlWriter.addAttribute("table:value", value); 0292 switch (operation) { 0293 case Match: 0294 xmlWriter.addAttribute("table:operator", "match"); 0295 break; 0296 case NotMatch: 0297 xmlWriter.addAttribute("table:operator", "!match"); 0298 break; 0299 case Equal: 0300 xmlWriter.addAttribute("table:operator", "="); 0301 break; 0302 case NotEqual: 0303 xmlWriter.addAttribute("table:operator", "!="); 0304 break; 0305 case Less: 0306 xmlWriter.addAttribute("table:operator", "<"); 0307 break; 0308 case Greater: 0309 xmlWriter.addAttribute("table:operator", ">"); 0310 break; 0311 case LessOrEqual: 0312 xmlWriter.addAttribute("table:operator", "<="); 0313 break; 0314 case GreaterOrEqual: 0315 xmlWriter.addAttribute("table:operator", ">="); 0316 break; 0317 case Empty: 0318 xmlWriter.addAttribute("table:operator", "empty"); 0319 break; 0320 case NotEmpty: 0321 xmlWriter.addAttribute("table:operator", "!empty"); 0322 break; 0323 case TopValues: 0324 xmlWriter.addAttribute("table:operator", "top values"); 0325 break; 0326 case BottomValues: 0327 xmlWriter.addAttribute("table:operator", "bottom values"); 0328 break; 0329 case TopPercent: 0330 xmlWriter.addAttribute("table:operator", "top percent"); 0331 break; 0332 case BottomPercent: 0333 xmlWriter.addAttribute("table:operator", "bottom percent"); 0334 break; 0335 } 0336 if (caseSensitivity == Qt::CaseSensitive) 0337 xmlWriter.addAttribute("table:case-sensitive", true); 0338 if (dataType == Number) 0339 xmlWriter.addAttribute("table:data-type", "number"); 0340 xmlWriter.endElement(); 0341 } 0342 bool evaluate(const Database& database, int index) const override { 0343 const Sheet* sheet = database.range().lastSheet(); 0344 const QRect range = database.range().lastRange(); 0345 const int start = database.orientation() == Qt::Vertical ? range.left() : range.top(); 0346 // debugSheets <<"index:" << index <<" start:" << start <<" fieldNumber:" << fieldNumber; 0347 const Value value = database.orientation() == Qt::Vertical 0348 ? sheet->cellStorage()->value(start + fieldNumber, index) 0349 : sheet->cellStorage()->value(index, start + fieldNumber); 0350 const QString testString = sheet->map()->converter()->asString(value).asString(); 0351 switch (operation) { 0352 case Match: { 0353 const bool result = QString::compare(this->value, testString, caseSensitivity) == 0; 0354 // debugSheets <<"Match" << this->value <<"?" << testString <<"" << result; 0355 if (result) 0356 return true; 0357 break; 0358 } 0359 case NotMatch: { 0360 const bool result = QString::compare(this->value, testString, caseSensitivity) != 0; 0361 // debugSheets <<"Not Match" << this->value <<"?" << testString <<"" << result; 0362 if (result) 0363 return true; 0364 break; 0365 } 0366 default: 0367 break; 0368 } 0369 return false; 0370 } 0371 bool isEmpty() const override { 0372 return fieldNumber == -1; 0373 } 0374 QHash<QString, Filter::Comparison> conditions(int fieldNumber) const override { 0375 QHash<QString, Filter::Comparison> result; 0376 if (this->fieldNumber == fieldNumber) 0377 result.insert(value, operation); 0378 return result; 0379 } 0380 void removeConditions(int fieldNumber) override { 0381 if (this->fieldNumber == fieldNumber) { 0382 // debugSheets <<"removing condition for fieldNumber" << fieldNumber; 0383 this->fieldNumber = -1; 0384 } 0385 } 0386 bool operator==(const Condition& other) const { 0387 if (fieldNumber != other.fieldNumber) 0388 return false; 0389 if (value != other.value) 0390 return false; 0391 if (operation != other.operation) 0392 return false; 0393 if (caseSensitivity != other.caseSensitivity) 0394 return false; 0395 if (dataType != other.dataType) 0396 return false; 0397 return true; 0398 } 0399 bool operator!=(const Condition& other) const { 0400 return !operator==(other); 0401 } 0402 QString dump() const override { 0403 QString result = QString("fieldNumber: %1 ").arg(fieldNumber); 0404 switch (operation) { 0405 case Match: result += "Match"; break; 0406 case NotMatch: result += "Not Match"; break; 0407 default: break; 0408 } 0409 return result + " value: " + value + '\n'; 0410 } 0411 0412 public: 0413 int fieldNumber; 0414 QString value; // Value? 0415 Comparison operation; 0416 Qt::CaseSensitivity caseSensitivity; 0417 Mode dataType; 0418 }; 0419 0420 Filter::And::And(const And& other) 0421 : AbstractCondition() 0422 { 0423 for (int i = 0; i < other.list.count(); ++i) { 0424 if (!other.list[i]) 0425 continue; 0426 else if (other.list[i]->type() == AbstractCondition::And) 0427 list.append(new Filter::And(*static_cast<Filter::And*>(other.list[i]))); 0428 else if (other.list[i]->type() == AbstractCondition::Or) 0429 list.append(new Filter::Or(*static_cast<Filter::Or*>(other.list[i]))); 0430 else 0431 list.append(new Filter::Condition(*static_cast<Filter::Condition*>(other.list[i]))); 0432 } 0433 } 0434 0435 bool Filter::And::loadOdf(const KoXmlElement& parent) 0436 { 0437 KoXmlElement element; 0438 AbstractCondition* condition; 0439 forEachElement(element, parent) { 0440 if (element.namespaceURI() != KoXmlNS::table) 0441 continue; 0442 if (element.localName() == "filter-or") 0443 condition = new Filter::Or(); 0444 else if (element.localName() == "filter-condition") 0445 condition = new Filter::Condition(); 0446 else 0447 continue; 0448 if (condition->loadOdf(element)) 0449 list.append(condition); 0450 else 0451 delete condition; 0452 } 0453 return !list.isEmpty(); 0454 } 0455 0456 Filter::Or::Or(const Or& other) 0457 : AbstractCondition() 0458 { 0459 for (int i = 0; i < other.list.count(); ++i) { 0460 if (!other.list[i]) 0461 continue; 0462 else if (other.list[i]->type() == AbstractCondition::And) 0463 list.append(new Filter::And(*static_cast<Filter::And*>(other.list[i]))); 0464 else if (other.list[i]->type() == AbstractCondition::Or) 0465 list.append(new Filter::Or(*static_cast<Filter::Or*>(other.list[i]))); 0466 else 0467 list.append(new Filter::Condition(*static_cast<Filter::Condition*>(other.list[i]))); 0468 } 0469 } 0470 0471 bool Filter::Or::loadOdf(const KoXmlElement& parent) 0472 { 0473 KoXmlElement element; 0474 AbstractCondition* condition; 0475 forEachElement(element, parent) { 0476 if (element.namespaceURI() != KoXmlNS::table) 0477 continue; 0478 if (element.localName() == "filter-and") 0479 condition = new Filter::And(); 0480 else if (element.localName() == "filter-condition") 0481 condition = new Filter::Condition(); 0482 else 0483 continue; 0484 if (condition->loadOdf(element)) 0485 list.append(condition); 0486 else 0487 delete condition; 0488 } 0489 return !list.isEmpty(); 0490 } 0491 0492 0493 class Q_DECL_HIDDEN Filter::Private 0494 { 0495 public: 0496 Private() 0497 : condition(0) 0498 , conditionSource(Self) 0499 , displayDuplicates(true) { 0500 } 0501 0502 AbstractCondition* condition; 0503 Region targetRangeAddress; 0504 enum { Self, CellRange } conditionSource; 0505 Region conditionSourceRangeAddress; 0506 bool displayDuplicates; 0507 }; 0508 0509 Filter::Filter() 0510 : d(new Private) 0511 { 0512 } 0513 0514 Filter::Filter(const Filter& other) 0515 : d(new Private) 0516 { 0517 if (!other.d->condition) 0518 d->condition = 0; 0519 else if (other.d->condition->type() == AbstractCondition::And) 0520 d->condition = new And(*static_cast<And*>(other.d->condition)); 0521 else if (other.d->condition->type() == AbstractCondition::Or) 0522 d->condition = new Or(*static_cast<Or*>(other.d->condition)); 0523 else 0524 d->condition = new Condition(*static_cast<Condition*>(other.d->condition)); 0525 d->targetRangeAddress = other.d->targetRangeAddress; 0526 d->conditionSource = other.d->conditionSource; 0527 d->conditionSourceRangeAddress = other.d->conditionSourceRangeAddress; 0528 d->displayDuplicates = other.d->displayDuplicates; 0529 } 0530 0531 Filter::~Filter() 0532 { 0533 delete d->condition; 0534 delete d; 0535 } 0536 0537 void Filter::addCondition(Composition composition, 0538 int fieldNumber, Comparison comparison, const QString& value, 0539 Qt::CaseSensitivity caseSensitivity, Mode mode) 0540 { 0541 Condition* condition = new Condition(fieldNumber, comparison, value, caseSensitivity, mode); 0542 if (!d->condition) { 0543 d->condition = condition; 0544 } else if (composition == AndComposition) { 0545 if (d->condition->type() == AbstractCondition::And) { 0546 static_cast<And*>(d->condition)->list.append(condition); 0547 } else { 0548 And* andComposition = new And(); 0549 andComposition->list.append(d->condition); 0550 andComposition->list.append(condition); 0551 d->condition = andComposition; 0552 } 0553 } else { // composition == OrComposition 0554 if (d->condition->type() == AbstractCondition::Or) { 0555 static_cast<Or*>(d->condition)->list.append(condition); 0556 } else { 0557 Or* orComposition = new Or(); 0558 orComposition->list.append(d->condition); 0559 orComposition->list.append(condition); 0560 d->condition = orComposition; 0561 } 0562 } 0563 } 0564 0565 QList<AbstractCondition*> Filter::copyList(const QList<AbstractCondition*>& list) 0566 { 0567 QList<AbstractCondition*> out; 0568 foreach (AbstractCondition* c, list) { 0569 if (!c) { 0570 continue; 0571 } else if (c->type() == AbstractCondition::And) { 0572 out.append(new Filter::And(*static_cast<Filter::And*>(c))); 0573 } else if (c->type() == AbstractCondition::Or) { 0574 out.append(new Filter::Or(*static_cast<Filter::Or*>(c))); 0575 } else { 0576 out.append(new Filter::Condition(*static_cast<Filter::Condition*>(c))); 0577 } 0578 } 0579 return out; 0580 } 0581 0582 void Filter::addSubFilter(Composition composition, const Filter& filter) 0583 { 0584 if (!d->condition) { 0585 if (!filter.d->condition) 0586 d->condition = 0; 0587 else if (filter.d->condition->type() == AbstractCondition::And) 0588 d->condition = new And(*static_cast<And*>(filter.d->condition)); 0589 else if (filter.d->condition->type() == AbstractCondition::Or) 0590 d->condition = new Or(*static_cast<Or*>(filter.d->condition)); 0591 else // if (filter.d->condition->type() == AbstractCondition::Condition) 0592 d->condition = new Condition(*static_cast<Condition*>(filter.d->condition)); 0593 } else if (composition == AndComposition) { 0594 if (filter.d->condition && d->condition->type() == AbstractCondition::And) { 0595 if (filter.d->condition->type() == AbstractCondition::And) 0596 static_cast<And*>(d->condition)->list += copyList(static_cast<And*>(filter.d->condition)->list); 0597 else if (filter.d->condition->type() == AbstractCondition::Or) 0598 static_cast<And*>(d->condition)->list.append(new Or(*static_cast<Or*>(filter.d->condition))); 0599 else // if (filter.d->condition->type() == AbstractCondition::Condition) 0600 static_cast<And*>(d->condition)->list.append(new Condition(*static_cast<Condition*>(filter.d->condition))); 0601 } else if (filter.d->condition) { 0602 And* andComposition = new And(); 0603 andComposition->list.append(d->condition); 0604 if (filter.d->condition->type() == AbstractCondition::And) 0605 andComposition->list += copyList(static_cast<And*>(filter.d->condition)->list); 0606 else if (filter.d->condition->type() == AbstractCondition::Or) 0607 andComposition->list.append(new Or(*static_cast<Or*>(filter.d->condition))); 0608 else // if (filter.d->condition->type() == AbstractCondition::Condition) 0609 andComposition->list.append(new Condition(*static_cast<Condition*>(filter.d->condition))); 0610 d->condition = andComposition; 0611 } 0612 } else { // composition == OrComposition 0613 if (filter.d->condition && d->condition->type() == AbstractCondition::Or) { 0614 if (filter.d->condition->type() == AbstractCondition::And) 0615 static_cast<Or*>(d->condition)->list.append(new And(*static_cast<And*>(filter.d->condition))); 0616 else if (filter.d->condition->type() == AbstractCondition::Or) 0617 static_cast<Or*>(d->condition)->list += copyList(static_cast<Or*>(filter.d->condition)->list); 0618 else // if (filter.d->condition->type() == AbstractCondition::Condition) 0619 static_cast<Or*>(d->condition)->list.append(new Condition(*static_cast<Condition*>(filter.d->condition))); 0620 } else if (filter.d->condition) { 0621 Or* orComposition = new Or(); 0622 orComposition->list.append(d->condition); 0623 if (filter.d->condition->type() == AbstractCondition::And) 0624 orComposition->list.append(new And(*static_cast<And*>(filter.d->condition))); 0625 else if (filter.d->condition->type() == AbstractCondition::Or) 0626 orComposition->list += copyList(static_cast<Or*>(filter.d->condition)->list); 0627 else // if (filter.d->condition->type() == AbstractCondition::Condition) 0628 orComposition->list.append(new Condition(*static_cast<Condition*>(filter.d->condition))); 0629 d->condition = orComposition; 0630 } 0631 } 0632 } 0633 0634 QHash<QString, Filter::Comparison> Filter::conditions(int fieldNumber) const 0635 { 0636 return d->condition ? d->condition->conditions(fieldNumber) : QHash<QString, Comparison>(); 0637 } 0638 0639 void Filter::removeConditions(int fieldNumber) 0640 { 0641 if (fieldNumber == -1) { 0642 // debugSheets <<"removing all conditions"; 0643 delete d->condition; 0644 d->condition = 0; 0645 return; 0646 } 0647 if (!d->condition) 0648 return; 0649 d->condition->removeConditions(fieldNumber); 0650 if (d->condition->isEmpty()) { 0651 delete d->condition; 0652 d->condition = 0; 0653 } 0654 } 0655 0656 bool Filter::isEmpty() const 0657 { 0658 return d->condition ? d->condition->isEmpty() : true; 0659 } 0660 0661 bool Filter::evaluate(const Database& database, int index) const 0662 { 0663 return d->condition ? d->condition->evaluate(database, index) : true; 0664 } 0665 0666 bool Filter::loadOdf(const KoXmlElement& element, const Map* map) 0667 { 0668 if (element.hasAttributeNS(KoXmlNS::table, "target-range-address")) { 0669 const QString address = element.attributeNS(KoXmlNS::table, "target-range-address", QString()); 0670 // only absolute addresses allowed; no fallback sheet needed 0671 d->targetRangeAddress = Region(Odf::loadRegion(address), map); 0672 if (!d->targetRangeAddress.isValid()) 0673 return false; 0674 } 0675 if (element.hasAttributeNS(KoXmlNS::table, "condition-source")) { 0676 if (element.attributeNS(KoXmlNS::table, "condition-source", "self") == "cell-range") 0677 d->conditionSource = Private::CellRange; 0678 else 0679 d->conditionSource = Private::Self; 0680 } 0681 if (element.hasAttributeNS(KoXmlNS::table, "condition-source-range-address")) { 0682 const QString address = element.attributeNS(KoXmlNS::table, "condition-source-range-address", QString()); 0683 // only absolute addresses allowed; no fallback sheet needed 0684 d->conditionSourceRangeAddress = Region(Odf::loadRegion(address), map); 0685 } 0686 if (element.hasAttributeNS(KoXmlNS::table, "display-duplicates")) { 0687 if (element.attributeNS(KoXmlNS::table, "display-duplicates", "true") == "false") 0688 d->displayDuplicates = false; 0689 else 0690 d->displayDuplicates = true; 0691 } 0692 KoXmlElement conditionElement; 0693 forEachElement(conditionElement, element) { 0694 if (conditionElement.localName() == "filter-and") { 0695 d->condition = new And(); 0696 break; 0697 } else if (conditionElement.localName() == "filter-or") { 0698 d->condition = new Or(); 0699 break; 0700 } else if (conditionElement.localName() == "filter-condition") { 0701 d->condition = new Condition(); 0702 break; 0703 } 0704 } 0705 if (!d->condition) 0706 return false; 0707 if (!d->condition->loadOdf(conditionElement.toElement())) { 0708 delete d->condition; 0709 d->condition = 0; 0710 return false; 0711 } 0712 return true; 0713 } 0714 0715 void Filter::saveOdf(KoXmlWriter& xmlWriter) const 0716 { 0717 if (!d->condition) 0718 return; 0719 xmlWriter.startElement("table:filter"); 0720 if (!d->targetRangeAddress.isEmpty()) 0721 xmlWriter.addAttribute("table:target-range-address", Odf::saveRegion(d->targetRangeAddress.name())); 0722 if (d->conditionSource != Private::Self) 0723 xmlWriter.addAttribute("table:condition-source", "cell-range"); 0724 if (!d->conditionSourceRangeAddress.isEmpty()) 0725 xmlWriter.addAttribute("table:condition-source-range-address", Odf::saveRegion(d->conditionSourceRangeAddress.name())); 0726 if (!d->displayDuplicates) 0727 xmlWriter.addAttribute("table:display-duplicates", "false"); 0728 d->condition->saveOdf(xmlWriter); 0729 xmlWriter.endElement(); 0730 } 0731 0732 bool Filter::conditionsEquals(AbstractCondition* a, AbstractCondition* b) 0733 { 0734 if (!a || !b) 0735 return a == b; 0736 if (a->type() != b->type()) 0737 return false; 0738 if (a->type() == AbstractCondition::And && *static_cast<And*>(a) != *static_cast<And*>(b)) 0739 return false; 0740 if (a->type() == AbstractCondition::Or && *static_cast<Or*>(a) != *static_cast<Or*>(b)) 0741 return false; 0742 if (a->type() == AbstractCondition::Condition && *static_cast<Condition*>(a) != *static_cast<Condition*>(b)) 0743 return false; 0744 return true; 0745 } 0746 0747 bool Filter::operator==(const Filter& other) const 0748 { 0749 if (d->targetRangeAddress != other.d->targetRangeAddress) 0750 return false; 0751 if (d->conditionSource != other.d->conditionSource) 0752 return false; 0753 if (d->conditionSourceRangeAddress != other.d->conditionSourceRangeAddress) 0754 return false; 0755 if (d->displayDuplicates != other.d->displayDuplicates) 0756 return false; 0757 return conditionsEquals(d->condition, other.d->condition); 0758 } 0759 0760 void Filter::dump() const 0761 { 0762 if (d->condition) 0763 debugSheets << "Condition:" + d->condition->dump(); 0764 else 0765 debugSheets << "Condition: 0"; 0766 } 0767 0768 bool AbstractCondition::listsAreEqual(const QList<AbstractCondition *> &a, const QList<AbstractCondition *> &b) 0769 { 0770 if (a.size() != b.size()) return false; 0771 for (int i = 0; i < a.size(); i++) { 0772 if (!Filter::conditionsEquals(a[i], b[i])) 0773 return false; 0774 } 0775 return true; 0776 }