1/* This file is part of the KDE project
2 Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20// Local
21#include "Validity.h"
22
23// KDE
24#include <kmessagebox.h>
25
26// Calligra
27#include <KoXmlReader.h>
28#include <KoXmlNS.h>
29
30// KSpread
31#include "CalculationSettings.h"
32#include "Cell.h"
33#include "Map.h"
34#include "OdfLoadingContext.h"
35#include "Sheet.h"
36#include "Value.h"
37#include "ValueCalc.h"
38#include "ValueConverter.h"
39#include "ValueParser.h"
40
41using namespace Calligra::Sheets;
42
43class Validity::Private : public QSharedData
44{
45public:
46 QString message;
47 QString title;
48 QString titleInfo;
49 QString messageInfo;
50 Value minValue;
51 Value maxValue;
52 Conditional::Type cond;
53 Action action;
54 Restriction restriction;
55 bool displayMessage;
56 bool allowEmptyCell;
57 bool displayValidationInformation;
58 QStringList listValidity;
59};
60
61Validity::Validity()
62 : d(new Private)
63{
64 d->cond = Conditional::None;
65 d->action = Stop;
66 d->restriction = None;
67 d->displayMessage = true;
68 d->allowEmptyCell = false;
69 d->displayValidationInformation = false;
70}
71
72Validity::Validity(const Validity& other)
73 : d(other.d)
74{
75}
76
77Validity::~Validity()
78{
79}
80
81bool Validity::isEmpty() const
82{
83 return d->restriction == None;
84}
85
86bool Validity::loadXML(Cell* const cell, const KoXmlElement& validityElement)
87{
88 ValueParser *const parser = cell->sheet()->map()->parser();
89 bool ok = false;
90 KoXmlElement param = validityElement.namedItem("param").toElement();
91 if (!param.isNull()) {
92 if (param.hasAttribute("cond")) {
93 d->cond = (Conditional::Type) param.attribute("cond").toInt(&ok);
94 if (!ok)
95 return false;
96 }
97 if (param.hasAttribute("action")) {
98 d->action = (Action) param.attribute("action").toInt(&ok);
99 if (!ok)
100 return false;
101 }
102 if (param.hasAttribute("allow")) {
103 d->restriction = (Restriction) param.attribute("allow").toInt(&ok);
104 if (!ok)
105 return false;
106 }
107 if (param.hasAttribute("valmin")) {
108 d->minValue = parser->tryParseNumber(param.attribute("valmin"), &ok);
109 if (!ok)
110 return false;
111 }
112 if (param.hasAttribute("valmax")) {
113 d->maxValue = parser->tryParseNumber(param.attribute("valmax"), &ok);
114 if (!ok)
115 return false;
116 }
117 if (param.hasAttribute("displaymessage")) {
118 d->displayMessage = (bool)param.attribute("displaymessage").toInt();
119 }
120 if (param.hasAttribute("displayvalidationinformation")) {
121 d->displayValidationInformation = (bool)param.attribute("displayvalidationinformation").toInt();
122 }
123 if (param.hasAttribute("allowemptycell")) {
124 d->allowEmptyCell = (bool)param.attribute("allowemptycell").toInt();
125 }
126 if (param.hasAttribute("listvalidity")) {
127 d->listValidity = param.attribute("listvalidity").split(';', QString::SkipEmptyParts);
128 }
129 }
130 KoXmlElement inputTitle = validityElement.namedItem("inputtitle").toElement();
131 if (!inputTitle.isNull()) {
132 d->titleInfo = inputTitle.text();
133 }
134 KoXmlElement inputMessage = validityElement.namedItem("inputmessage").toElement();
135 if (!inputMessage.isNull()) {
136 d->messageInfo = inputMessage.text();
137 }
138
139 KoXmlElement titleElement = validityElement.namedItem("title").toElement();
140 if (!titleElement.isNull()) {
141 d->title = titleElement.text();
142 }
143 KoXmlElement messageElement = validityElement.namedItem("message").toElement();
144 if (!messageElement.isNull()) {
145 d->message = messageElement.text();
146 }
147 KoXmlElement timeMinElement = validityElement.namedItem("timemin").toElement();
148 if (!timeMinElement.isNull()) {
149 d->minValue = parser->tryParseTime(timeMinElement.text());
150 }
151 KoXmlElement timeMaxElement = validityElement.namedItem("timemax").toElement();
152 if (!timeMaxElement.isNull()) {
153 d->maxValue = parser->tryParseTime(timeMaxElement.text());
154 }
155 KoXmlElement dateMinElement = validityElement.namedItem("datemin").toElement();
156 if (!dateMinElement.isNull()) {
157 d->minValue = parser->tryParseTime(dateMinElement.text());
158 }
159 KoXmlElement dateMaxElement = validityElement.namedItem("datemax").toElement();
160 if (!dateMaxElement.isNull()) {
161 d->maxValue = parser->tryParseTime(dateMaxElement.text());
162 }
163 return true;
164}
165
166QDomElement Validity::saveXML(QDomDocument& doc, const ValueConverter *converter) const
167{
168 QDomElement validityElement = doc.createElement("validity");
169
170 QDomElement param = doc.createElement("param");
171 param.setAttribute("cond", (int)d->cond);
172 param.setAttribute("action", (int)d->action);
173 param.setAttribute("allow", (int)d->restriction);
174 param.setAttribute("valmin", converter->asString(d->minValue).asString());
175 param.setAttribute("valmax", converter->asString(d->maxValue).asString());
176 param.setAttribute("displaymessage", d->displayMessage);
177 param.setAttribute("displayvalidationinformation", d->displayValidationInformation);
178 param.setAttribute("allowemptycell", d->allowEmptyCell);
179 if (!d->listValidity.isEmpty())
180 param.setAttribute("listvalidity", d->listValidity.join(";"));
181 validityElement.appendChild(param);
182 QDomElement titleElement = doc.createElement("title");
183 titleElement.appendChild(doc.createTextNode(d->title));
184 validityElement.appendChild(titleElement);
185 QDomElement messageElement = doc.createElement("message");
186 messageElement.appendChild(doc.createCDATASection(d->message));
187 validityElement.appendChild(messageElement);
188
189 QDomElement inputTitle = doc.createElement("inputtitle");
190 inputTitle.appendChild(doc.createTextNode(d->titleInfo));
191 validityElement.appendChild(inputTitle);
192
193 QDomElement inputMessage = doc.createElement("inputmessage");
194 inputMessage.appendChild(doc.createTextNode(d->messageInfo));
195 validityElement.appendChild(inputMessage);
196
197
198
199 QString tmp;
200 if (d->restriction == Time) {
201 QDomElement timeMinElement = doc.createElement("timemin");
202 tmp = converter->asString(d->minValue).asString();
203 timeMinElement.appendChild(doc.createTextNode(tmp));
204 validityElement.appendChild(timeMinElement);
205
206 if (d->cond == Conditional::Between || d->cond == Conditional::Different) {
207 QDomElement timeMaxElement = doc.createElement("timemax");
208 tmp = converter->asString(d->maxValue).asString();
209 timeMaxElement.appendChild(doc.createTextNode(tmp));
210 validityElement.appendChild(timeMaxElement);
211 }
212 }
213
214 if (d->restriction == Date) {
215 QDomElement dateMinElement = doc.createElement("datemin");
216 const QDate minDate = d->minValue.asDate(converter->settings());
217 QString tmp("%1/%2/%3");
218 tmp = tmp.arg(minDate.year()).arg(minDate.month()).arg(minDate.day());
219 dateMinElement.appendChild(doc.createTextNode(tmp));
220 validityElement.appendChild(dateMinElement);
221
222 if (d->cond == Conditional::Between || d->cond == Conditional::Different) {
223 QDomElement dateMaxElement = doc.createElement("datemax");
224 const QDate maxDate = d->maxValue.asDate(converter->settings());
225 QString tmp("%1/%2/%3");
226 tmp = tmp.arg(maxDate.year()).arg(maxDate.month()).arg(maxDate.day());
227 dateMaxElement.appendChild(doc.createTextNode(tmp));
228 validityElement.appendChild(dateMaxElement);
229 }
230 }
231 return validityElement;
232}
233
234
235void Validity::loadOdfValidation(Cell* const cell, const QString& validationName,
236 OdfLoadingContext& tableContext)
237{
238 KoXmlElement element = tableContext.validities.value(validationName);
239 Validity validity;
240 if (element.hasAttributeNS(KoXmlNS::table, "condition")) {
241 QString valExpression = element.attributeNS(KoXmlNS::table, "condition", QString());
242 kDebug(36003) << " element.attribute( table:condition )" << valExpression;
243 //Condition ::= ExtendedTrueCondition | TrueFunction 'and' TrueCondition
244 //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
245 //ExtendedTrueCondition ::= ExtendedGetFunction | cell-content-text-length() Operator Value
246 //TrueCondition ::= GetFunction | cell-content() Operator Value
247 //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
248 //ExtendedGetFunction ::= cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value)
249 //Operator ::= '<' | '>' | '<=' | '>=' | '=' | '!='
250 //Value ::= NumberValue | String | Formula
251 //A Formula is a formula without an equals (=) sign at the beginning. See section 8.1.3 for more information.
252 //A String comprises one or more characters surrounded by quotation marks.
253 //A NumberValue is a whole or decimal number. It must not contain comma separators for numbers of 1000 or greater.
254
255 //ExtendedTrueCondition
256 if (valExpression.contains("cell-content-text-length()")) {
257 //"cell-content-text-length()>45"
258 valExpression = valExpression.remove("oooc:cell-content-text-length()");
259 kDebug(36003) << " valExpression = :" << valExpression;
260 setRestriction(Validity::TextLength);
261
262 loadOdfValidationCondition(valExpression, cell->sheet()->map()->parser());
263 } else if (valExpression.contains("cell-content-is-text()")) {
264 setRestriction(Validity::Text);
265 }
266 //cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value) | cell-content-is-in-list( StringList )
267 else if (valExpression.contains("cell-content-text-length-is-between")) {
268 setRestriction(Validity::TextLength);
269 setCondition(Conditional::Between);
270 valExpression.remove("oooc:cell-content-text-length-is-between(");
271 kDebug(36003) << " valExpression :" << valExpression;
272 valExpression.remove(')');
273 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
274 loadOdfValidationValue(listVal, cell->sheet()->map()->parser());
275 } else if (valExpression.contains("cell-content-text-length-is-not-between")) {
276 setRestriction(Validity::TextLength);
277 setCondition(Conditional::Different);
278 valExpression.remove("oooc:cell-content-text-length-is-not-between(");
279 kDebug(36003) << " valExpression :" << valExpression;
280 valExpression.remove(')');
281 kDebug(36003) << " valExpression :" << valExpression;
282 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
283 loadOdfValidationValue(listVal, cell->sheet()->map()->parser());
284 } else if (valExpression.contains("cell-content-is-in-list(")) {
285 setRestriction(Validity::List);
286 valExpression.remove("oooc:cell-content-is-in-list(");
287 kDebug(36003) << " valExpression :" << valExpression;
288 valExpression.remove(')');
289 setValidityList(valExpression.split(';', QString::SkipEmptyParts));
290
291 }
292 //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
293 else {
294 if (valExpression.contains("cell-content-is-whole-number()")) {
295 setRestriction(Validity::Number);
296 valExpression.remove("oooc:cell-content-is-whole-number() and ");
297 } else if (valExpression.contains("cell-content-is-decimal-number()")) {
298 setRestriction(Validity::Integer);
299 valExpression.remove("oooc:cell-content-is-decimal-number() and ");
300 } else if (valExpression.contains("cell-content-is-date()")) {
301 setRestriction(Validity::Date);
302 valExpression.remove("oooc:cell-content-is-date() and ");
303 } else if (valExpression.contains("cell-content-is-time()")) {
304 setRestriction(Validity::Time);
305 valExpression.remove("oooc:cell-content-is-time() and ");
306 }
307 kDebug(36003) << "valExpression :" << valExpression;
308
309 if (valExpression.contains("cell-content()")) {
310 valExpression.remove("cell-content()");
311 loadOdfValidationCondition(valExpression, cell->sheet()->map()->parser());
312 }
313 //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
314 //for the moment we support just int/double value, not text/date/time :(
315 if (valExpression.contains("cell-content-is-between(")) {
316 valExpression.remove("cell-content-is-between(");
317 valExpression.remove(')');
318 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
319 loadOdfValidationValue(listVal, cell->sheet()->map()->parser());
320 setCondition(Conditional::Between);
321 }
322 if (valExpression.contains("cell-content-is-not-between(")) {
323 valExpression.remove("cell-content-is-not-between(");
324 valExpression.remove(')');
325 QStringList listVal = valExpression.split(',', QString::SkipEmptyParts);
326 loadOdfValidationValue(listVal, cell->sheet()->map()->parser());
327 setCondition(Conditional::Different);
328 }
329 }
330 }
331 if (element.hasAttributeNS(KoXmlNS::table, "allow-empty-cell")) {
332 kDebug(36003) << " element.hasAttribute( table:allow-empty-cell ) :" << element.hasAttributeNS(KoXmlNS::table, "allow-empty-cell");
333 setAllowEmptyCell(((element.attributeNS(KoXmlNS::table, "allow-empty-cell", QString()) == "true") ? true : false));
334 }
335 if (element.hasAttributeNS(KoXmlNS::table, "base-cell-address")) {
336 //todo what is it ?
337 }
338
339 KoXmlElement help = KoXml::namedItemNS(element, KoXmlNS::table, "help-message");
340 if (!help.isNull()) {
341 if (help.hasAttributeNS(KoXmlNS::table, "title")) {
342 kDebug(36003) << "help.attribute( table:title ) :" << help.attributeNS(KoXmlNS::table, "title", QString());
343 setTitleInfo(help.attributeNS(KoXmlNS::table, "title", QString()));
344 }
345 if (help.hasAttributeNS(KoXmlNS::table, "display")) {
346 kDebug(36003) << "help.attribute( table:display ) :" << help.attributeNS(KoXmlNS::table, "display", QString());
347 setDisplayValidationInformation(((help.attributeNS(KoXmlNS::table, "display", QString()) == "true") ? true : false));
348 }
349 KoXmlElement attrText = KoXml::namedItemNS(help, KoXmlNS::text, "p");
350 if (!attrText.isNull()) {
351 kDebug(36003) << "help text :" << attrText.text();
352 setMessageInfo(attrText.text());
353 }
354 }
355
356 KoXmlElement error = KoXml::namedItemNS(element, KoXmlNS::table, "error-message");
357 if (!error.isNull()) {
358 if (error.hasAttributeNS(KoXmlNS::table, "title"))
359 setTitle(error.attributeNS(KoXmlNS::table, "title", QString()));
360 if (error.hasAttributeNS(KoXmlNS::table, "message-type")) {
361 QString str = error.attributeNS(KoXmlNS::table, "message-type", QString());
362 if (str == "warning")
363 setAction(Validity::Warning);
364 else if (str == "information")
365 setAction(Validity::Information);
366 else if (str == "stop")
367 setAction(Validity::Stop);
368 else
369 kDebug(36003) << "validation : message type unknown :" << str;
370 }
371
372 if (error.hasAttributeNS(KoXmlNS::table, "display")) {
373 kDebug(36003) << " display message :" << error.attributeNS(KoXmlNS::table, "display", QString());
374 setDisplayMessage((error.attributeNS(KoXmlNS::table, "display", QString()) == "true"));
375 }
376 KoXmlElement attrText = KoXml::namedItemNS(error, KoXmlNS::text, "p");
377 if (!attrText.isNull())
378 setMessage(attrText.text());
379 }
380 cell->setValidity(validity);
381}
382
383void Validity::loadOdfValidationValue(const QStringList &listVal, const ValueParser *parser)
384{
385 bool ok = false;
386 kDebug(36003) << " listVal[0] :" << listVal[0] << " listVal[1] :" << listVal[1];
387
388 if (restriction() == Validity::Date) {
389 setMinimumValue(parser->tryParseDate(listVal[0]));
390 setMaximumValue(parser->tryParseDate(listVal[1]));
391 } else if (restriction() == Validity::Time) {
392 setMinimumValue(parser->tryParseTime(listVal[0]));
393 setMaximumValue(parser->tryParseTime(listVal[1]));
394 } else {
395 setMinimumValue(Value(listVal[0].toDouble(&ok)));
396 if (!ok) {
397 setMinimumValue(Value(listVal[0].toInt(&ok)));
398 if (!ok)
399 kDebug(36003) << " Try to parse this value :" << listVal[0];
400
401#if 0
402 if (!ok)
403 setMinimumValue(listVal[0]);
404#endif
405 }
406 ok = false;
407 setMaximumValue(Value(listVal[1].toDouble(&ok)));
408 if (!ok) {
409 setMaximumValue(Value(listVal[1].toInt(&ok)));
410 if (!ok)
411 kDebug(36003) << " Try to parse this value :" << listVal[1];
412
413#if 0
414 if (!ok)
415 setMaximumValue(listVal[1]);
416#endif
417 }
418 }
419}
420
421void Validity::loadOdfValidationCondition(QString &valExpression, const ValueParser *parser)
422{
423 if (isEmpty()) return;
424 QString value;
425 if (valExpression.indexOf("<=") == 0) {
426 value = valExpression.remove(0, 2);
427 setCondition(Conditional::InferiorEqual);
428 } else if (valExpression.indexOf(">=") == 0) {
429 value = valExpression.remove(0, 2);
430 setCondition(Conditional::SuperiorEqual);
431 } else if (valExpression.indexOf("!=") == 0) {
432 //add Differentto attribute
433 value = valExpression.remove(0, 2);
434 setCondition(Conditional::DifferentTo);
435 } else if (valExpression.indexOf('<') == 0) {
436 value = valExpression.remove(0, 1);
437 setCondition(Conditional::Inferior);
438 } else if (valExpression.indexOf('>') == 0) {
439 value = valExpression.remove(0, 1);
440 setCondition(Conditional::Superior);
441 } else if (valExpression.indexOf('=') == 0) {
442 value = valExpression.remove(0, 1);
443 setCondition(Conditional::Equal);
444 } else
445 kDebug(36003) << " I don't know how to parse it :" << valExpression;
446 if (restriction() == Validity::Date) {
447 setMinimumValue(parser->tryParseDate(value));
448 } else if (restriction() == Validity::Date) {
449 setMinimumValue(parser->tryParseTime(value));
450 } else {
451 bool ok = false;
452 setMinimumValue(Value(value.toDouble(&ok)));
453 if (!ok) {
454 setMinimumValue(Value(value.toInt(&ok)));
455 if (!ok)
456 kDebug(36003) << " Try to parse this value :" << value;
457
458#if 0
459 if (!ok)
460 setMinimumValue(value);
461#endif
462 }
463 }
464}
465
466Validity::Action Validity::action() const
467{
468 return d->action;
469}
470
471bool Validity::allowEmptyCell() const
472{
473 return d->allowEmptyCell;
474}
475
476Conditional::Type Validity::condition() const
477{
478 return d->cond;
479}
480
481bool Validity::displayMessage() const
482{
483 return d->displayMessage;
484}
485
486bool Validity::displayValidationInformation() const
487{
488 return d->displayValidationInformation;
489}
490
491const QString& Validity::messageInfo() const
492{
493 return d->messageInfo;
494}
495
496const Value &Validity::maximumValue() const
497{
498 return d->maxValue;
499}
500
501const QString& Validity::message() const
502{
503 return d->message;
504}
505
506const Value &Validity::minimumValue() const
507{
508 return d->minValue;
509}
510
511Validity::Restriction Validity::restriction() const
512{
513 return d->restriction;
514}
515
516const QString& Validity::title() const
517{
518 return d->title;
519}
520
521const QString& Validity::titleInfo() const
522{
523 return d->titleInfo;
524}
525
526const QStringList& Validity::validityList() const
527{
528 return d->listValidity;
529}
530
531void Validity::setAction(Action action)
532{
533 d->action = action;
534}
535
536void Validity::setAllowEmptyCell(bool allow)
537{
538 d->allowEmptyCell = allow;
539}
540
541void Validity::setCondition(Conditional::Type condition)
542{
543 d->cond = condition;
544}
545
546void Validity::setDisplayMessage(bool display)
547{
548 d->displayMessage = display;
549}
550
551void Validity::setDisplayValidationInformation(bool display)
552{
553 d->displayValidationInformation = display;
554}
555
556void Validity::setMaximumValue(const Value &value)
557{
558 d->maxValue = value;
559}
560
561void Validity::setMessage(const QString& msg)
562{
563 d->message = msg;
564}
565
566void Validity::setMessageInfo(const QString& info)
567{
568 d->messageInfo = info;
569}
570
571void Validity::setMinimumValue(const Value &value)
572{
573 d->minValue = value;
574}
575
576void Validity::setRestriction(Restriction restriction)
577{
578 d->restriction = restriction;
579}
580
581void Validity::setTitle(const QString& t)
582{
583 d->title = t;
584}
585
586void Validity::setTitleInfo(const QString& info)
587{
588 d->titleInfo = info;
589}
590
591void Validity::setValidityList(const QStringList& list)
592{
593 d->listValidity = list;
594}
595
596bool Validity::testValidity(const Cell* cell) const
597{
598 bool valid = false;
599 if (d->restriction != None) {
600 //fixme
601 if (d->allowEmptyCell && cell->userInput().isEmpty())
602 return true;
603
604 ValueCalc *const calc = cell->sheet()->map()->calc();
605 const Qt::CaseSensitivity cs = calc->settings()->caseSensitiveComparisons();
606
607 if ((cell->value().isNumber() &&
608 (d->restriction == Number ||
609 (d->restriction == Integer &&
610 numToDouble(cell->value().asFloat()) == ceil(numToDouble(cell->value().asFloat())))))
611 || (d->restriction == Time && cell->isTime())
612 || (d->restriction == Date && cell->isDate())) {
613 switch (d->cond) {
614 case Conditional::Equal:
615 valid = cell->value().equal(d->minValue, cs);
616 break;
617 case Conditional::DifferentTo:
618 valid = !cell->value().equal(d->minValue, cs);
619 break;
620 case Conditional::Superior:
621 valid = cell->value().greater(d->minValue, cs);
622 break;
623 case Conditional::Inferior:
624 valid = cell->value().less(d->minValue, cs);
625 break;
626 case Conditional::SuperiorEqual:
627 valid = (cell->value().compare(d->minValue, cs)) >= 0;
628 break;
629 case Conditional::InferiorEqual:
630 valid = (cell->value().compare(d->minValue, cs)) <= 0;
631 break;
632 case Conditional::Between:
633 valid = (cell->value().compare(d->minValue, cs) >= 0 &&
634 cell->value().compare(d->maxValue, cs) <= 0);
635 break;
636 case Conditional::Different:
637 valid = (cell->value().compare(d->minValue, cs) < 0 ||
638 cell->value().compare(d->maxValue, cs) > 0);
639 break;
640 default :
641 break;
642 }
643 } else if (d->restriction == Text) {
644 valid = cell->value().isString();
645 } else if (d->restriction == List) {
646 //test int value
647 if (cell->value().isString() && d->listValidity.contains(cell->value().asString()))
648 valid = true;
649 } else if (d->restriction == TextLength) {
650 if (cell->value().isString()) {
651 int len = cell->displayText().length();
652 const int min = d->minValue.asInteger();
653 const int max = d->maxValue.asInteger();
654 switch (d->cond) {
655 case Conditional::Equal:
656 if (len == min)
657 valid = true;
658 break;
659 case Conditional::DifferentTo:
660 if (len != min)
661 valid = true;
662 break;
663 case Conditional::Superior:
664 if (len > min)
665 valid = true;
666 break;
667 case Conditional::Inferior:
668 if (len < min)
669 valid = true;
670 break;
671 case Conditional::SuperiorEqual:
672 if (len >= min)
673 valid = true;
674 break;
675 case Conditional::InferiorEqual:
676 if (len <= min)
677 valid = true;
678 break;
679 case Conditional::Between:
680 if (len >= min && len <= max)
681 valid = true;
682 break;
683 case Conditional::Different:
684 if (len < min || len > max)
685 valid = true;
686 break;
687 default :
688 break;
689 }
690 }
691 }
692 } else {
693 valid = true;
694 }
695
696 if (!valid) {
697 if (d->displayMessage) {
698 switch (d->action) {
699 case Stop:
700 KMessageBox::error((QWidget*)0, d->message, d->title);
701 break;
702 case Warning:
703 if (KMessageBox::warningYesNo((QWidget*)0, d->message, d->title) == KMessageBox::Yes) {
704 valid = true;
705 }
706 break;
707 case Information:
708 KMessageBox::information((QWidget*)0, d->message, d->title);
709 valid = true;
710 break;
711 }
712 }
713
714 cell->sheet()->showStatusMessage(i18n("Validation for cell %1 failed", cell->fullName()));
715 }
716 return valid;
717}
718
719void Validity::operator=(const Validity & other)
720{
721 d = other.d;
722}
723
724bool Validity::operator==(const Validity& other) const
725{
726 if (d->message == other.d->message &&
727 d->title == other.d->title &&
728 d->titleInfo == other.d->titleInfo &&
729 d->messageInfo == other.d->messageInfo &&
730 d->minValue == other.d->minValue &&
731 d->maxValue == other.d->maxValue &&
732 d->cond == other.d->cond &&
733 d->action == other.d->action &&
734 d->restriction == other.d->restriction &&
735 d->displayMessage == other.d->displayMessage &&
736 d->allowEmptyCell == other.d->allowEmptyCell &&
737 d->displayValidationInformation == other.d->displayValidationInformation &&
738 d->listValidity == other.d->listValidity) {
739 return true;
740 }
741 return false;
742}
743
744// static
745QHash<QString, KoXmlElement> Validity::preloadValidities(const KoXmlElement& body)
746{
747 QHash<QString, KoXmlElement> validities;
748 KoXmlNode validation = KoXml::namedItemNS(body, KoXmlNS::table, "content-validations");
749 kDebug() << "validation.isNull?" << validation.isNull();
750 if (!validation.isNull()) {
751 KoXmlElement element;
752 forEachElement(element, validation) {
753 if (element.tagName() == "content-validation" && element.namespaceURI() == KoXmlNS::table) {
754 const QString name = element.attributeNS(KoXmlNS::table, "name", QString());
755 validities.insert(name, element);
756 kDebug() << " validation found:" << name;
757 } else {
758 kDebug() << " Tag not recognized:" << element.tagName();
759 }
760 }
761 }
762 return validities;
763}
764