File indexing completed on 2024-05-26 03:50:50

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