1 // xlsxcell.cpp
2 
3 #include <cmath>
4 
5 #include <QtGlobal>
6 #include <QDebug>
7 #include <QDateTime>
8 #include <QDate>
9 #include <QTime>
10 
11 #include "xlsxcell.h"
12 #include "xlsxcell_p.h"
13 #include "xlsxformat.h"
14 #include "xlsxformat_p.h"
15 #include "xlsxutility_p.h"
16 #include "xlsxworksheet.h"
17 #include "xlsxworkbook.h"
18 
19 QT_BEGIN_NAMESPACE_XLSX
20 
CellPrivate(Cell * p)21 CellPrivate::CellPrivate(Cell *p) :
22 	q_ptr(p)
23 {
24 
25 }
26 
CellPrivate(const CellPrivate * const cp)27 CellPrivate::CellPrivate(const CellPrivate * const cp)
28     : parent(cp->parent)
29     , cellType(cp->cellType)
30     , value(cp->value)
31     , formula(cp->formula)
32     , format(cp->format)
33     , richString(cp->richString)
34     , styleNumber(cp->styleNumber)
35 {
36 
37 }
38 
39 /*!
40   \class Cell
41   \inmodule QtXlsx
42   \brief The Cell class provides a API that is used to handle the worksheet cell.
43 
44 */
45 
46 /*!
47   \enum Cell::CellType
48   \value BooleanType      Boolean type
49   \value NumberType       Number type, can be blank or used with forumula
50   \value ErrorType        Error type
51   \value SharedStringType Shared string type
52   \value StringType       String type, can be used with forumula
53   \value InlineStringType Inline string type
54   */
55 
56 /*!
57  * \internal
58  * Created by Worksheet only.
59  */
60 // qint32 styleIndex = (-1)
Cell(const QVariant & data,CellType type,const Format & format,Worksheet * parent,qint32 styleIndex)61 Cell::Cell(const QVariant &data,
62 	CellType type,
63 	const Format &format,
64 	Worksheet *parent,
65 	qint32 styleIndex ) :
66 	d_ptr(new CellPrivate(this))
67 {
68 	d_ptr->value = data;
69 	d_ptr->cellType = type;
70 	d_ptr->format = format;
71 	d_ptr->parent = parent;
72 	d_ptr->styleNumber = styleIndex;
73 }
74 
75 /*!
76  * \internal
77  */
Cell(const Cell * const cell)78 Cell::Cell(const Cell * const cell):
79 	d_ptr(new CellPrivate(cell->d_ptr))
80 {
81 	d_ptr->q_ptr = this;
82 }
83 
84 /*!
85  * Destroys the Cell and cleans up.
86  */
~Cell()87 Cell::~Cell()
88 {
89 	if ( NULL != d_ptr )
90 		delete d_ptr;
91 }
92 
93 /*!
94  * Return the dataType of this Cell
95  */
cellType() const96 Cell::CellType Cell::cellType() const
97 {
98 	Q_D(const Cell);
99 
100 	return d->cellType;
101 }
102 
103 /*!
104  * Return the data content of this Cell
105  */
value() const106 QVariant Cell::value() const
107 {
108 	Q_D(const Cell);
109 
110 	return d->value;
111 }
112 
113 /*!
114 * Return the data content of this Cell for reading
115 */
readValue() const116 QVariant Cell::readValue() const
117 {
118 	Q_D(const Cell);
119 
120 	QVariant ret; // return value
121 	ret = d->value;
122 
123 	Format fmt = this->format();
124 
125 	if (isDateTime())
126 	{
127         QVariant vDT = dateTime();
128         if ( vDT.isNull() )
129         {
130             return QVariant();
131         }
132 
133         // https://github.com/QtExcel/QXlsx/issues/171
134         // https://www.qt.io/blog/whats-new-in-qmetatype-qvariant
135         #if QT_VERSION >= 0x060000 // Qt 6.0 or over
136                 if ( vDT.metaType().id() == QMetaType::QDateTime )
137                 {
138                     ret = vDT;
139                 }
140                 else if ( vDT.metaType().id() == QMetaType::QDate )
141                 {
142                     ret = vDT;
143                 }
144                 else if ( vDT.metaType().id() == QMetaType::QTime )
145                 {
146                     ret = vDT;
147                 }
148                 else
149                 {
150                     return QVariant();
151                 }
152         #else
153                 if ( vDT.type() == QVariant::DateTime )
154                 {
155                     ret = vDT;
156                 }
157                 else if ( vDT.type() == QVariant::Date )
158                 {
159                     ret = vDT;
160                 }
161                 else if ( vDT.type() == QVariant::Time )
162                 {
163                     ret = vDT;
164                 }
165                 else
166                 {
167                     return QVariant();
168                 }
169         #endif
170 
171         // QDateTime dt = dateTime();
172         // ret = dt;
173 
174         // QString strFormat = fmt.numberFormat();
175         // if (!strFormat.isEmpty())
176         // {
177         // 	// TODO: use number format
178         // }
179 
180         // qint32 styleNo = d->styleNumber;
181 
182         // if (styleNo == 10)
183         // {
184         // }
185 
186         // if (styleNo == 11)
187         // {
188 			// QTime timeValue = dt.time(); // only time. (HH:mm:ss)
189 			// ret = timeValue;
190 			// return ret;
191         // }
192 
193         // if (styleNo == 12)
194         // {
195         // }
196 
197         // if (styleNo == 13) // (HH:mm:ss)
198         // {
199             // double dValue = d->value.toDouble();
200             // int day = int(dValue); // unit is day.
201             // double deciamlPointValue1 = dValue - double(day);
202 
203             // double dHour = deciamlPointValue1 * (double(1.0) / double(24.0));
204             // int hour = int(dHour);
205 
206             // double deciamlPointValue2 = deciamlPointValue1 - (double(hour) * (double(1.0) / double(24.0)));
207             // double dMin = deciamlPointValue2 * (double(1.0) / double(60.0));
208             // int min = int(dMin);
209 
210             // double deciamlPointValue3 = deciamlPointValue2 - (double(min) * (double(1.0) / double(60.0)));
211             // double dSec = deciamlPointValue3 * (double(1.0) / double(60.0));
212             // int sec = int(dSec);
213 
214             // int totalHour = hour + (day * 24);
215 
216             // QString strTime;
217             // strTime = QString("%1:%2:%3").arg(totalHour).arg(min).arg(sec);
218             // ret = strTime;
219 
220             // return ret;
221         // }
222 
223         // return ret;
224         // */
225 	}
226 
227 	if (hasFormula())
228 	{
229 		QString formulaString = this->formula().formulaText();
230 		ret = formulaString;
231 		return ret; // return formula string
232 	}
233 
234 	return ret;
235 }
236 
237 /*!
238  * Return the style used by this Cell. If no style used, 0 will be returned.
239  */
format() const240 Format Cell::format() const
241 {
242 	Q_D(const Cell);
243 
244 	return d->format;
245 }
246 
247 /*!
248  * Returns true if the cell has one formula.
249  */
hasFormula() const250 bool Cell::hasFormula() const
251 {
252 	Q_D(const Cell);
253 
254 	return d->formula.isValid();
255 }
256 
257 /*!
258  * Return the formula contents if the dataType is Formula
259  */
formula() const260 CellFormula Cell::formula() const
261 {
262 	Q_D(const Cell);
263 
264 	return d->formula;
265 }
266 
267 /*!
268  * Returns whether the value is probably a dateTime or not
269  */
isDateTime() const270 bool Cell::isDateTime() const
271 {
272 	Q_D(const Cell);
273 
274 	Cell::CellType cellType = d->cellType;
275     double dValue = d->value.toDouble(); // number
276 //	QString strValue = d->value.toString().toUtf8();
277 	bool isValidFormat = d->format.isValid();
278     bool isDateTimeFormat = d->format.isDateTimeFormat(); // datetime format
279 
280     // dev67
281     if ( cellType == NumberType ||
282          cellType == DateType ||
283          cellType == CustomType )
284     {
285         if ( dValue >= 0 &&
286              isValidFormat &&
287              isDateTimeFormat )
288         {
289             return true;
290         }
291     }
292 
293 	return false;
294 }
295 
296 /*!
297  * Return the data time value.
298  */
299 /*
300 QDateTime Cell::dateTime() const
301 {
302 	Q_D(const Cell);
303 
304 	if (!isDateTime())
305 		return QDateTime();
306 
307 	return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904());
308 }
309 */
dateTime() const310 QVariant Cell::dateTime() const
311 {
312     Q_D(const Cell);
313 
314     if (!isDateTime())
315     {
316         return QVariant();
317     }
318 
319     // dev57
320 
321     QVariant ret;
322     double dValue = d->value.toDouble();
323     bool isDate1904 = d->parent->workbook()->isDate1904();
324     ret = datetimeFromNumber(dValue, isDate1904);
325     return ret;
326 }
327 
328 /*!
329  * Returns whether the cell is probably a rich string or not
330  */
isRichString() const331 bool Cell::isRichString() const
332 {
333 	Q_D(const Cell);
334 
335     if ( d->cellType != SharedStringType &&
336             d->cellType != InlineStringType &&
337             d->cellType != StringType )
338     {
339 		return false;
340     }
341 
342 	return d->richString.isRichString();
343 }
344 
styleNumber() const345 qint32 Cell::styleNumber() const
346 {
347 	Q_D(const Cell);
348 
349 	qint32 ret = d->styleNumber;
350 	return ret;
351 }
352 
353 QT_END_NAMESPACE_XLSX
354