File indexing completed on 2025-03-23 03:32:46
0001 // xlsxcellformula.cpp 0002 0003 #include <QtGlobal> 0004 #include <QObject> 0005 #include <QString> 0006 #include <QXmlStreamReader> 0007 #include <QXmlStreamWriter> 0008 #include <QDebug> 0009 0010 #include "xlsxcellformula.h" 0011 #include "xlsxcellformula_p.h" 0012 #include "xlsxutility_p.h" 0013 0014 QT_BEGIN_NAMESPACE_XLSX 0015 0016 CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_) 0017 :formula(formula_), type(type_), reference(ref_), ca(false), si(0) 0018 { 0019 //Remove the formula '=' sign if exists 0020 if (formula.startsWith(QLatin1String("="))) 0021 formula.remove(0,1); 0022 else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}"))) 0023 formula = formula.mid(2, formula.length()-3); 0024 } 0025 0026 CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other) 0027 : QSharedData(other) 0028 , formula(other.formula), type(other.type), reference(other.reference) 0029 , ca(other.ca), si(other.si) 0030 { 0031 0032 } 0033 0034 CellFormulaPrivate::~CellFormulaPrivate() 0035 { 0036 0037 } 0038 0039 /*! 0040 \class CellFormula 0041 \inmodule QtXlsx 0042 \brief The CellFormula class provides a API that is used to handle the cell formula. 0043 0044 */ 0045 0046 /*! 0047 \enum CellFormula::FormulaType 0048 \value NormalType 0049 \value ArrayType 0050 \value DataTableType 0051 \value SharedType 0052 */ 0053 0054 /*! 0055 * Creates a new formula. 0056 */ 0057 CellFormula::CellFormula() 0058 { 0059 //The d pointer is initialized with a null pointer 0060 } 0061 0062 /*! 0063 * Creates a new formula with the given \a formula and \a type. 0064 */ 0065 CellFormula::CellFormula(const char *formula, FormulaType type) 0066 :d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type)) 0067 { 0068 0069 } 0070 0071 /*! 0072 * Creates a new formula with the given \a formula and \a type. 0073 */ 0074 CellFormula::CellFormula(const QString &formula, FormulaType type) 0075 :d(new CellFormulaPrivate(formula, CellRange(), type)) 0076 { 0077 0078 } 0079 0080 /*! 0081 * Creates a new formula with the given \a formula, \a ref and \a type. 0082 */ 0083 CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type) 0084 :d(new CellFormulaPrivate(formula, ref, type)) 0085 { 0086 0087 } 0088 0089 /*! 0090 Creates a new formula with the same attributes as the \a other formula. 0091 */ 0092 CellFormula::CellFormula(const CellFormula &other) 0093 :d(other.d) 0094 { 0095 } 0096 0097 /*! 0098 Assigns the \a other formula to this formula, and returns a 0099 reference to this formula. 0100 */ 0101 CellFormula &CellFormula::operator =(const CellFormula &other) 0102 { 0103 d = other.d; 0104 return *this; 0105 } 0106 0107 /*! 0108 * Destroys this formula. 0109 */ 0110 CellFormula::~CellFormula() 0111 { 0112 0113 } 0114 0115 /*! 0116 * Returns the type of the formula. 0117 */ 0118 CellFormula::FormulaType CellFormula::formulaType() const 0119 { 0120 return d ? d->type : NormalType; 0121 } 0122 0123 /*! 0124 * Returns the contents of the formula. 0125 */ 0126 QString CellFormula::formulaText() const 0127 { 0128 return d ? d->formula : QString(); 0129 } 0130 0131 /*! 0132 * Returns the reference cells of the formula. For normal formula, 0133 * this will return an invalid CellRange object. 0134 */ 0135 CellRange CellFormula::reference() const 0136 { 0137 return d ? d->reference : CellRange(); 0138 } 0139 0140 /*! 0141 * Returns whether the formula is valid. 0142 */ 0143 bool CellFormula::isValid() const 0144 { 0145 return d; 0146 } 0147 0148 /*! 0149 * Returns the shared index for shared formula. 0150 */ 0151 int CellFormula::sharedIndex() const 0152 { 0153 return d && d->type == SharedType ? d->si : (-1); 0154 } 0155 0156 /* aca (Always Calculate Array) // not-implmented attribute 0157 * 0158 * Only applies to array formulas. 0159 * 0160 * true indicates that the entire array shall be calculated in full. 0161 * If false the individual cells of the array shall be calculated as needed. 0162 * 0163 * The aca value shall be ignored unless the value of the corresponding 0164 * t attribute is array. 0165 * 0166 * [Note: The primary case where an array formula must be calculated in 0167 * part instead of in full is when some cells in the array depend on other 0168 * cells that are semi-calculated, e.g., contains the function =(). end note] 0169 * 0170 * The possible values for this attribute are defined by the W3C XML Schema 0171 * boolean datatype. 0172 */ 0173 0174 /* bx (Assigns Value to Name) // not-implmented attribute 0175 * 0176 * Specifies that this formula assigns a value to a name. 0177 * 0178 * The possible values for this attribute are defined by the W3C XML 0179 * Schema boolean datatype. 0180 */ 0181 0182 /* del1 (Input 1 Deleted) // not-implmented attribute 0183 * 0184 * Whether the first input cell for data table has been deleted. 0185 * Applies to data table formula only. Written on master cell of data table 0186 * formula only. 0187 * 0188 * The possible values for this attribute are defined by the W3C XML Schema 0189 * boolean datatype. 0190 */ 0191 0192 /* del2 (Input 2 Deleted) // not-impplmented attribute 0193 * 0194 * Whether the second input cell for data table has been deleted. 0195 * Applies to data table formula only. Written on master cell of data 0196 * table formula only. 0197 * 0198 * The possible values for this attribute are defined by the W3C XML Schema 0199 * boolean datatype. 0200 */ 0201 0202 /* dt2D (Data Table 2-D) // not-implmented attribute 0203 * 0204 * Data table is two-dimentional. Only applies to the data tables function. 0205 * Written on master cell of data table formula only. 0206 * 0207 * The possible values for this attribute are defined by the W3C XML Schema 0208 * boolean datatype. 0209 */ 0210 0211 /* dtr (Data Table Row) // not-implmented attribute 0212 * 0213 * true if one-dimentional data table is a row, otherwise it's a column. 0214 * Only applies to the data tables function. Written on master cell of data 0215 * table formula only. 0216 * 0217 * The possible values for this attribute are defined by the W3C XML Schema 0218 * boolean datatype. 0219 */ 0220 0221 /* r1 (Data Table Cell 1) // not-implmented attribute 0222 * 0223 * First input cell for data table. Only applies to the data tables array 0224 * function "TABLE()". Written on master cell of data table formula only. 0225 * 0226 * The possible values for this attribute are defined by the ST_CellRef 0227 * simple type (§18.18.7). 0228 */ 0229 0230 /* r2 (Input Cell 2) // not-implmented attribute 0231 * 0232 * Second input cell for data table when dt2D is '1'. Only applies to the 0233 * data tables array function "TABLE()".Written on master cell of data table 0234 * formula only. 0235 * 0236 * The possible values for this attribute are defined by the ST_CellRef 0237 * simple type (§18.18.7). 0238 */ 0239 0240 /*! 0241 * \internal 0242 * \remark pair with loadFromXml() 0243 */ 0244 bool CellFormula::saveToXml(QXmlStreamWriter &writer) const 0245 { 0246 0247 // t (Formula Type) 0248 // 0249 // Type of formula. 0250 // The possible values for this attribute are defined by the 0251 // ST_CellFormulaType simple type (§18.18.6). 0252 // 0253 // 18.18.6 ST_CellFormulaType (Formula Type) 0254 // array (Array Formula) 0255 // dataTable (Table Formula) 0256 // normal (Normal) 0257 // shared (Shared Formula) 0258 0259 QString t; 0260 switch (d->type) 0261 { 0262 case CellFormula::ArrayType: 0263 t = QStringLiteral("array"); 0264 break; 0265 case CellFormula::SharedType: 0266 t = QStringLiteral("shared"); 0267 break; 0268 case CellFormula::NormalType: 0269 t = QStringLiteral("normal"); 0270 break; 0271 case CellFormula::DataTableType: 0272 t = QStringLiteral("dataTable"); 0273 break; 0274 default: // undefined type 0275 return false; 0276 break; 0277 } 0278 0279 // f (Formula) 0280 // 0281 // Formula for the cell. The formula expression is contained in the 0282 // character node of this element. 0283 writer.writeStartElement(QStringLiteral("f")); 0284 0285 if (!t.isEmpty()) 0286 { 0287 writer.writeAttribute(QStringLiteral("t"), t); // write type(t) 0288 } 0289 0290 // ref (Range of Cells) 0291 // 0292 // Range of cells which the formula applies to. 0293 // Only required for shared formula, array formula or data table. 0294 // Only written on the master formula, 0295 // not subsequent formulas belonging to the same shared group, array, 0296 // or data table. 0297 // The possible values for this attribute are defined by the ST_Ref 0298 // simple type (§18.18.62). 0299 0300 if ( d->type == CellFormula::SharedType || 0301 d->type == CellFormula::ArrayType || 0302 d->type == CellFormula::DataTableType ) 0303 { 0304 if (d->reference.isValid()) 0305 { 0306 writer.writeAttribute(QStringLiteral("ref"), d->reference.toString()); 0307 } 0308 } 0309 0310 // ca (Calculate Cell) 0311 // 0312 // Indicates that this formula needs to be recalculated the next time 0313 // calculation is performed. [Example: This is always set on volatile 0314 // functions, like =(), and circular references. end example] 0315 // The possible values for this attribute are defined by the W3C XML 0316 // Schema boolean datatype. 0317 // 0318 // 3.2.2 boolean 0319 // 3.2.2.1 Lexical representation 0320 // An instance of a datatype that is defined as ·boolean· can have the 0321 // following legal literals {true, false, 1, 0}. 0322 0323 if (d->ca) 0324 { 0325 writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1")); 0326 } 0327 0328 // si (Shared Group Index) 0329 // Optional attribute to optimize load performance by sharing formulas. 0330 // 0331 // When a formula is a shared formula (t value is shared) then this value 0332 // indicates the group to which this particular cell's formula belongs. The 0333 // first formula in a group of shared formulas is saved in the f element. 0334 // This is considered the 'master' formula cell. Subsequent cells sharing 0335 // this formula need not have the formula written in their f element. 0336 // Instead, the attribute si value for a particular cell is used to figure 0337 // what the formula expression should be based on the cell's relative 0338 // location to the master formula cell. 0339 0340 if (d->type == CellFormula::SharedType) 0341 { 0342 int si = d->si; 0343 writer.writeAttribute(QStringLiteral("si"), QString::number(si)); 0344 } 0345 0346 if (!d->formula.isEmpty()) 0347 { 0348 QString strFormula = d->formula; 0349 writer.writeCharacters(strFormula); // write formula 0350 } 0351 0352 writer.writeEndElement(); // f 0353 0354 return true; 0355 } 0356 0357 /*! 0358 * \internal 0359 * \remark pair with saveToXml() 0360 */ 0361 bool CellFormula::loadFromXml(QXmlStreamReader &reader) 0362 { 0363 Q_ASSERT(reader.name() == QLatin1String("f")); 0364 if (!d) 0365 d = new CellFormulaPrivate(QString(), CellRange(), NormalType); 0366 0367 QXmlStreamAttributes attributes = reader.attributes(); 0368 QString typeString = attributes.value(QLatin1String("t")).toString(); 0369 0370 // branch: shared-formula 0371 // 0372 if (typeString == QLatin1String("array")) { 0373 d->type = ArrayType; 0374 } 0375 else if (typeString == QLatin1String("shared")) { 0376 d->type = SharedType; 0377 } 0378 else if (typeString == QLatin1String("normal")) { 0379 d->type = NormalType; 0380 } 0381 else if (typeString == QLatin1String("dataTable")) { 0382 d->type = DataTableType; 0383 } 0384 else { 0385 /* 0386 // undefined type 0387 // qDebug() << "Undefined type" << typeString; 0388 return false; 0389 // */ 0390 0391 // dev40 {{ 0392 // https://github.com/QtExcel/QXlsx/issues/38 0393 d->type = NormalType; // Change: normal Type is not mentioned in the xml file!!!!! 0394 // }} 0395 } 0396 0397 // branch: shared-formula 0398 // 0399 // ref (Range of Cells) 0400 // Range of cells which the formula applies to. 0401 // Only required for shared formula, array formula or data table. 0402 if ( d->type == CellFormula::SharedType || 0403 d->type == CellFormula::ArrayType || 0404 d->type == CellFormula::DataTableType ) 0405 { 0406 if (attributes.hasAttribute(QLatin1String("ref"))) 0407 { 0408 QString refString = attributes.value(QLatin1String("ref")).toString(); 0409 d->reference = CellRange(refString); 0410 } 0411 } 0412 0413 // branch: shared-formula 0414 // 0415 // si (Shared Group Index) 0416 // Optional attribute to optimize load performance by sharing formulas. 0417 // When a formula is a shared formula (t value is shared) then this value 0418 // indicates the group to which this particular cell's formula belongs. 0419 if ( d->type == CellFormula::SharedType ) 0420 { 0421 QString ca = attributes.value(QLatin1String("si")).toString(); 0422 d->ca = parseXsdBoolean(ca, false); 0423 0424 if (attributes.hasAttribute(QLatin1String("si"))) 0425 { 0426 d->si = attributes.value(QLatin1String("si")).toInt(); 0427 } 0428 } 0429 0430 d->formula = reader.readElementText(); // read formula 0431 0432 return true; 0433 } 0434 0435 /*! 0436 * \internal 0437 */ 0438 bool CellFormula::operator ==(const CellFormula &formula) const 0439 { 0440 return d->formula == formula.d->formula && d->type == formula.d->type 0441 && d->si ==formula.d->si; 0442 } 0443 0444 /*! 0445 * \internal 0446 */ 0447 bool CellFormula::operator !=(const CellFormula &formula) const 0448 { 0449 return d->formula != formula.d->formula || d->type != formula.d->type 0450 || d->si !=formula.d->si; 0451 } 0452 0453 QT_END_NAMESPACE_XLSX