File indexing completed on 2025-03-23 03:32:48
0001 // xlsxconditionalformatting.cpp 0002 0003 #include <QtGlobal> 0004 #include <QXmlStreamReader> 0005 #include <QXmlStreamWriter> 0006 #include <QDebug> 0007 0008 #include "xlsxconditionalformatting.h" 0009 #include "xlsxconditionalformatting_p.h" 0010 #include "xlsxworksheet.h" 0011 #include "xlsxcellrange.h" 0012 #include "xlsxstyles_p.h" 0013 0014 QT_BEGIN_NAMESPACE_XLSX 0015 0016 ConditionalFormattingPrivate::ConditionalFormattingPrivate() 0017 { 0018 0019 } 0020 0021 ConditionalFormattingPrivate::ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other) 0022 :QSharedData(other) 0023 { 0024 0025 } 0026 0027 ConditionalFormattingPrivate::~ConditionalFormattingPrivate() 0028 { 0029 0030 } 0031 0032 void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData &cfvo) const 0033 { 0034 writer.writeEmptyElement(QStringLiteral("cfvo")); 0035 QString type; 0036 switch(cfvo.type) { 0037 case ConditionalFormatting::VOT_Formula: type=QStringLiteral("formula"); break; 0038 case ConditionalFormatting::VOT_Max: type=QStringLiteral("max"); break; 0039 case ConditionalFormatting::VOT_Min: type=QStringLiteral("min"); break; 0040 case ConditionalFormatting::VOT_Num: type=QStringLiteral("num"); break; 0041 case ConditionalFormatting::VOT_Percent: type=QStringLiteral("percent"); break; 0042 case ConditionalFormatting::VOT_Percentile: type=QStringLiteral("percentile"); break; 0043 default: break; 0044 } 0045 writer.writeAttribute(QStringLiteral("type"), type); 0046 writer.writeAttribute(QStringLiteral("val"), cfvo.value); 0047 if (!cfvo.gte) 0048 writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0")); 0049 } 0050 0051 /*! 0052 * \class ConditionalFormatting 0053 * \brief Conditional formatting for single cell or ranges 0054 * \inmodule QtXlsx 0055 * 0056 * The conditional formatting can be applied to a single cell or ranges of cells. 0057 */ 0058 0059 0060 /*! 0061 \enum ConditionalFormatting::HighlightRuleType 0062 0063 \value Highlight_LessThan 0064 \value Highlight_LessThanOrEqual 0065 \value Highlight_Equal 0066 \value Highlight_NotEqual 0067 \value Highlight_GreaterThanOrEqual 0068 \value Highlight_GreaterThan 0069 \value Highlight_Between 0070 \value Highlight_NotBetween 0071 0072 \value Highlight_ContainsText 0073 \value Highlight_NotContainsText 0074 \value Highlight_BeginsWith 0075 \value Highlight_EndsWith 0076 0077 \value Highlight_TimePeriod 0078 0079 \value Highlight_Duplicate 0080 \value Highlight_Unique 0081 0082 \value Highlight_Blanks 0083 \value Highlight_NoBlanks 0084 \value Highlight_Errors 0085 \value Highlight_NoErrors 0086 0087 \value Highlight_Top 0088 \value Highlight_TopPercent 0089 \value Highlight_Bottom 0090 \value Highlight_BottomPercent 0091 0092 \value Highlight_AboveAverage 0093 \value Highlight_AboveOrEqualAverage 0094 \value Highlight_BelowAverage 0095 \value Highlight_BelowOrEqualAverage 0096 \value Highlight_AboveStdDev1 0097 \value Highlight_AboveStdDev2 0098 \value Highlight_AboveStdDev3 0099 \value Highlight_BelowStdDev1 0100 \value Highlight_BelowStdDev2 0101 \value Highlight_BelowStdDev3 0102 0103 \value Highlight_Expression 0104 */ 0105 0106 /*! 0107 \enum ConditionalFormatting::ValueObjectType 0108 0109 \value VOT_Formula 0110 \value VOT_Max 0111 \value VOT_Min 0112 \value VOT_Num 0113 \value VOT_Percent 0114 \value VOT_Percentile 0115 */ 0116 0117 /*! 0118 Construct a conditional formatting object 0119 */ 0120 ConditionalFormatting::ConditionalFormatting() 0121 :d(new ConditionalFormattingPrivate()) 0122 { 0123 0124 } 0125 0126 /*! 0127 Constructs a copy of \a other. 0128 */ 0129 ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other) 0130 :d(other.d) 0131 { 0132 0133 } 0134 0135 /*! 0136 Assigns \a other to this conditional formatting and returns a reference to 0137 this conditional formatting. 0138 */ 0139 ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other) 0140 { 0141 this->d = other.d; 0142 return *this; 0143 } 0144 0145 0146 /*! 0147 * Destroy the object. 0148 */ 0149 ConditionalFormatting::~ConditionalFormatting() 0150 { 0151 } 0152 0153 /*! 0154 * Add a hightlight rule with the given \a type, \a formula1, \a formula2, 0155 * \a format and \a stopIfTrue. 0156 * Return false if failed. 0157 */ 0158 bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue) 0159 { 0160 if (format.isEmpty()) 0161 return false; 0162 0163 bool skipFormula = false; 0164 0165 auto cfRule = std::make_shared<XlsxCfRuleData>(); 0166 if (type >= Highlight_LessThan && type <= Highlight_NotBetween) { 0167 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs"); 0168 QString op; 0169 switch (type) { 0170 case Highlight_Between: op = QStringLiteral("between"); break; 0171 case Highlight_Equal: op = QStringLiteral("equal"); break; 0172 case Highlight_GreaterThan: op = QStringLiteral("greaterThan"); break; 0173 case Highlight_GreaterThanOrEqual: op = QStringLiteral("greaterThanOrEqual"); break; 0174 case Highlight_LessThan: op = QStringLiteral("lessThan"); break; 0175 case Highlight_LessThanOrEqual: op = QStringLiteral("lessThanOrEqual"); break; 0176 case Highlight_NotBetween: op = QStringLiteral("notBetween"); break; 0177 case Highlight_NotEqual: op = QStringLiteral("notEqual"); break; 0178 default: break; 0179 } 0180 cfRule->attrs[XlsxCfRuleData::A_operator] = op; 0181 } else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) { 0182 if (type == Highlight_ContainsText) { 0183 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText"); 0184 cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText"); 0185 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1); 0186 } else if (type == Highlight_NotContainsText) { 0187 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText"); 0188 cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains"); 0189 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1); 0190 } else if (type == Highlight_BeginsWith) { 0191 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith"); 0192 cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith"); 0193 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1); 0194 } else { 0195 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith"); 0196 cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith"); 0197 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1); 0198 } 0199 cfRule->attrs[XlsxCfRuleData::A_text] = formula1; 0200 skipFormula = true; 0201 } else if (type == Highlight_TimePeriod) { 0202 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod"); 0203 //:Todo 0204 return false; 0205 } else if (type == Highlight_Duplicate) { 0206 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues"); 0207 } else if (type == Highlight_Unique) { 0208 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues"); 0209 } else if (type == Highlight_Errors) { 0210 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors"); 0211 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)"); 0212 skipFormula = true; 0213 } else if (type == Highlight_NoErrors) { 0214 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors"); 0215 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))"); 0216 skipFormula = true; 0217 } else if (type == Highlight_Blanks) { 0218 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks"); 0219 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0"); 0220 skipFormula = true; 0221 } else if (type == Highlight_NoBlanks) { 0222 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks"); 0223 cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0"); 0224 skipFormula = true; 0225 } else if (type >= Highlight_Top && type <= Highlight_BottomPercent) { 0226 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10"); 0227 if (type == Highlight_Bottom || type == Highlight_BottomPercent) 0228 cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1"); 0229 if (type == Highlight_TopPercent || type == Highlight_BottomPercent) 0230 cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1"); 0231 cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10"); 0232 skipFormula = true; 0233 } else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) { 0234 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage"); 0235 if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3) 0236 cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0"); 0237 if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage) 0238 cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1"); 0239 if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1) 0240 cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1"); 0241 else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2) 0242 cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2"); 0243 else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3) 0244 cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3"); 0245 } else if (type == Highlight_Expression){ 0246 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression"); 0247 } else { 0248 return false; 0249 } 0250 0251 cfRule->dxfFormat = format; 0252 if (stopIfTrue) 0253 cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; 0254 if (!skipFormula) { 0255 if (!formula1.isEmpty()) 0256 cfRule->attrs[XlsxCfRuleData::A_formula1] = formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1; 0257 if (!formula2.isEmpty()) 0258 cfRule->attrs[XlsxCfRuleData::A_formula2] = formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2; 0259 } 0260 d->cfRules.append(cfRule); 0261 return true; 0262 } 0263 0264 /*! 0265 * \overload 0266 * 0267 * Add a hightlight rule with the given \a type \a format and \a stopIfTrue. 0268 */ 0269 bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue) 0270 { 0271 if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) 0272 || (type >= Highlight_Duplicate && type <= Highlight_NoErrors)) { 0273 return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue); 0274 } 0275 0276 return false; 0277 } 0278 0279 /*! 0280 * \overload 0281 * 0282 * Add a hightlight rule with the given \a type, \a formula, \a format and \a stopIfTrue. 0283 * Return false if failed. 0284 */ 0285 bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula, const Format &format, bool stopIfTrue) 0286 { 0287 if (type == Highlight_Between || type == Highlight_NotBetween) 0288 return false; 0289 0290 return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue); 0291 } 0292 0293 /*! 0294 * Add a dataBar rule with the given \a color, \a type1, \a val1 0295 * , \a type2, \a val2, \a showData and \a stopIfTrue. 0296 * Return false if failed. 0297 */ 0298 bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue) 0299 { 0300 auto cfRule = std::make_shared<XlsxCfRuleData>(); 0301 0302 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar"); 0303 cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color); 0304 if (stopIfTrue) 0305 cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; 0306 if (!showData) 0307 cfRule->attrs[XlsxCfRuleData::A_hideData] = true; 0308 0309 XlsxCfVoData cfvo1(type1, val1); 0310 XlsxCfVoData cfvo2(type2, val2); 0311 cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); 0312 cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); 0313 0314 d->cfRules.append(cfRule); 0315 return true; 0316 } 0317 0318 /*! 0319 * \overload 0320 * Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue. 0321 */ 0322 bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue) 0323 { 0324 return addDataBarRule(color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue); 0325 } 0326 0327 /*! 0328 * Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue. 0329 * Return false if failed. 0330 */ 0331 bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue) 0332 { 0333 ValueObjectType type1 = VOT_Min; 0334 ValueObjectType type2 = VOT_Max; 0335 QString val1 = QStringLiteral("0"); 0336 QString val2 = QStringLiteral("0"); 0337 0338 auto cfRule = std::make_shared<XlsxCfRuleData>(); 0339 0340 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale"); 0341 cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor); 0342 cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor); 0343 if (stopIfTrue) 0344 cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; 0345 0346 XlsxCfVoData cfvo1(type1, val1); 0347 XlsxCfVoData cfvo2(type2, val2); 0348 cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); 0349 cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); 0350 0351 d->cfRules.append(cfRule); 0352 return true; 0353 } 0354 0355 /*! 0356 * Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue. 0357 * Return false if failed. 0358 */ 0359 bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue) 0360 { 0361 ValueObjectType type1 = VOT_Min; 0362 ValueObjectType type2 = VOT_Percent; 0363 ValueObjectType type3 = VOT_Max; 0364 QString val1 = QStringLiteral("0"); 0365 QString val2 = QStringLiteral("50"); 0366 QString val3 = QStringLiteral("0"); 0367 0368 auto cfRule = std::make_shared<XlsxCfRuleData>(); 0369 0370 cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale"); 0371 cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor); 0372 cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor); 0373 cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor); 0374 0375 if (stopIfTrue) 0376 cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; 0377 0378 XlsxCfVoData cfvo1(type1, val1); 0379 XlsxCfVoData cfvo2(type2, val2); 0380 XlsxCfVoData cfvo3(type3, val3); 0381 cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); 0382 cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); 0383 cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3); 0384 0385 d->cfRules.append(cfRule); 0386 return true; 0387 } 0388 0389 /*! 0390 Returns the ranges on which the validation will be applied. 0391 */ 0392 QList<CellRange> ConditionalFormatting::ranges() const 0393 { 0394 return d->ranges; 0395 } 0396 0397 /*! 0398 Add the \a cell on which the conditional formatting will apply to. 0399 */ 0400 void ConditionalFormatting::addCell(const CellReference &cell) 0401 { 0402 d->ranges.append(CellRange(cell, cell)); 0403 } 0404 0405 /*! 0406 \overload 0407 Add the cell(\a row, \a col) on which the conditional formatting will apply to. 0408 */ 0409 void ConditionalFormatting::addCell(int row, int col) 0410 { 0411 d->ranges.append(CellRange(row, col, row, col)); 0412 } 0413 0414 /*! 0415 \overload 0416 Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on 0417 which the conditional formatting will apply to. 0418 */ 0419 void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol) 0420 { 0421 d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol)); 0422 } 0423 0424 /*! 0425 Add the \a range on which the conditional formatting will apply to. 0426 */ 0427 void ConditionalFormatting::addRange(const CellRange &range) 0428 { 0429 d->ranges.append(range); 0430 } 0431 0432 bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *rule, Styles *styles) 0433 { 0434 Q_ASSERT(reader.name() == QLatin1String("cfRule")); 0435 QXmlStreamAttributes attrs = reader.attributes(); 0436 if (attrs.hasAttribute(QLatin1String("type"))) 0437 rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString(); 0438 if (attrs.hasAttribute(QLatin1String("dxfId"))) { 0439 int id = attrs.value(QLatin1String("dxfId")).toInt(); 0440 if (styles) 0441 rule->dxfFormat = styles->dxfFormat(id); 0442 else 0443 rule->dxfFormat.setDxfIndex(id); 0444 } 0445 rule->priority = attrs.value(QLatin1String("priority")).toInt(); 0446 if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) { 0447 //default is false 0448 rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1"); 0449 } 0450 if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) { 0451 //default is true 0452 rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0"); 0453 } 0454 if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) { 0455 //default is false 0456 rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1"); 0457 } 0458 if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) { 0459 //default is false 0460 rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1"); 0461 } 0462 if (attrs.hasAttribute(QLatin1String("operator"))) 0463 rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString(); 0464 0465 if (attrs.hasAttribute(QLatin1String("text"))) 0466 rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString(); 0467 0468 if (attrs.hasAttribute(QLatin1String("timePeriod"))) 0469 rule->attrs[XlsxCfRuleData::A_timePeriod] = attrs.value(QLatin1String("timePeriod")).toString(); 0470 0471 if (attrs.hasAttribute(QLatin1String("rank"))) 0472 rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString(); 0473 0474 if (attrs.hasAttribute(QLatin1String("stdDev"))) 0475 rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString(); 0476 0477 if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) { 0478 //default is false 0479 rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1"); 0480 } 0481 0482 while (!reader.atEnd()) { 0483 reader.readNextStartElement(); 0484 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0485 if (reader.name() == QLatin1String("formula")) { 0486 const QString f = reader.readElementText(); 0487 if (!rule->attrs.contains(XlsxCfRuleData::A_formula1)) 0488 rule->attrs[XlsxCfRuleData::A_formula1] = f; 0489 else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2)) 0490 rule->attrs[XlsxCfRuleData::A_formula2] = f; 0491 else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3)) 0492 rule->attrs[XlsxCfRuleData::A_formula3] = f; 0493 } else if (reader.name() == QLatin1String("dataBar")) { 0494 readCfDataBar(reader, rule); 0495 } else if (reader.name() == QLatin1String("colorScale")) { 0496 readCfColorScale(reader, rule); 0497 } 0498 } 0499 if (reader.tokenType() == QXmlStreamReader::EndElement 0500 && reader.name() == QStringLiteral("conditionalFormatting")) { 0501 break; 0502 } 0503 } 0504 return true; 0505 } 0506 0507 bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule) 0508 { 0509 Q_ASSERT(reader.name() == QLatin1String("dataBar")); 0510 QXmlStreamAttributes attrs = reader.attributes(); 0511 if (attrs.value(QLatin1String("showValue")) == QLatin1String("0")) 0512 rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1"); 0513 0514 while (!reader.atEnd()) { 0515 reader.readNextStartElement(); 0516 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0517 if (reader.name() == QLatin1String("cfvo")) { 0518 XlsxCfVoData data; 0519 readCfVo(reader, data); 0520 if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1)) 0521 rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data); 0522 else 0523 rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data); 0524 } else if (reader.name() == QLatin1String("color")) { 0525 XlsxColor color; 0526 color.loadFromXml(reader); 0527 rule->attrs[XlsxCfRuleData::A_color1] = color; 0528 } 0529 } 0530 if (reader.tokenType() == QXmlStreamReader::EndElement 0531 && reader.name() == QStringLiteral("dataBar")) { 0532 break; 0533 } 0534 } 0535 0536 return true; 0537 } 0538 0539 bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule) 0540 { 0541 Q_ASSERT(reader.name() == QLatin1String("colorScale")); 0542 0543 while (!reader.atEnd()) { 0544 reader.readNextStartElement(); 0545 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0546 if (reader.name() == QLatin1String("cfvo")) { 0547 XlsxCfVoData data; 0548 readCfVo(reader, data); 0549 if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1)) 0550 rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data); 0551 else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2)) 0552 rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data); 0553 else 0554 rule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(data); 0555 } else if (reader.name() == QLatin1String("color")) { 0556 XlsxColor color; 0557 color.loadFromXml(reader); 0558 if (!rule->attrs.contains(XlsxCfRuleData::A_color1)) 0559 rule->attrs[XlsxCfRuleData::A_color1] = color; 0560 else if (!rule->attrs.contains(XlsxCfRuleData::A_color2)) 0561 rule->attrs[XlsxCfRuleData::A_color2] = color; 0562 else 0563 rule->attrs[XlsxCfRuleData::A_color3] = color; 0564 } 0565 } 0566 if (reader.tokenType() == QXmlStreamReader::EndElement 0567 && reader.name() == QStringLiteral("colorScale")) { 0568 break; 0569 } 0570 } 0571 0572 return true; 0573 } 0574 0575 bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo) 0576 { 0577 Q_ASSERT(reader.name() == QStringLiteral("cfvo")); 0578 0579 QXmlStreamAttributes attrs = reader.attributes(); 0580 0581 QString type = attrs.value(QLatin1String("type")).toString(); 0582 ConditionalFormatting::ValueObjectType t; 0583 if (type == QLatin1String("formula")) 0584 t = ConditionalFormatting::VOT_Formula; 0585 else if (type == QLatin1String("max")) 0586 t = ConditionalFormatting::VOT_Max; 0587 else if (type == QLatin1String("min")) 0588 t = ConditionalFormatting::VOT_Min; 0589 else if (type == QLatin1String("num")) 0590 t = ConditionalFormatting::VOT_Num; 0591 else if (type == QLatin1String("percent")) 0592 t = ConditionalFormatting::VOT_Percent; 0593 else //if (type == QLatin1String("percentile")) 0594 t = ConditionalFormatting::VOT_Percentile; 0595 0596 cfvo.type = t; 0597 cfvo.value = attrs.value(QLatin1String("val")).toString(); 0598 if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) { 0599 //default is true 0600 cfvo.gte = false; 0601 } 0602 return true; 0603 } 0604 0605 bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles) 0606 { 0607 Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting")); 0608 0609 d->ranges.clear(); 0610 d->cfRules.clear(); 0611 QXmlStreamAttributes attrs = reader.attributes(); 0612 const QString sqref = attrs.value(QLatin1String("sqref")).toString(); 0613 const auto sqrefParts = sqref.split(QLatin1Char(' ')); 0614 for (const QString &range : sqrefParts) { 0615 this->addRange(range); 0616 } 0617 0618 while (!reader.atEnd()) { 0619 reader.readNextStartElement(); 0620 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0621 if (reader.name() == QLatin1String("cfRule")) { 0622 auto cfRule = std::make_shared<XlsxCfRuleData>(); 0623 d->readCfRule(reader, cfRule.get(), styles); 0624 d->cfRules.append(cfRule); 0625 } 0626 } 0627 if (reader.tokenType() == QXmlStreamReader::EndElement 0628 && reader.name() == QStringLiteral("conditionalFormatting")) { 0629 break; 0630 } 0631 } 0632 0633 0634 return true; 0635 } 0636 0637 bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const 0638 { 0639 writer.writeStartElement(QStringLiteral("conditionalFormatting")); 0640 QStringList sqref; 0641 const auto rangeList = ranges(); 0642 for (const CellRange &range : rangeList) { 0643 sqref.append(range.toString()); 0644 } 0645 writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" "))); 0646 0647 for (int i=0; i<d->cfRules.size(); ++i) { 0648 const std::shared_ptr<XlsxCfRuleData> &rule = d->cfRules[i]; 0649 writer.writeStartElement(QStringLiteral("cfRule")); 0650 writer.writeAttribute(QStringLiteral("type"), rule->attrs[XlsxCfRuleData::A_type].toString()); 0651 if (rule->dxfFormat.dxfIndexValid()) 0652 writer.writeAttribute(QStringLiteral("dxfId"), QString::number(rule->dxfFormat.dxfIndex())); 0653 writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority)); 0654 0655 auto it = rule->attrs.constFind(XlsxCfRuleData::A_stopIfTrue); 0656 if (it != rule->attrs.constEnd()) 0657 writer.writeAttribute(QStringLiteral("stopIfTrue"), it.value().toString()); 0658 0659 it = rule->attrs.constFind(XlsxCfRuleData::A_aboveAverage); 0660 if (it != rule->attrs.constEnd()) 0661 writer.writeAttribute(QStringLiteral("aboveAverage"), it.value().toString()); 0662 0663 it = rule->attrs.constFind(XlsxCfRuleData::A_percent); 0664 if (it != rule->attrs.constEnd()) 0665 writer.writeAttribute(QStringLiteral("percent"), it.value().toString()); 0666 0667 it = rule->attrs.constFind(XlsxCfRuleData::A_bottom); 0668 if (it != rule->attrs.constEnd()) 0669 writer.writeAttribute(QStringLiteral("bottom"), it.value().toString()); 0670 0671 it = rule->attrs.constFind(XlsxCfRuleData::A_operator); 0672 if (it != rule->attrs.constEnd()) 0673 writer.writeAttribute(QStringLiteral("operator"), it.value().toString()); 0674 0675 it = rule->attrs.constFind(XlsxCfRuleData::A_text); 0676 if (it != rule->attrs.constEnd()) 0677 writer.writeAttribute(QStringLiteral("text"), it.value().toString()); 0678 0679 it = rule->attrs.constFind(XlsxCfRuleData::A_timePeriod); 0680 if (it != rule->attrs.constEnd()) 0681 writer.writeAttribute(QStringLiteral("timePeriod"), it.value().toString()); 0682 0683 it = rule->attrs.constFind(XlsxCfRuleData::A_rank); 0684 if (it != rule->attrs.constEnd()) 0685 writer.writeAttribute(QStringLiteral("rank"), it.value().toString()); 0686 0687 it = rule->attrs.constFind(XlsxCfRuleData::A_stdDev); 0688 if (it != rule->attrs.constEnd()) 0689 writer.writeAttribute(QStringLiteral("stdDev"), it.value().toString()); 0690 0691 it = rule->attrs.constFind(XlsxCfRuleData::A_equalAverage); 0692 if (it != rule->attrs.constEnd()) 0693 writer.writeAttribute(QStringLiteral("equalAverage"), it.value().toString()); 0694 0695 if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) { 0696 writer.writeStartElement(QStringLiteral("dataBar")); 0697 if (rule->attrs.contains(XlsxCfRuleData::A_hideData)) 0698 writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0")); 0699 d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>()); 0700 d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>()); 0701 rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer); 0702 writer.writeEndElement();//dataBar 0703 } else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) { 0704 writer.writeStartElement(QStringLiteral("colorScale")); 0705 d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>()); 0706 d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>()); 0707 0708 it = rule->attrs.constFind(XlsxCfRuleData::A_cfvo3); 0709 if (it != rule->attrs.constEnd()) 0710 d->writeCfVo(writer, it.value().value<XlsxCfVoData>()); 0711 0712 rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer); 0713 rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer); 0714 0715 it = rule->attrs.constFind(XlsxCfRuleData::A_color3); 0716 if (it != rule->attrs.constEnd()) 0717 it.value().value<XlsxColor>().saveToXml(writer); 0718 0719 writer.writeEndElement();//colorScale 0720 } 0721 0722 0723 it = rule->attrs.constFind(XlsxCfRuleData::A_formula1_temp); 0724 if (it != rule->attrs.constEnd()) { 0725 const auto _ranges = ranges(); 0726 const auto begin = _ranges.begin(); 0727 if (begin != _ranges.end()) { 0728 QString str = begin->toString(); 0729 QString startCell = str.mid(0, str.indexOf(u':')); 0730 writer.writeTextElement(QStringLiteral("formula"), it.value().toString().arg(startCell)); 0731 } 0732 } else if ((it = rule->attrs.constFind(XlsxCfRuleData::A_formula1)) != rule->attrs.constEnd()) { 0733 writer.writeTextElement(QStringLiteral("formula"), it.value().toString()); 0734 } 0735 0736 it = rule->attrs.constFind(XlsxCfRuleData::A_formula2); 0737 if (it != rule->attrs.constEnd()) 0738 writer.writeTextElement(QStringLiteral("formula"), it.value().toString()); 0739 0740 it = rule->attrs.constFind(XlsxCfRuleData::A_formula3); 0741 if (it != rule->attrs.constEnd()) 0742 writer.writeTextElement(QStringLiteral("formula"), it.value().toString()); 0743 0744 writer.writeEndElement(); //cfRule 0745 } 0746 0747 writer.writeEndElement(); //conditionalFormatting 0748 return true; 0749 } 0750 0751 QT_END_NAMESPACE_XLSX