xlsxconditionalformatting.cpp 30 KB

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