xlsxcellformula.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // xlsxcellformula.cpp
  2. #include <QtGlobal>
  3. #include <QObject>
  4. #include <QString>
  5. #include <QXmlStreamReader>
  6. #include <QXmlStreamWriter>
  7. #include <QDebug>
  8. #include "xlsxcellformula.h"
  9. #include "xlsxcellformula_p.h"
  10. #include "xlsxutility_p.h"
  11. QT_BEGIN_NAMESPACE_XLSX
  12. CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_)
  13. :formula(formula_), type(type_), reference(ref_), ca(false), si(0)
  14. {
  15. //Remove the formula '=' sign if exists
  16. if (formula.startsWith(QLatin1String("=")))
  17. formula.remove(0,1);
  18. else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}")))
  19. formula = formula.mid(2, formula.length()-3);
  20. }
  21. CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other)
  22. : QSharedData(other)
  23. , formula(other.formula), type(other.type), reference(other.reference)
  24. , ca(other.ca), si(other.si)
  25. {
  26. }
  27. CellFormulaPrivate::~CellFormulaPrivate()
  28. {
  29. }
  30. /*!
  31. \class CellFormula
  32. \inmodule QtXlsx
  33. \brief The CellFormula class provides a API that is used to handle the cell formula.
  34. */
  35. /*!
  36. \enum CellFormula::FormulaType
  37. \value NormalType
  38. \value ArrayType
  39. \value DataTableType
  40. \value SharedType
  41. */
  42. /*!
  43. * Creates a new formula.
  44. */
  45. CellFormula::CellFormula()
  46. {
  47. //The d pointer is initialized with a null pointer
  48. }
  49. /*!
  50. * Creates a new formula with the given \a formula and \a type.
  51. */
  52. CellFormula::CellFormula(const char *formula, FormulaType type)
  53. :d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type))
  54. {
  55. }
  56. /*!
  57. * Creates a new formula with the given \a formula and \a type.
  58. */
  59. CellFormula::CellFormula(const QString &formula, FormulaType type)
  60. :d(new CellFormulaPrivate(formula, CellRange(), type))
  61. {
  62. }
  63. /*!
  64. * Creates a new formula with the given \a formula, \a ref and \a type.
  65. */
  66. CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type)
  67. :d(new CellFormulaPrivate(formula, ref, type))
  68. {
  69. }
  70. /*!
  71. Creates a new formula with the same attributes as the \a other formula.
  72. */
  73. CellFormula::CellFormula(const CellFormula &other)
  74. :d(other.d)
  75. {
  76. }
  77. /*!
  78. Assigns the \a other formula to this formula, and returns a
  79. reference to this formula.
  80. */
  81. CellFormula &CellFormula::operator =(const CellFormula &other)
  82. {
  83. d = other.d;
  84. return *this;
  85. }
  86. /*!
  87. * Destroys this formula.
  88. */
  89. CellFormula::~CellFormula()
  90. {
  91. }
  92. /*!
  93. * Returns the type of the formula.
  94. */
  95. CellFormula::FormulaType CellFormula::formulaType() const
  96. {
  97. return d ? d->type : NormalType;
  98. }
  99. /*!
  100. * Returns the contents of the formula.
  101. */
  102. QString CellFormula::formulaText() const
  103. {
  104. return d ? d->formula : QString();
  105. }
  106. /*!
  107. * Returns the reference cells of the formula. For normal formula,
  108. * this will return an invalid CellRange object.
  109. */
  110. CellRange CellFormula::reference() const
  111. {
  112. return d ? d->reference : CellRange();
  113. }
  114. /*!
  115. * Returns whether the formula is valid.
  116. */
  117. bool CellFormula::isValid() const
  118. {
  119. return d;
  120. }
  121. /*!
  122. * Returns the shared index for shared formula.
  123. */
  124. int CellFormula::sharedIndex() const
  125. {
  126. return d && d->type == SharedType ? d->si : (-1);
  127. }
  128. /* aca (Always Calculate Array) // not-implmented attribute
  129. *
  130. * Only applies to array formulas.
  131. *
  132. * true indicates that the entire array shall be calculated in full.
  133. * If false the individual cells of the array shall be calculated as needed.
  134. *
  135. * The aca value shall be ignored unless the value of the corresponding
  136. * t attribute is array.
  137. *
  138. * [Note: The primary case where an array formula must be calculated in
  139. * part instead of in full is when some cells in the array depend on other
  140. * cells that are semi-calculated, e.g., contains the function =(). end note]
  141. *
  142. * The possible values for this attribute are defined by the W3C XML Schema
  143. * boolean datatype.
  144. */
  145. /* bx (Assigns Value to Name) // not-implmented attribute
  146. *
  147. * Specifies that this formula assigns a value to a name.
  148. *
  149. * The possible values for this attribute are defined by the W3C XML
  150. * Schema boolean datatype.
  151. */
  152. /* del1 (Input 1 Deleted) // not-implmented attribute
  153. *
  154. * Whether the first input cell for data table has been deleted.
  155. * Applies to data table formula only. Written on master cell of data table
  156. * formula only.
  157. *
  158. * The possible values for this attribute are defined by the W3C XML Schema
  159. * boolean datatype.
  160. */
  161. /* del2 (Input 2 Deleted) // not-impplmented attribute
  162. *
  163. * Whether the second input cell for data table has been deleted.
  164. * Applies to data table formula only. Written on master cell of data
  165. * table formula only.
  166. *
  167. * The possible values for this attribute are defined by the W3C XML Schema
  168. * boolean datatype.
  169. */
  170. /* dt2D (Data Table 2-D) // not-implmented attribute
  171. *
  172. * Data table is two-dimentional. Only applies to the data tables function.
  173. * Written on master cell of data table formula only.
  174. *
  175. * The possible values for this attribute are defined by the W3C XML Schema
  176. * boolean datatype.
  177. */
  178. /* dtr (Data Table Row) // not-implmented attribute
  179. *
  180. * true if one-dimentional data table is a row, otherwise it's a column.
  181. * Only applies to the data tables function. Written on master cell of data
  182. * table formula only.
  183. *
  184. * The possible values for this attribute are defined by the W3C XML Schema
  185. * boolean datatype.
  186. */
  187. /* r1 (Data Table Cell 1) // not-implmented attribute
  188. *
  189. * First input cell for data table. Only applies to the data tables array
  190. * function "TABLE()". Written on master cell of data table formula only.
  191. *
  192. * The possible values for this attribute are defined by the ST_CellRef
  193. * simple type (§18.18.7).
  194. */
  195. /* r2 (Input Cell 2) // not-implmented attribute
  196. *
  197. * Second input cell for data table when dt2D is '1'. Only applies to the
  198. * data tables array function "TABLE()".Written on master cell of data table
  199. * formula only.
  200. *
  201. * The possible values for this attribute are defined by the ST_CellRef
  202. * simple type (§18.18.7).
  203. */
  204. /*!
  205. * \internal
  206. * \remark pair with loadFromXml()
  207. */
  208. bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
  209. {
  210. // t (Formula Type)
  211. //
  212. // Type of formula.
  213. // The possible values for this attribute are defined by the
  214. // ST_CellFormulaType simple type (§18.18.6).
  215. //
  216. // 18.18.6 ST_CellFormulaType (Formula Type)
  217. // array (Array Formula)
  218. // dataTable (Table Formula)
  219. // normal (Normal)
  220. // shared (Shared Formula)
  221. QString t;
  222. switch (d->type)
  223. {
  224. case CellFormula::ArrayType:
  225. t = QStringLiteral("array");
  226. break;
  227. case CellFormula::SharedType:
  228. t = QStringLiteral("shared");
  229. break;
  230. case CellFormula::NormalType:
  231. t = QStringLiteral("normal");
  232. break;
  233. case CellFormula::DataTableType:
  234. t = QStringLiteral("dataTable");
  235. break;
  236. default: // undefined type
  237. return false;
  238. break;
  239. }
  240. // f (Formula)
  241. //
  242. // Formula for the cell. The formula expression is contained in the
  243. // character node of this element.
  244. writer.writeStartElement(QStringLiteral("f"));
  245. if (!t.isEmpty())
  246. {
  247. writer.writeAttribute(QStringLiteral("t"), t); // write type(t)
  248. }
  249. // ref (Range of Cells)
  250. //
  251. // Range of cells which the formula applies to.
  252. // Only required for shared formula, array formula or data table.
  253. // Only written on the master formula,
  254. // not subsequent formulas belonging to the same shared group, array,
  255. // or data table.
  256. // The possible values for this attribute are defined by the ST_Ref
  257. // simple type (§18.18.62).
  258. if ( d->type == CellFormula::SharedType ||
  259. d->type == CellFormula::ArrayType ||
  260. d->type == CellFormula::DataTableType )
  261. {
  262. if (d->reference.isValid())
  263. {
  264. writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
  265. }
  266. }
  267. // ca (Calculate Cell)
  268. //
  269. // Indicates that this formula needs to be recalculated the next time
  270. // calculation is performed. [Example: This is always set on volatile
  271. // functions, like =(), and circular references. end example]
  272. // The possible values for this attribute are defined by the W3C XML
  273. // Schema boolean datatype.
  274. //
  275. // 3.2.2 boolean
  276. // 3.2.2.1 Lexical representation
  277. // An instance of a datatype that is defined as ·boolean· can have the
  278. // following legal literals {true, false, 1, 0}.
  279. if (d->ca)
  280. {
  281. writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
  282. }
  283. // si (Shared Group Index)
  284. // Optional attribute to optimize load performance by sharing formulas.
  285. //
  286. // When a formula is a shared formula (t value is shared) then this value
  287. // indicates the group to which this particular cell's formula belongs. The
  288. // first formula in a group of shared formulas is saved in the f element.
  289. // This is considered the 'master' formula cell. Subsequent cells sharing
  290. // this formula need not have the formula written in their f element.
  291. // Instead, the attribute si value for a particular cell is used to figure
  292. // what the formula expression should be based on the cell's relative
  293. // location to the master formula cell.
  294. if (d->type == CellFormula::SharedType)
  295. {
  296. int si = d->si;
  297. writer.writeAttribute(QStringLiteral("si"), QString::number(si));
  298. }
  299. if (!d->formula.isEmpty())
  300. {
  301. QString strFormula = d->formula;
  302. writer.writeCharacters(strFormula); // write formula
  303. }
  304. writer.writeEndElement(); // f
  305. return true;
  306. }
  307. /*!
  308. * \internal
  309. * \remark pair with saveToXml()
  310. */
  311. bool CellFormula::loadFromXml(QXmlStreamReader &reader)
  312. {
  313. Q_ASSERT(reader.name() == QLatin1String("f"));
  314. if (!d)
  315. d = new CellFormulaPrivate(QString(), CellRange(), NormalType);
  316. QXmlStreamAttributes attributes = reader.attributes();
  317. QString typeString = attributes.value(QLatin1String("t")).toString();
  318. // branch: shared-formula
  319. //
  320. if (typeString == QLatin1String("array")) {
  321. d->type = ArrayType;
  322. }
  323. else if (typeString == QLatin1String("shared")) {
  324. d->type = SharedType;
  325. }
  326. else if (typeString == QLatin1String("normal")) {
  327. d->type = NormalType;
  328. }
  329. else if (typeString == QLatin1String("dataTable")) {
  330. d->type = DataTableType;
  331. }
  332. else {
  333. /*
  334. // undefined type
  335. // qDebug() << "Undefined type" << typeString;
  336. return false;
  337. // */
  338. // dev40 {{
  339. // https://github.com/QtExcel/QXlsx/issues/38
  340. d->type = NormalType; // Change: normal Type is not mentioned in the xml file!!!!!
  341. // }}
  342. }
  343. // branch: shared-formula
  344. //
  345. // ref (Range of Cells)
  346. // Range of cells which the formula applies to.
  347. // Only required for shared formula, array formula or data table.
  348. if ( d->type == CellFormula::SharedType ||
  349. d->type == CellFormula::ArrayType ||
  350. d->type == CellFormula::DataTableType )
  351. {
  352. if (attributes.hasAttribute(QLatin1String("ref")))
  353. {
  354. QString refString = attributes.value(QLatin1String("ref")).toString();
  355. d->reference = CellRange(refString);
  356. }
  357. }
  358. // branch: shared-formula
  359. //
  360. // si (Shared Group Index)
  361. // Optional attribute to optimize load performance by sharing formulas.
  362. // When a formula is a shared formula (t value is shared) then this value
  363. // indicates the group to which this particular cell's formula belongs.
  364. if ( d->type == CellFormula::SharedType )
  365. {
  366. QString ca = attributes.value(QLatin1String("si")).toString();
  367. d->ca = parseXsdBoolean(ca, false);
  368. if (attributes.hasAttribute(QLatin1String("si")))
  369. {
  370. d->si = attributes.value(QLatin1String("si")).toString().toInt();
  371. }
  372. }
  373. d->formula = reader.readElementText(); // read formula
  374. return true;
  375. }
  376. /*!
  377. * \internal
  378. */
  379. bool CellFormula::operator ==(const CellFormula &formula) const
  380. {
  381. return d->formula == formula.d->formula && d->type == formula.d->type
  382. && d->si ==formula.d->si;
  383. }
  384. /*!
  385. * \internal
  386. */
  387. bool CellFormula::operator !=(const CellFormula &formula) const
  388. {
  389. return d->formula != formula.d->formula || d->type != formula.d->type
  390. || d->si !=formula.d->si;
  391. }
  392. QT_END_NAMESPACE_XLSX