andre@1: /**************************************************************************** andre@1: ** Copyright (c) 2013-2014 Debao Zhang andre@1: ** All right reserved. andre@1: ** andre@1: ** Permission is hereby granted, free of charge, to any person obtaining andre@1: ** a copy of this software and associated documentation files (the andre@1: ** "Software"), to deal in the Software without restriction, including andre@1: ** without limitation the rights to use, copy, modify, merge, publish, andre@1: ** distribute, sublicense, and/or sell copies of the Software, and to andre@1: ** permit persons to whom the Software is furnished to do so, subject to andre@1: ** the following conditions: andre@1: ** andre@1: ** The above copyright notice and this permission notice shall be andre@1: ** included in all copies or substantial portions of the Software. andre@1: ** andre@1: ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, andre@1: ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF andre@1: ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND andre@1: ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE andre@1: ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION andre@1: ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION andre@1: ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. andre@1: ** andre@1: ****************************************************************************/ andre@1: andre@1: #include "xlsxdatavalidation.h" andre@1: #include "xlsxdatavalidation_p.h" andre@1: #include "xlsxworksheet.h" andre@1: #include "xlsxcellrange.h" andre@1: andre@1: #include andre@1: #include andre@1: andre@1: QT_BEGIN_NAMESPACE_XLSX andre@1: andre@1: DataValidationPrivate::DataValidationPrivate() andre@1: :validationType(DataValidation::None), validationOperator(DataValidation::Between) andre@1: , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) andre@1: , isErrorMessageVisible(true) andre@1: { andre@1: andre@1: } andre@1: andre@1: DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) andre@1: :validationType(type), validationOperator(op) andre@1: , errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true) andre@1: , isErrorMessageVisible(true), formula1(formula1), formula2(formula2) andre@1: { andre@1: andre@1: } andre@1: andre@1: DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other) andre@1: :QSharedData(other) andre@1: , validationType(DataValidation::None), validationOperator(DataValidation::Between) andre@1: , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) andre@1: , isErrorMessageVisible(true) andre@1: { andre@1: andre@1: } andre@1: andre@1: DataValidationPrivate::~DataValidationPrivate() andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: * \class DataValidation andre@1: * \brief Data validation for single cell or a range andre@1: * \inmodule QtXlsx andre@1: * andre@1: * The data validation can be applied to a single cell or a range of cells. andre@1: */ andre@1: andre@1: /*! andre@1: * \enum DataValidation::ValidationType andre@1: * andre@1: * The enum type defines the type of data that you wish to validate. andre@1: * andre@1: * \value None the type of data is unrestricted. This is the same as not applying a data validation. andre@1: * \value Whole restricts the cell to integer values. Means "Whole number"? andre@1: * \value Decimal restricts the cell to decimal values. andre@1: * \value List restricts the cell to a set of user specified values. andre@1: * \value Date restricts the cell to date values. andre@1: * \value Time restricts the cell to time values. andre@1: * \value TextLength restricts the cell data based on an integer string length. andre@1: * \value Custom restricts the cell based on an external Excel formula that returns a true/false value. andre@1: */ andre@1: andre@1: /*! andre@1: * \enum DataValidation::ValidationOperator andre@1: * andre@1: * The enum type defines the criteria by which the data in the andre@1: * cell is validated andre@1: * andre@1: * \value Between andre@1: * \value NotBetween andre@1: * \value Equal andre@1: * \value NotEqual andre@1: * \value LessThan andre@1: * \value LessThanOrEqual andre@1: * \value GreaterThan andre@1: * \value GreaterThanOrEqual andre@1: */ andre@1: andre@1: /*! andre@1: * \enum DataValidation::ErrorStyle andre@1: * andre@1: * The enum type defines the type of error dialog that andre@1: * is displayed. andre@1: * andre@1: * \value Stop andre@1: * \value Warning andre@1: * \value Information andre@1: */ andre@1: andre@1: /*! andre@1: * Construct a data validation object with the given \a type, \a op, \a formula1 andre@1: * \a formula2, and \a allowBlank. andre@1: */ andre@1: DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) andre@1: :d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank)) andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: Construct a data validation object andre@1: */ andre@1: DataValidation::DataValidation() andre@1: :d(new DataValidationPrivate()) andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: Constructs a copy of \a other. andre@1: */ andre@1: DataValidation::DataValidation(const DataValidation &other) andre@1: :d(other.d) andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: Assigns \a other to this validation and returns a reference to this validation. andre@1: */ andre@1: DataValidation &DataValidation::operator=(const DataValidation &other) andre@1: { andre@1: this->d = other.d; andre@1: return *this; andre@1: } andre@1: andre@1: andre@1: /*! andre@1: * Destroy the object. andre@1: */ andre@1: DataValidation::~DataValidation() andre@1: { andre@1: } andre@1: andre@1: /*! andre@1: Returns the validation type. andre@1: */ andre@1: DataValidation::ValidationType DataValidation::validationType() const andre@1: { andre@1: return d->validationType; andre@1: } andre@1: andre@1: /*! andre@1: Returns the validation operator. andre@1: */ andre@1: DataValidation::ValidationOperator DataValidation::validationOperator() const andre@1: { andre@1: return d->validationOperator; andre@1: } andre@1: andre@1: /*! andre@1: Returns the validation error style. andre@1: */ andre@1: DataValidation::ErrorStyle DataValidation::errorStyle() const andre@1: { andre@1: return d->errorStyle; andre@1: } andre@1: andre@1: /*! andre@1: Returns the formula1. andre@1: */ andre@1: QString DataValidation::formula1() const andre@1: { andre@1: return d->formula1; andre@1: } andre@1: andre@1: /*! andre@1: Returns the formula2. andre@1: */ andre@1: QString DataValidation::formula2() const andre@1: { andre@1: return d->formula2; andre@1: } andre@1: andre@1: /*! andre@1: Returns whether blank is allowed. andre@1: */ andre@1: bool DataValidation::allowBlank() const andre@1: { andre@1: return d->allowBlank; andre@1: } andre@1: andre@1: /*! andre@1: Returns the error message. andre@1: */ andre@1: QString DataValidation::errorMessage() const andre@1: { andre@1: return d->errorMessage; andre@1: } andre@1: andre@1: /*! andre@1: Returns the error message title. andre@1: */ andre@1: QString DataValidation::errorMessageTitle() const andre@1: { andre@1: return d->errorMessageTitle; andre@1: } andre@1: andre@1: /*! andre@1: Returns the prompt message. andre@1: */ andre@1: QString DataValidation::promptMessage() const andre@1: { andre@1: return d->promptMessage; andre@1: } andre@1: andre@1: /*! andre@1: Returns the prompt message title. andre@1: */ andre@1: QString DataValidation::promptMessageTitle() const andre@1: { andre@1: return d->promptMessageTitle; andre@1: } andre@1: andre@1: /*! andre@1: Returns the whether prompt message is shown. andre@1: */ andre@1: bool DataValidation::isPromptMessageVisible() const andre@1: { andre@1: return d->isPromptMessageVisible; andre@1: } andre@1: andre@1: /*! andre@1: Returns the whether error message is shown. andre@1: */ andre@1: bool DataValidation::isErrorMessageVisible() const andre@1: { andre@1: return d->isErrorMessageVisible; andre@1: } andre@1: andre@1: /*! andre@1: Returns the ranges on which the validation will be applied. andre@1: */ andre@1: QList DataValidation::ranges() const andre@1: { andre@1: return d->ranges; andre@1: } andre@1: andre@1: /*! andre@1: Sets the validation type to \a type. andre@1: */ andre@1: void DataValidation::setValidationType(DataValidation::ValidationType type) andre@1: { andre@1: d->validationType = type; andre@1: } andre@1: andre@1: /*! andre@1: Sets the validation operator to \a op. andre@1: */ andre@1: void DataValidation::setValidationOperator(DataValidation::ValidationOperator op) andre@1: { andre@1: d->validationOperator = op; andre@1: } andre@1: andre@1: /*! andre@1: Sets the error style to \a es. andre@1: */ andre@1: void DataValidation::setErrorStyle(DataValidation::ErrorStyle es) andre@1: { andre@1: d->errorStyle = es; andre@1: } andre@1: andre@1: /*! andre@1: Sets the formula1 to \a formula. andre@1: */ andre@1: void DataValidation::setFormula1(const QString &formula) andre@1: { andre@1: if (formula.startsWith(QLatin1Char('='))) andre@1: d->formula1 = formula.mid(1); andre@1: else andre@1: d->formula1 = formula; andre@1: } andre@1: andre@1: /*! andre@1: Sets the formulas to \a formula. andre@1: */ andre@1: void DataValidation::setFormula2(const QString &formula) andre@1: { andre@1: if (formula.startsWith(QLatin1Char('='))) andre@1: d->formula2 = formula.mid(1); andre@1: else andre@1: d->formula2 = formula; andre@1: } andre@1: andre@1: /*! andre@1: Sets the error message to \a error with title \a title. andre@1: */ andre@1: void DataValidation::setErrorMessage(const QString &error, const QString &title) andre@1: { andre@1: d->errorMessage = error; andre@1: d->errorMessageTitle = title; andre@1: } andre@1: andre@1: /*! andre@1: Sets the prompt message to \a prompt with title \a title. andre@1: */ andre@1: void DataValidation::setPromptMessage(const QString &prompt, const QString &title) andre@1: { andre@1: d->promptMessage = prompt; andre@1: d->promptMessageTitle = title; andre@1: } andre@1: andre@1: /*! andre@1: Enable/disabe blank allow based on \a enable. andre@1: */ andre@1: void DataValidation::setAllowBlank(bool enable) andre@1: { andre@1: d->allowBlank = enable; andre@1: } andre@1: andre@1: /*! andre@1: Enable/disabe prompt message visible based on \a visible. andre@1: */ andre@1: void DataValidation::setPromptMessageVisible(bool visible) andre@1: { andre@1: d->isPromptMessageVisible = visible; andre@1: } andre@1: andre@1: /*! andre@1: Enable/disabe error message visible based on \a visible. andre@1: */ andre@1: void DataValidation::setErrorMessageVisible(bool visible) andre@1: { andre@1: d->isErrorMessageVisible = visible; andre@1: } andre@1: andre@1: /*! andre@1: Add the \a cell on which the DataValidation will apply to. andre@1: */ andre@1: void DataValidation::addCell(const CellReference &cell) andre@1: { andre@1: d->ranges.append(CellRange(cell, cell)); andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Add the cell(\a row, \a col) on which the DataValidation will apply to. andre@1: */ andre@1: void DataValidation::addCell(int row, int col) andre@1: { andre@1: d->ranges.append(CellRange(row, col, row, col)); andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on andre@1: which the DataValidation will apply to. andre@1: */ andre@1: void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol) andre@1: { andre@1: d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol)); andre@1: } andre@1: andre@1: /*! andre@1: Add the \a range on which the DataValidation will apply to. andre@1: */ andre@1: void DataValidation::addRange(const CellRange &range) andre@1: { andre@1: d->ranges.append(range); andre@1: } andre@1: andre@1: /*! andre@1: * \internal andre@1: */ andre@1: bool DataValidation::saveToXml(QXmlStreamWriter &writer) const andre@1: { andre@1: static QMap typeMap; andre@1: static QMap opMap; andre@1: static QMap esMap; andre@1: if (typeMap.isEmpty()) { andre@1: typeMap.insert(DataValidation::None, QStringLiteral("none")); andre@1: typeMap.insert(DataValidation::Whole, QStringLiteral("whole")); andre@1: typeMap.insert(DataValidation::Decimal, QStringLiteral("decimal")); andre@1: typeMap.insert(DataValidation::List, QStringLiteral("list")); andre@1: typeMap.insert(DataValidation::Date, QStringLiteral("date")); andre@1: typeMap.insert(DataValidation::Time, QStringLiteral("time")); andre@1: typeMap.insert(DataValidation::TextLength, QStringLiteral("textLength")); andre@1: typeMap.insert(DataValidation::Custom, QStringLiteral("custom")); andre@1: andre@1: opMap.insert(DataValidation::Between, QStringLiteral("between")); andre@1: opMap.insert(DataValidation::NotBetween, QStringLiteral("notBetween")); andre@1: opMap.insert(DataValidation::Equal, QStringLiteral("equal")); andre@1: opMap.insert(DataValidation::NotEqual, QStringLiteral("notEqual")); andre@1: opMap.insert(DataValidation::LessThan, QStringLiteral("lessThan")); andre@1: opMap.insert(DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual")); andre@1: opMap.insert(DataValidation::GreaterThan, QStringLiteral("greaterThan")); andre@1: opMap.insert(DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual")); andre@1: andre@1: esMap.insert(DataValidation::Stop, QStringLiteral("stop")); andre@1: esMap.insert(DataValidation::Warning, QStringLiteral("warning")); andre@1: esMap.insert(DataValidation::Information, QStringLiteral("information")); andre@1: } andre@1: andre@1: writer.writeStartElement(QStringLiteral("dataValidation")); andre@1: if (validationType() != DataValidation::None) andre@1: writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]); andre@1: if (errorStyle() != DataValidation::Stop) andre@1: writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]); andre@1: if (validationOperator() != DataValidation::Between) andre@1: writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]); andre@1: if (allowBlank()) andre@1: writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1")); andre@1: // if (dropDownVisible()) andre@1: // writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1")); andre@1: if (isPromptMessageVisible()) andre@1: writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1")); andre@1: if (isErrorMessageVisible()) andre@1: writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1")); andre@1: if (!errorMessageTitle().isEmpty()) andre@1: writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle()); andre@1: if (!errorMessage().isEmpty()) andre@1: writer.writeAttribute(QStringLiteral("error"), errorMessage()); andre@1: if (!promptMessageTitle().isEmpty()) andre@1: writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle()); andre@1: if (!promptMessage().isEmpty()) andre@1: writer.writeAttribute(QStringLiteral("prompt"), promptMessage()); andre@1: andre@1: QStringList sqref; andre@1: foreach (CellRange range, ranges()) andre@1: sqref.append(range.toString()); andre@1: writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' '))); andre@1: andre@1: if (!formula1().isEmpty()) andre@1: writer.writeTextElement(QStringLiteral("formula1"), formula1()); andre@1: if (!formula2().isEmpty()) andre@1: writer.writeTextElement(QStringLiteral("formula2"), formula2()); andre@1: andre@1: writer.writeEndElement(); //dataValidation andre@1: andre@1: return true; andre@1: } andre@1: andre@1: /*! andre@1: * \internal andre@1: */ andre@1: DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader) andre@1: { andre@1: Q_ASSERT(reader.name() == QLatin1String("dataValidation")); andre@1: andre@1: static QMap typeMap; andre@1: static QMap opMap; andre@1: static QMap esMap; andre@1: if (typeMap.isEmpty()) { andre@1: typeMap.insert(QStringLiteral("none"), DataValidation::None); andre@1: typeMap.insert(QStringLiteral("whole"), DataValidation::Whole); andre@1: typeMap.insert(QStringLiteral("decimal"), DataValidation::Decimal); andre@1: typeMap.insert(QStringLiteral("list"), DataValidation::List); andre@1: typeMap.insert(QStringLiteral("date"), DataValidation::Date); andre@1: typeMap.insert(QStringLiteral("time"), DataValidation::Time); andre@1: typeMap.insert(QStringLiteral("textLength"), DataValidation::TextLength); andre@1: typeMap.insert(QStringLiteral("custom"), DataValidation::Custom); andre@1: andre@1: opMap.insert(QStringLiteral("between"), DataValidation::Between); andre@1: opMap.insert(QStringLiteral("notBetween"), DataValidation::NotBetween); andre@1: opMap.insert(QStringLiteral("equal"), DataValidation::Equal); andre@1: opMap.insert(QStringLiteral("notEqual"), DataValidation::NotEqual); andre@1: opMap.insert(QStringLiteral("lessThan"), DataValidation::LessThan); andre@1: opMap.insert(QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual); andre@1: opMap.insert(QStringLiteral("greaterThan"), DataValidation::GreaterThan); andre@1: opMap.insert(QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual); andre@1: andre@1: esMap.insert(QStringLiteral("stop"), DataValidation::Stop); andre@1: esMap.insert(QStringLiteral("warning"), DataValidation::Warning); andre@1: esMap.insert(QStringLiteral("information"), DataValidation::Information); andre@1: } andre@1: andre@1: DataValidation validation; andre@1: QXmlStreamAttributes attrs = reader.attributes(); andre@1: andre@1: QString sqref = attrs.value(QLatin1String("sqref")).toString(); andre@1: foreach (QString range, sqref.split(QLatin1Char(' '))) andre@1: validation.addRange(range); andre@1: andre@1: if (attrs.hasAttribute(QLatin1String("type"))) { andre@1: QString t = attrs.value(QLatin1String("type")).toString(); andre@1: validation.setValidationType(typeMap.contains(t) ? typeMap[t] : DataValidation::None); andre@1: } andre@1: if (attrs.hasAttribute(QLatin1String("errorStyle"))) { andre@1: QString es = attrs.value(QLatin1String("errorStyle")).toString(); andre@1: validation.setErrorStyle(esMap.contains(es) ? esMap[es] : DataValidation::Stop); andre@1: } andre@1: if (attrs.hasAttribute(QLatin1String("operator"))) { andre@1: QString op = attrs.value(QLatin1String("operator")).toString(); andre@1: validation.setValidationOperator(opMap.contains(op) ? opMap[op] : DataValidation::Between); andre@1: } andre@1: if (attrs.hasAttribute(QLatin1String("allowBlank"))) { andre@1: validation.setAllowBlank(true); andre@1: } else { andre@1: validation.setAllowBlank(false); andre@1: } andre@1: if (attrs.hasAttribute(QLatin1String("showInputMessage"))) { andre@1: validation.setPromptMessageVisible(true); andre@1: } else { andre@1: validation.setPromptMessageVisible(false); andre@1: } andre@1: if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) { andre@1: validation.setErrorMessageVisible(true); andre@1: } else { andre@1: validation.setErrorMessageVisible(false); andre@1: } andre@1: andre@1: QString et = attrs.value(QLatin1String("errorTitle")).toString(); andre@1: QString e = attrs.value(QLatin1String("error")).toString(); andre@1: if (!e.isEmpty() || !et.isEmpty()) andre@1: validation.setErrorMessage(e, et); andre@1: andre@1: QString pt = attrs.value(QLatin1String("promptTitle")).toString(); andre@1: QString p = attrs.value(QLatin1String("prompt")).toString(); andre@1: if (!p.isEmpty() || !pt.isEmpty()) andre@1: validation.setPromptMessage(p, pt); andre@1: andre@1: //find the end andre@1: while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("formula1")) { andre@1: validation.setFormula1(reader.readElementText()); andre@1: } else if (reader.name() == QLatin1String("formula2")) { andre@1: validation.setFormula2(reader.readElementText()); andre@1: } andre@1: } andre@1: } andre@1: return validation; andre@1: } andre@1: andre@1: QT_END_NAMESPACE_XLSX