File indexing completed on 2025-03-23 03:32:48
0001 // xlsxdatavalidation.cpp 0002 0003 #include <QtGlobal> 0004 #include <QXmlStreamReader> 0005 #include <QXmlStreamWriter> 0006 0007 #include "xlsxdatavalidation.h" 0008 #include "xlsxdatavalidation_p.h" 0009 #include "xlsxworksheet.h" 0010 #include "xlsxcellrange.h" 0011 0012 QT_BEGIN_NAMESPACE_XLSX 0013 0014 DataValidationPrivate::DataValidationPrivate() 0015 :validationType(DataValidation::None), validationOperator(DataValidation::Between) 0016 , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) 0017 , isErrorMessageVisible(true) 0018 { 0019 0020 } 0021 0022 DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) 0023 :validationType(type), validationOperator(op) 0024 , errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true) 0025 , isErrorMessageVisible(true), formula1(formula1), formula2(formula2) 0026 { 0027 0028 } 0029 0030 DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other) 0031 :QSharedData(other) 0032 , validationType(DataValidation::None), validationOperator(DataValidation::Between) 0033 , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) 0034 , isErrorMessageVisible(true) 0035 { 0036 0037 } 0038 0039 DataValidationPrivate::~DataValidationPrivate() 0040 { 0041 0042 } 0043 0044 /*! 0045 * \class DataValidation 0046 * \brief Data validation for single cell or a range 0047 * \inmodule QtXlsx 0048 * 0049 * The data validation can be applied to a single cell or a range of cells. 0050 */ 0051 0052 /*! 0053 * \enum DataValidation::ValidationType 0054 * 0055 * The enum type defines the type of data that you wish to validate. 0056 * 0057 * \value None the type of data is unrestricted. This is the same as not applying a data validation. 0058 * \value Whole restricts the cell to integer values. Means "Whole number"? 0059 * \value Decimal restricts the cell to decimal values. 0060 * \value List restricts the cell to a set of user specified values. 0061 * \value Date restricts the cell to date values. 0062 * \value Time restricts the cell to time values. 0063 * \value TextLength restricts the cell data based on an integer string length. 0064 * \value Custom restricts the cell based on an external Excel formula that returns a true/false value. 0065 */ 0066 0067 /*! 0068 * \enum DataValidation::ValidationOperator 0069 * 0070 * The enum type defines the criteria by which the data in the 0071 * cell is validated 0072 * 0073 * \value Between 0074 * \value NotBetween 0075 * \value Equal 0076 * \value NotEqual 0077 * \value LessThan 0078 * \value LessThanOrEqual 0079 * \value GreaterThan 0080 * \value GreaterThanOrEqual 0081 */ 0082 0083 /*! 0084 * \enum DataValidation::ErrorStyle 0085 * 0086 * The enum type defines the type of error dialog that 0087 * is displayed. 0088 * 0089 * \value Stop 0090 * \value Warning 0091 * \value Information 0092 */ 0093 0094 /*! 0095 * Construct a data validation object with the given \a type, \a op, \a formula1 0096 * \a formula2, and \a allowBlank. 0097 */ 0098 DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) 0099 :d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank)) 0100 { 0101 0102 } 0103 0104 /*! 0105 Construct a data validation object 0106 */ 0107 DataValidation::DataValidation() 0108 :d(new DataValidationPrivate()) 0109 { 0110 0111 } 0112 0113 /*! 0114 Constructs a copy of \a other. 0115 */ 0116 DataValidation::DataValidation(const DataValidation &other) 0117 :d(other.d) 0118 { 0119 0120 } 0121 0122 /*! 0123 Assigns \a other to this validation and returns a reference to this validation. 0124 */ 0125 DataValidation &DataValidation::operator=(const DataValidation &other) 0126 { 0127 this->d = other.d; 0128 return *this; 0129 } 0130 0131 0132 /*! 0133 * Destroy the object. 0134 */ 0135 DataValidation::~DataValidation() 0136 { 0137 } 0138 0139 /*! 0140 Returns the validation type. 0141 */ 0142 DataValidation::ValidationType DataValidation::validationType() const 0143 { 0144 return d->validationType; 0145 } 0146 0147 /*! 0148 Returns the validation operator. 0149 */ 0150 DataValidation::ValidationOperator DataValidation::validationOperator() const 0151 { 0152 return d->validationOperator; 0153 } 0154 0155 /*! 0156 Returns the validation error style. 0157 */ 0158 DataValidation::ErrorStyle DataValidation::errorStyle() const 0159 { 0160 return d->errorStyle; 0161 } 0162 0163 /*! 0164 Returns the formula1. 0165 */ 0166 QString DataValidation::formula1() const 0167 { 0168 return d->formula1; 0169 } 0170 0171 /*! 0172 Returns the formula2. 0173 */ 0174 QString DataValidation::formula2() const 0175 { 0176 return d->formula2; 0177 } 0178 0179 /*! 0180 Returns whether blank is allowed. 0181 */ 0182 bool DataValidation::allowBlank() const 0183 { 0184 return d->allowBlank; 0185 } 0186 0187 /*! 0188 Returns the error message. 0189 */ 0190 QString DataValidation::errorMessage() const 0191 { 0192 return d->errorMessage; 0193 } 0194 0195 /*! 0196 Returns the error message title. 0197 */ 0198 QString DataValidation::errorMessageTitle() const 0199 { 0200 return d->errorMessageTitle; 0201 } 0202 0203 /*! 0204 Returns the prompt message. 0205 */ 0206 QString DataValidation::promptMessage() const 0207 { 0208 return d->promptMessage; 0209 } 0210 0211 /*! 0212 Returns the prompt message title. 0213 */ 0214 QString DataValidation::promptMessageTitle() const 0215 { 0216 return d->promptMessageTitle; 0217 } 0218 0219 /*! 0220 Returns the whether prompt message is shown. 0221 */ 0222 bool DataValidation::isPromptMessageVisible() const 0223 { 0224 return d->isPromptMessageVisible; 0225 } 0226 0227 /*! 0228 Returns the whether error message is shown. 0229 */ 0230 bool DataValidation::isErrorMessageVisible() const 0231 { 0232 return d->isErrorMessageVisible; 0233 } 0234 0235 /*! 0236 Returns the ranges on which the validation will be applied. 0237 */ 0238 QList<CellRange> DataValidation::ranges() const 0239 { 0240 return d->ranges; 0241 } 0242 0243 /*! 0244 Sets the validation type to \a type. 0245 */ 0246 void DataValidation::setValidationType(DataValidation::ValidationType type) 0247 { 0248 d->validationType = type; 0249 } 0250 0251 /*! 0252 Sets the validation operator to \a op. 0253 */ 0254 void DataValidation::setValidationOperator(DataValidation::ValidationOperator op) 0255 { 0256 d->validationOperator = op; 0257 } 0258 0259 /*! 0260 Sets the error style to \a es. 0261 */ 0262 void DataValidation::setErrorStyle(DataValidation::ErrorStyle es) 0263 { 0264 d->errorStyle = es; 0265 } 0266 0267 /*! 0268 Sets the formula1 to \a formula. 0269 */ 0270 void DataValidation::setFormula1(const QString &formula) 0271 { 0272 if (formula.startsWith(QLatin1Char('='))) 0273 d->formula1 = formula.mid(1); 0274 else 0275 d->formula1 = formula; 0276 } 0277 0278 /*! 0279 Sets the formulas to \a formula. 0280 */ 0281 void DataValidation::setFormula2(const QString &formula) 0282 { 0283 if (formula.startsWith(QLatin1Char('='))) 0284 d->formula2 = formula.mid(1); 0285 else 0286 d->formula2 = formula; 0287 } 0288 0289 /*! 0290 Sets the error message to \a error with title \a title. 0291 */ 0292 void DataValidation::setErrorMessage(const QString &error, const QString &title) 0293 { 0294 d->errorMessage = error; 0295 d->errorMessageTitle = title; 0296 } 0297 0298 /*! 0299 Sets the prompt message to \a prompt with title \a title. 0300 */ 0301 void DataValidation::setPromptMessage(const QString &prompt, const QString &title) 0302 { 0303 d->promptMessage = prompt; 0304 d->promptMessageTitle = title; 0305 } 0306 0307 /*! 0308 Enable/disabe blank allow based on \a enable. 0309 */ 0310 void DataValidation::setAllowBlank(bool enable) 0311 { 0312 d->allowBlank = enable; 0313 } 0314 0315 /*! 0316 Enable/disabe prompt message visible based on \a visible. 0317 */ 0318 void DataValidation::setPromptMessageVisible(bool visible) 0319 { 0320 d->isPromptMessageVisible = visible; 0321 } 0322 0323 /*! 0324 Enable/disabe error message visible based on \a visible. 0325 */ 0326 void DataValidation::setErrorMessageVisible(bool visible) 0327 { 0328 d->isErrorMessageVisible = visible; 0329 } 0330 0331 /*! 0332 Add the \a cell on which the DataValidation will apply to. 0333 */ 0334 void DataValidation::addCell(const CellReference &cell) 0335 { 0336 d->ranges.append(CellRange(cell, cell)); 0337 } 0338 0339 /*! 0340 \overload 0341 Add the cell(\a row, \a col) on which the DataValidation will apply to. 0342 */ 0343 void DataValidation::addCell(int row, int col) 0344 { 0345 d->ranges.append(CellRange(row, col, row, col)); 0346 } 0347 0348 /*! 0349 \overload 0350 Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on 0351 which the DataValidation will apply to. 0352 */ 0353 void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol) 0354 { 0355 d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol)); 0356 } 0357 0358 /*! 0359 Add the \a range on which the DataValidation will apply to. 0360 */ 0361 void DataValidation::addRange(const CellRange &range) 0362 { 0363 d->ranges.append(range); 0364 } 0365 0366 /*! 0367 * \internal 0368 */ 0369 bool DataValidation::saveToXml(QXmlStreamWriter &writer) const 0370 { 0371 static const QMap<DataValidation::ValidationType, QString> typeMap = { 0372 {DataValidation::None, QStringLiteral("none")}, 0373 {DataValidation::Whole, QStringLiteral("whole")}, 0374 {DataValidation::Decimal, QStringLiteral("decimal")}, 0375 {DataValidation::List, QStringLiteral("list")}, 0376 {DataValidation::Date, QStringLiteral("date")}, 0377 {DataValidation::Time, QStringLiteral("time")}, 0378 {DataValidation::TextLength, QStringLiteral("textLength")}, 0379 {DataValidation::Custom, QStringLiteral("custom")} 0380 }; 0381 0382 static const QMap<DataValidation::ValidationOperator, QString> opMap = { 0383 {DataValidation::Between, QStringLiteral("between")}, 0384 {DataValidation::NotBetween, QStringLiteral("notBetween")}, 0385 {DataValidation::Equal, QStringLiteral("equal")}, 0386 {DataValidation::NotEqual, QStringLiteral("notEqual")}, 0387 {DataValidation::LessThan, QStringLiteral("lessThan")}, 0388 {DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual")}, 0389 {DataValidation::GreaterThan, QStringLiteral("greaterThan")}, 0390 {DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual")} 0391 }; 0392 0393 static const QMap<DataValidation::ErrorStyle, QString> esMap = { 0394 {DataValidation::Stop, QStringLiteral("stop")}, 0395 {DataValidation::Warning, QStringLiteral("warning")}, 0396 {DataValidation::Information, QStringLiteral("information")} 0397 }; 0398 0399 writer.writeStartElement(QStringLiteral("dataValidation")); 0400 if (validationType() != DataValidation::None) 0401 writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]); 0402 if (errorStyle() != DataValidation::Stop) 0403 writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]); 0404 if (validationOperator() != DataValidation::Between) 0405 writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]); 0406 if (allowBlank()) 0407 writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1")); 0408 // if (dropDownVisible()) 0409 // writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1")); 0410 if (isPromptMessageVisible()) 0411 writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1")); 0412 if (isErrorMessageVisible()) 0413 writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1")); 0414 if (!errorMessageTitle().isEmpty()) 0415 writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle()); 0416 if (!errorMessage().isEmpty()) 0417 writer.writeAttribute(QStringLiteral("error"), errorMessage()); 0418 if (!promptMessageTitle().isEmpty()) 0419 writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle()); 0420 if (!promptMessage().isEmpty()) 0421 writer.writeAttribute(QStringLiteral("prompt"), promptMessage()); 0422 0423 QStringList sqref; 0424 const auto rangeList = ranges(); 0425 for (const CellRange &range : rangeList) 0426 sqref.append(range.toString()); 0427 writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" "))); 0428 0429 if (!formula1().isEmpty()) 0430 writer.writeTextElement(QStringLiteral("formula1"), formula1()); 0431 if (!formula2().isEmpty()) 0432 writer.writeTextElement(QStringLiteral("formula2"), formula2()); 0433 0434 writer.writeEndElement(); //dataValidation 0435 0436 return true; 0437 } 0438 0439 /*! 0440 * \internal 0441 */ 0442 DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader) 0443 { 0444 Q_ASSERT(reader.name() == QLatin1String("dataValidation")); 0445 0446 static const QMap<QString, DataValidation::ValidationType> typeMap = { 0447 {QStringLiteral("none"), DataValidation::None}, 0448 {QStringLiteral("whole"), DataValidation::Whole}, 0449 {QStringLiteral("decimal"), DataValidation::Decimal}, 0450 {QStringLiteral("list"), DataValidation::List}, 0451 {QStringLiteral("date"), DataValidation::Date}, 0452 {QStringLiteral("time"), DataValidation::Time}, 0453 {QStringLiteral("textLength"), DataValidation::TextLength}, 0454 {QStringLiteral("custom"), DataValidation::Custom} 0455 }; 0456 0457 static const QMap<QString, DataValidation::ValidationOperator> opMap = { 0458 {QStringLiteral("between"), DataValidation::Between}, 0459 {QStringLiteral("notBetween"), DataValidation::NotBetween}, 0460 {QStringLiteral("equal"), DataValidation::Equal}, 0461 {QStringLiteral("notEqual"), DataValidation::NotEqual}, 0462 {QStringLiteral("lessThan"), DataValidation::LessThan}, 0463 {QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual}, 0464 {QStringLiteral("greaterThan"), DataValidation::GreaterThan}, 0465 {QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual} 0466 }; 0467 0468 static const QMap<QString, DataValidation::ErrorStyle> esMap = { 0469 {QStringLiteral("stop"), DataValidation::Stop}, 0470 {QStringLiteral("warning"), DataValidation::Warning}, 0471 {QStringLiteral("information"), DataValidation::Information} 0472 }; 0473 0474 DataValidation validation; 0475 QXmlStreamAttributes attrs = reader.attributes(); 0476 0477 QString sqref = attrs.value(QLatin1String("sqref")).toString(); 0478 const auto sqrefParts = sqref.split(QLatin1Char(' ')); 0479 for (const QString &range : sqrefParts) 0480 validation.addRange(range); 0481 0482 if (attrs.hasAttribute(QLatin1String("type"))) { 0483 QString t = attrs.value(QLatin1String("type")).toString(); 0484 auto it = typeMap.constFind(t); 0485 validation.setValidationType(it != typeMap.constEnd() ? it.value() : DataValidation::None); 0486 } 0487 if (attrs.hasAttribute(QLatin1String("errorStyle"))) { 0488 QString es = attrs.value(QLatin1String("errorStyle")).toString(); 0489 auto it = esMap.constFind(es); 0490 validation.setErrorStyle(it != esMap.constEnd() ? it.value() : DataValidation::Stop); 0491 } 0492 if (attrs.hasAttribute(QLatin1String("operator"))) { 0493 QString op = attrs.value(QLatin1String("operator")).toString(); 0494 auto it = opMap.constFind(op); 0495 validation.setValidationOperator(it != opMap.constEnd() ? it.value() : DataValidation::Between); 0496 } 0497 if (attrs.hasAttribute(QLatin1String("allowBlank"))) { 0498 validation.setAllowBlank(true); 0499 } else { 0500 validation.setAllowBlank(false); 0501 } 0502 if (attrs.hasAttribute(QLatin1String("showInputMessage"))) { 0503 validation.setPromptMessageVisible(true); 0504 } else { 0505 validation.setPromptMessageVisible(false); 0506 } 0507 if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) { 0508 validation.setErrorMessageVisible(true); 0509 } else { 0510 validation.setErrorMessageVisible(false); 0511 } 0512 0513 QString et = attrs.value(QLatin1String("errorTitle")).toString(); 0514 QString e = attrs.value(QLatin1String("error")).toString(); 0515 if (!e.isEmpty() || !et.isEmpty()) 0516 validation.setErrorMessage(e, et); 0517 0518 QString pt = attrs.value(QLatin1String("promptTitle")).toString(); 0519 QString p = attrs.value(QLatin1String("prompt")).toString(); 0520 if (!p.isEmpty() || !pt.isEmpty()) 0521 validation.setPromptMessage(p, pt); 0522 0523 //find the end 0524 while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) { 0525 reader.readNextStartElement(); 0526 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0527 if (reader.name() == QLatin1String("formula1")) { 0528 validation.setFormula1(reader.readElementText()); 0529 } else if (reader.name() == QLatin1String("formula2")) { 0530 validation.setFormula2(reader.readElementText()); 0531 } 0532 } 0533 } 0534 return validation; 0535 } 0536 0537 QT_END_NAMESPACE_XLSX