xlsxconditionalformatting.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. // xlsxconditionalformatting.cpp
  2. #include <QtGlobal>
  3. #include <QXmlStreamReader>
  4. #include <QXmlStreamWriter>
  5. #include <QDebug>
  6. #include "xlsxconditionalformatting.h"
  7. #include "xlsxconditionalformatting_p.h"
  8. #include "xlsxworksheet.h"
  9. #include "xlsxcellrange.h"
  10. #include "xlsxstyles_p.h"
  11. QT_BEGIN_NAMESPACE_XLSX
  12. ConditionalFormattingPrivate::ConditionalFormattingPrivate()
  13. {
  14. }
  15. ConditionalFormattingPrivate::ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other)
  16. :QSharedData(other)
  17. {
  18. }
  19. ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
  20. {
  21. }
  22. void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData &cfvo) const
  23. {
  24. writer.writeEmptyElement(QStringLiteral("cfvo"));
  25. QString type;
  26. switch(cfvo.type) {
  27. case ConditionalFormatting::VOT_Formula: type=QStringLiteral("formula"); break;
  28. case ConditionalFormatting::VOT_Max: type=QStringLiteral("max"); break;
  29. case ConditionalFormatting::VOT_Min: type=QStringLiteral("min"); break;
  30. case ConditionalFormatting::VOT_Num: type=QStringLiteral("num"); break;
  31. case ConditionalFormatting::VOT_Percent: type=QStringLiteral("percent"); break;
  32. case ConditionalFormatting::VOT_Percentile: type=QStringLiteral("percentile"); break;
  33. default: break;
  34. }
  35. writer.writeAttribute(QStringLiteral("type"), type);
  36. writer.writeAttribute(QStringLiteral("val"), cfvo.value);
  37. if (!cfvo.gte)
  38. writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0"));
  39. }
  40. /*!
  41. * \class ConditionalFormatting
  42. * \brief Conditional formatting for single cell or ranges
  43. * \inmodule QtXlsx
  44. *
  45. * The conditional formatting can be applied to a single cell or ranges of cells.
  46. */
  47. /*!
  48. \enum ConditionalFormatting::HighlightRuleType
  49. \value Highlight_LessThan
  50. \value Highlight_LessThanOrEqual
  51. \value Highlight_Equal
  52. \value Highlight_NotEqual
  53. \value Highlight_GreaterThanOrEqual
  54. \value Highlight_GreaterThan
  55. \value Highlight_Between
  56. \value Highlight_NotBetween
  57. \value Highlight_ContainsText
  58. \value Highlight_NotContainsText
  59. \value Highlight_BeginsWith
  60. \value Highlight_EndsWith
  61. \value Highlight_TimePeriod
  62. \value Highlight_Duplicate
  63. \value Highlight_Unique
  64. \value Highlight_Blanks
  65. \value Highlight_NoBlanks
  66. \value Highlight_Errors
  67. \value Highlight_NoErrors
  68. \value Highlight_Top
  69. \value Highlight_TopPercent
  70. \value Highlight_Bottom
  71. \value Highlight_BottomPercent
  72. \value Highlight_AboveAverage
  73. \value Highlight_AboveOrEqualAverage
  74. \value Highlight_BelowAverage
  75. \value Highlight_BelowOrEqualAverage
  76. \value Highlight_AboveStdDev1
  77. \value Highlight_AboveStdDev2
  78. \value Highlight_AboveStdDev3
  79. \value Highlight_BelowStdDev1
  80. \value Highlight_BelowStdDev2
  81. \value Highlight_BelowStdDev3
  82. \value Highlight_Expression
  83. */
  84. /*!
  85. \enum ConditionalFormatting::ValueObjectType
  86. \value VOT_Formula
  87. \value VOT_Max
  88. \value VOT_Min
  89. \value VOT_Num
  90. \value VOT_Percent
  91. \value VOT_Percentile
  92. */
  93. /*!
  94. Construct a conditional formatting object
  95. */
  96. ConditionalFormatting::ConditionalFormatting()
  97. :d(new ConditionalFormattingPrivate())
  98. {
  99. }
  100. /*!
  101. Constructs a copy of \a other.
  102. */
  103. ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other)
  104. :d(other.d)
  105. {
  106. }
  107. /*!
  108. Assigns \a other to this conditional formatting and returns a reference to
  109. this conditional formatting.
  110. */
  111. ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other)
  112. {
  113. this->d = other.d;
  114. return *this;
  115. }
  116. /*!
  117. * Destroy the object.
  118. */
  119. ConditionalFormatting::~ConditionalFormatting()
  120. {
  121. }
  122. /*!
  123. * Add a hightlight rule with the given \a type, \a formula1, \a formula2,
  124. * \a format and \a stopIfTrue.
  125. * Return false if failed.
  126. */
  127. bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue)
  128. {
  129. if (format.isEmpty())
  130. return false;
  131. bool skipFormula = false;
  132. QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
  133. if (type >= Highlight_LessThan && type <= Highlight_NotBetween) {
  134. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs");
  135. QString op;
  136. switch (type) {
  137. case Highlight_Between: op = QStringLiteral("between"); break;
  138. case Highlight_Equal: op = QStringLiteral("equal"); break;
  139. case Highlight_GreaterThan: op = QStringLiteral("greaterThan"); break;
  140. case Highlight_GreaterThanOrEqual: op = QStringLiteral("greaterThanOrEqual"); break;
  141. case Highlight_LessThan: op = QStringLiteral("lessThan"); break;
  142. case Highlight_LessThanOrEqual: op = QStringLiteral("lessThanOrEqual"); break;
  143. case Highlight_NotBetween: op = QStringLiteral("notBetween"); break;
  144. case Highlight_NotEqual: op = QStringLiteral("notEqual"); break;
  145. default: break;
  146. }
  147. cfRule->attrs[XlsxCfRuleData::A_operator] = op;
  148. } else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) {
  149. if (type == Highlight_ContainsText) {
  150. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText");
  151. cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText");
  152. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1);
  153. } else if (type == Highlight_NotContainsText) {
  154. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText");
  155. cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains");
  156. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1);
  157. } else if (type == Highlight_BeginsWith) {
  158. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith");
  159. cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith");
  160. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
  161. } else {
  162. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith");
  163. cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith");
  164. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
  165. }
  166. cfRule->attrs[XlsxCfRuleData::A_text] = formula1;
  167. skipFormula = true;
  168. } else if (type == Highlight_TimePeriod) {
  169. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod");
  170. //:Todo
  171. return false;
  172. } else if (type == Highlight_Duplicate) {
  173. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues");
  174. } else if (type == Highlight_Unique) {
  175. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues");
  176. } else if (type == Highlight_Errors) {
  177. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors");
  178. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)");
  179. skipFormula = true;
  180. } else if (type == Highlight_NoErrors) {
  181. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors");
  182. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))");
  183. skipFormula = true;
  184. } else if (type == Highlight_Blanks) {
  185. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks");
  186. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0");
  187. skipFormula = true;
  188. } else if (type == Highlight_NoBlanks) {
  189. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks");
  190. cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0");
  191. skipFormula = true;
  192. } else if (type >= Highlight_Top && type <= Highlight_BottomPercent) {
  193. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10");
  194. if (type == Highlight_Bottom || type == Highlight_BottomPercent)
  195. cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1");
  196. if (type == Highlight_TopPercent || type == Highlight_BottomPercent)
  197. cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1");
  198. cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10");
  199. skipFormula = true;
  200. } else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) {
  201. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage");
  202. if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3)
  203. cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0");
  204. if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage)
  205. cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1");
  206. if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1)
  207. cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1");
  208. else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2)
  209. cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2");
  210. else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3)
  211. cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3");
  212. } else if (type == Highlight_Expression){
  213. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression");
  214. } else {
  215. return false;
  216. }
  217. cfRule->dxfFormat = format;
  218. if (stopIfTrue)
  219. cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
  220. if (!skipFormula) {
  221. if (!formula1.isEmpty())
  222. cfRule->attrs[XlsxCfRuleData::A_formula1] = formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1;
  223. if (!formula2.isEmpty())
  224. cfRule->attrs[XlsxCfRuleData::A_formula2] = formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2;
  225. }
  226. d->cfRules.append(cfRule);
  227. return true;
  228. }
  229. /*!
  230. * \overload
  231. *
  232. * Add a hightlight rule with the given \a type \a format and \a stopIfTrue.
  233. */
  234. bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue)
  235. {
  236. if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3)
  237. || (type >= Highlight_Duplicate && type <= Highlight_NoErrors)) {
  238. return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue);
  239. }
  240. return false;
  241. }
  242. /*!
  243. * \overload
  244. *
  245. * Add a hightlight rule with the given \a type, \a formula, \a format and \a stopIfTrue.
  246. * Return false if failed.
  247. */
  248. bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula, const Format &format, bool stopIfTrue)
  249. {
  250. if (type == Highlight_Between || type == Highlight_NotBetween)
  251. return false;
  252. return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue);
  253. }
  254. /*!
  255. * Add a dataBar rule with the given \a color, \a type1, \a val1
  256. * , \a type2, \a val2, \a showData and \a stopIfTrue.
  257. * Return false if failed.
  258. */
  259. bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue)
  260. {
  261. QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
  262. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar");
  263. cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color);
  264. if (stopIfTrue)
  265. cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
  266. if (!showData)
  267. cfRule->attrs[XlsxCfRuleData::A_hideData] = true;
  268. XlsxCfVoData cfvo1(type1, val1);
  269. XlsxCfVoData cfvo2(type2, val2);
  270. cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
  271. cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
  272. d->cfRules.append(cfRule);
  273. return true;
  274. }
  275. /*!
  276. * \overload
  277. * Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue.
  278. */
  279. bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue)
  280. {
  281. return addDataBarRule(color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue);
  282. }
  283. /*!
  284. * Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue.
  285. * Return false if failed.
  286. */
  287. bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue)
  288. {
  289. ValueObjectType type1 = VOT_Min;
  290. ValueObjectType type2 = VOT_Max;
  291. QString val1 = QStringLiteral("0");
  292. QString val2 = QStringLiteral("0");
  293. QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
  294. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
  295. cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
  296. cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor);
  297. if (stopIfTrue)
  298. cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
  299. XlsxCfVoData cfvo1(type1, val1);
  300. XlsxCfVoData cfvo2(type2, val2);
  301. cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
  302. cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
  303. d->cfRules.append(cfRule);
  304. return true;
  305. }
  306. /*!
  307. * Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue.
  308. * Return false if failed.
  309. */
  310. bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue)
  311. {
  312. ValueObjectType type1 = VOT_Min;
  313. ValueObjectType type2 = VOT_Percent;
  314. ValueObjectType type3 = VOT_Max;
  315. QString val1 = QStringLiteral("0");
  316. QString val2 = QStringLiteral("50");
  317. QString val3 = QStringLiteral("0");
  318. QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
  319. cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
  320. cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
  321. cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor);
  322. cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor);
  323. if (stopIfTrue)
  324. cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
  325. XlsxCfVoData cfvo1(type1, val1);
  326. XlsxCfVoData cfvo2(type2, val2);
  327. XlsxCfVoData cfvo3(type3, val3);
  328. cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
  329. cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
  330. cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3);
  331. d->cfRules.append(cfRule);
  332. return true;
  333. }
  334. /*!
  335. Returns the ranges on which the validation will be applied.
  336. */
  337. QList<CellRange> ConditionalFormatting::ranges() const
  338. {
  339. return d->ranges;
  340. }
  341. /*!
  342. Add the \a cell on which the conditional formatting will apply to.
  343. */
  344. void ConditionalFormatting::addCell(const CellReference &cell)
  345. {
  346. d->ranges.append(CellRange(cell, cell));
  347. }
  348. /*!
  349. \overload
  350. Add the cell(\a row, \a col) on which the conditional formatting will apply to.
  351. */
  352. void ConditionalFormatting::addCell(int row, int col)
  353. {
  354. d->ranges.append(CellRange(row, col, row, col));
  355. }
  356. /*!
  357. \overload
  358. Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
  359. which the conditional formatting will apply to.
  360. */
  361. void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
  362. {
  363. d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
  364. }
  365. /*!
  366. Add the \a range on which the conditional formatting will apply to.
  367. */
  368. void ConditionalFormatting::addRange(const CellRange &range)
  369. {
  370. d->ranges.append(range);
  371. }
  372. bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *rule, Styles *styles)
  373. {
  374. Q_ASSERT(reader.name() == QLatin1String("cfRule"));
  375. QXmlStreamAttributes attrs = reader.attributes();
  376. if (attrs.hasAttribute(QLatin1String("type")))
  377. rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString();
  378. if (attrs.hasAttribute(QLatin1String("dxfId"))) {
  379. int id = attrs.value(QLatin1String("dxfId")).toString().toInt();
  380. if (styles)
  381. rule->dxfFormat = styles->dxfFormat(id);
  382. else
  383. rule->dxfFormat.setDxfIndex(id);
  384. }
  385. rule->priority = attrs.value(QLatin1String("priority")).toString().toInt();
  386. if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) {
  387. //default is false
  388. rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1");
  389. }
  390. if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) {
  391. //default is true
  392. rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0");
  393. }
  394. if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) {
  395. //default is false
  396. rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1");
  397. }
  398. if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) {
  399. //default is false
  400. rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1");
  401. }
  402. if (attrs.hasAttribute(QLatin1String("operator")))
  403. rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString();
  404. if (attrs.hasAttribute(QLatin1String("text")))
  405. rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString();
  406. if (attrs.hasAttribute(QLatin1String("timePeriod")))
  407. rule->attrs[XlsxCfRuleData::A_timePeriod] = attrs.value(QLatin1String("timePeriod")).toString();
  408. if (attrs.hasAttribute(QLatin1String("rank")))
  409. rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString();
  410. if (attrs.hasAttribute(QLatin1String("stdDev")))
  411. rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString();
  412. if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) {
  413. //default is false
  414. rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1");
  415. }
  416. while (!reader.atEnd()) {
  417. reader.readNextStartElement();
  418. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  419. if (reader.name() == QLatin1String("formula")) {
  420. const QString f = reader.readElementText();
  421. if (!rule->attrs.contains(XlsxCfRuleData::A_formula1))
  422. rule->attrs[XlsxCfRuleData::A_formula1] = f;
  423. else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2))
  424. rule->attrs[XlsxCfRuleData::A_formula2] = f;
  425. else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3))
  426. rule->attrs[XlsxCfRuleData::A_formula3] = f;
  427. } else if (reader.name() == QLatin1String("dataBar")) {
  428. readCfDataBar(reader, rule);
  429. } else if (reader.name() == QLatin1String("colorScale")) {
  430. readCfColorScale(reader, rule);
  431. }
  432. }
  433. if (reader.tokenType() == QXmlStreamReader::EndElement
  434. && reader.name() == QStringLiteral("conditionalFormatting")) {
  435. break;
  436. }
  437. }
  438. return true;
  439. }
  440. bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule)
  441. {
  442. Q_ASSERT(reader.name() == QLatin1String("dataBar"));
  443. QXmlStreamAttributes attrs = reader.attributes();
  444. if (attrs.value(QLatin1String("showValue")) == QLatin1String("0"))
  445. rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1");
  446. while (!reader.atEnd()) {
  447. reader.readNextStartElement();
  448. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  449. if (reader.name() == QLatin1String("cfvo")) {
  450. XlsxCfVoData data;
  451. readCfVo(reader, data);
  452. if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
  453. rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
  454. else
  455. rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
  456. } else if (reader.name() == QLatin1String("color")) {
  457. XlsxColor color;
  458. color.loadFromXml(reader);
  459. rule->attrs[XlsxCfRuleData::A_color1] = color;
  460. }
  461. }
  462. if (reader.tokenType() == QXmlStreamReader::EndElement
  463. && reader.name() == QStringLiteral("dataBar")) {
  464. break;
  465. }
  466. }
  467. return true;
  468. }
  469. bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule)
  470. {
  471. Q_ASSERT(reader.name() == QLatin1String("colorScale"));
  472. while (!reader.atEnd()) {
  473. reader.readNextStartElement();
  474. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  475. if (reader.name() == QLatin1String("cfvo")) {
  476. XlsxCfVoData data;
  477. readCfVo(reader, data);
  478. if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
  479. rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
  480. else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2))
  481. rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
  482. else
  483. rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
  484. } else if (reader.name() == QLatin1String("color")) {
  485. XlsxColor color;
  486. color.loadFromXml(reader);
  487. if (!rule->attrs.contains(XlsxCfRuleData::A_color1))
  488. rule->attrs[XlsxCfRuleData::A_color1] = color;
  489. else if (!rule->attrs.contains(XlsxCfRuleData::A_color2))
  490. rule->attrs[XlsxCfRuleData::A_color2] = color;
  491. else
  492. rule->attrs[XlsxCfRuleData::A_color3] = color;
  493. }
  494. }
  495. if (reader.tokenType() == QXmlStreamReader::EndElement
  496. && reader.name() == QStringLiteral("colorScale")) {
  497. break;
  498. }
  499. }
  500. return true;
  501. }
  502. bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo)
  503. {
  504. Q_ASSERT(reader.name() == QStringLiteral("cfvo"));
  505. QXmlStreamAttributes attrs = reader.attributes();
  506. QString type = attrs.value(QLatin1String("type")).toString();
  507. ConditionalFormatting::ValueObjectType t;
  508. if (type == QLatin1String("formula"))
  509. t = ConditionalFormatting::VOT_Formula;
  510. else if (type == QLatin1String("max"))
  511. t = ConditionalFormatting::VOT_Max;
  512. else if (type == QLatin1String("min"))
  513. t = ConditionalFormatting::VOT_Min;
  514. else if (type == QLatin1String("num"))
  515. t = ConditionalFormatting::VOT_Num;
  516. else if (type == QLatin1String("percent"))
  517. t = ConditionalFormatting::VOT_Percent;
  518. else //if (type == QLatin1String("percentile"))
  519. t = ConditionalFormatting::VOT_Percentile;
  520. cfvo.type = t;
  521. cfvo.value = attrs.value(QLatin1String("val")).toString();
  522. if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) {
  523. //default is true
  524. cfvo.gte = false;
  525. }
  526. return true;
  527. }
  528. bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles)
  529. {
  530. Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting"));
  531. d->ranges.clear();
  532. d->cfRules.clear();
  533. QXmlStreamAttributes attrs = reader.attributes();
  534. const QString sqref = attrs.value(QLatin1String("sqref")).toString();
  535. const auto sqrefParts = sqref.split(QLatin1Char(' '));
  536. for (const QString &range : sqrefParts) {
  537. this->addRange(range);
  538. }
  539. while (!reader.atEnd()) {
  540. reader.readNextStartElement();
  541. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  542. if (reader.name() == QLatin1String("cfRule")) {
  543. QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
  544. d->readCfRule(reader, cfRule.data(), styles);
  545. d->cfRules.append(cfRule);
  546. }
  547. }
  548. if (reader.tokenType() == QXmlStreamReader::EndElement
  549. && reader.name() == QStringLiteral("conditionalFormatting")) {
  550. break;
  551. }
  552. }
  553. return true;
  554. }
  555. bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const
  556. {
  557. writer.writeStartElement(QStringLiteral("conditionalFormatting"));
  558. QStringList sqref;
  559. const auto rangeList = ranges();
  560. for (const CellRange &range : rangeList) {
  561. sqref.append(range.toString());
  562. }
  563. writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" ")));
  564. for (int i=0; i<d->cfRules.size(); ++i) {
  565. const QSharedPointer<XlsxCfRuleData> &rule = d->cfRules[i];
  566. writer.writeStartElement(QStringLiteral("cfRule"));
  567. writer.writeAttribute(QStringLiteral("type"), rule->attrs[XlsxCfRuleData::A_type].toString());
  568. if (rule->dxfFormat.dxfIndexValid())
  569. writer.writeAttribute(QStringLiteral("dxfId"), QString::number(rule->dxfFormat.dxfIndex()));
  570. writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority));
  571. auto it = rule->attrs.constFind(XlsxCfRuleData::A_stopIfTrue);
  572. if (it != rule->attrs.constEnd())
  573. writer.writeAttribute(QStringLiteral("stopIfTrue"), it.value().toString());
  574. it = rule->attrs.constFind(XlsxCfRuleData::A_aboveAverage);
  575. if (it != rule->attrs.constEnd())
  576. writer.writeAttribute(QStringLiteral("aboveAverage"), it.value().toString());
  577. it = rule->attrs.constFind(XlsxCfRuleData::A_percent);
  578. if (it != rule->attrs.constEnd())
  579. writer.writeAttribute(QStringLiteral("percent"), it.value().toString());
  580. it = rule->attrs.constFind(XlsxCfRuleData::A_bottom);
  581. if (it != rule->attrs.constEnd())
  582. writer.writeAttribute(QStringLiteral("bottom"), it.value().toString());
  583. it = rule->attrs.constFind(XlsxCfRuleData::A_operator);
  584. if (it != rule->attrs.constEnd())
  585. writer.writeAttribute(QStringLiteral("operator"), it.value().toString());
  586. it = rule->attrs.constFind(XlsxCfRuleData::A_text);
  587. if (it != rule->attrs.constEnd())
  588. writer.writeAttribute(QStringLiteral("text"), it.value().toString());
  589. it = rule->attrs.constFind(XlsxCfRuleData::A_timePeriod);
  590. if (it != rule->attrs.constEnd())
  591. writer.writeAttribute(QStringLiteral("timePeriod"), it.value().toString());
  592. it = rule->attrs.constFind(XlsxCfRuleData::A_rank);
  593. if (it != rule->attrs.constEnd())
  594. writer.writeAttribute(QStringLiteral("rank"), it.value().toString());
  595. it = rule->attrs.constFind(XlsxCfRuleData::A_stdDev);
  596. if (it != rule->attrs.constEnd())
  597. writer.writeAttribute(QStringLiteral("stdDev"), it.value().toString());
  598. it = rule->attrs.constFind(XlsxCfRuleData::A_equalAverage);
  599. if (it != rule->attrs.constEnd())
  600. writer.writeAttribute(QStringLiteral("equalAverage"), it.value().toString());
  601. if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) {
  602. writer.writeStartElement(QStringLiteral("dataBar"));
  603. if (rule->attrs.contains(XlsxCfRuleData::A_hideData))
  604. writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0"));
  605. d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
  606. d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
  607. rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
  608. writer.writeEndElement();//dataBar
  609. } else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) {
  610. writer.writeStartElement(QStringLiteral("colorScale"));
  611. d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
  612. d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
  613. it = rule->attrs.constFind(XlsxCfRuleData::A_cfvo3);
  614. if (it != rule->attrs.constEnd())
  615. d->writeCfVo(writer, it.value().value<XlsxCfVoData>());
  616. rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
  617. rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer);
  618. it = rule->attrs.constFind(XlsxCfRuleData::A_color3);
  619. if (it != rule->attrs.constEnd())
  620. it.value().value<XlsxColor>().saveToXml(writer);
  621. writer.writeEndElement();//colorScale
  622. }
  623. it = rule->attrs.constFind(XlsxCfRuleData::A_formula1_temp);
  624. if (it != rule->attrs.constEnd()) {
  625. QString str = ( ranges().begin() )->toString();
  626. QString startCell = *( str.split(QLatin1Char(':')).begin() );
  627. writer.writeTextElement(QStringLiteral("formula"), it.value().toString().arg(startCell));
  628. } else if ((it = rule->attrs.constFind(XlsxCfRuleData::A_formula1)) != rule->attrs.constEnd()) {
  629. writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
  630. }
  631. it = rule->attrs.constFind(XlsxCfRuleData::A_formula2);
  632. if (it != rule->attrs.constEnd())
  633. writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
  634. it = rule->attrs.constFind(XlsxCfRuleData::A_formula3);
  635. if (it != rule->attrs.constEnd())
  636. writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
  637. writer.writeEndElement(); //cfRule
  638. }
  639. writer.writeEndElement(); //conditionalFormatting
  640. return true;
  641. }
  642. QT_END_NAMESPACE_XLSX