1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtContacts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#ifndef QCONTACTDETAIL_P_H
35#define QCONTACTDETAIL_P_H
36
37//
38// W A R N I N G
39// -------------
40//
41// This file is not part of the Qt API. It exists purely as an
42// implementation detail. This header file may change from version to
43// version without notice, or even be removed.
44//
45// We mean it.
46//
47
48#include <QMap>
49#include <QList>
50#include <QString>
51#include <QVariant>
52#include <QDateTime>
53#include <QAtomicInt>
54#include <QSharedData>
55#include <QStringList>
56
57#include "qcontactdetail.h"
58
59QT_BEGIN_NAMESPACE_CONTACTS
60
61class QContactDetailPrivate : public QSharedData
62{
63public:
64 static QAtomicInt lastDetailKey;
65
66 // all details have these fields
67 QList<int> m_contexts;
68
69 // detail metadata
70 QString m_provenance;
71 QContactDetail::DetailType m_type;
72 QContactDetail::AccessConstraints m_access;
73 int m_detailId;
74 int m_hasValueBitfield; // subclass types must set the hasValue bit for any field value which isn't stored in m_extraData.
75
76 // extra field data
77 QMap<int, QVariant> m_extraData;
78
79 QContactDetailPrivate()
80 : m_type(QContactDetail::TypeUndefined)
81 , m_access(QContactDetail::NoConstraint)
82 , m_detailId(lastDetailKey.fetchAndAddOrdered(valueToAdd: 1))
83 , m_hasValueBitfield(0) {}
84 QContactDetailPrivate(QContactDetail::DetailType detailType)
85 : m_type(detailType)
86 , m_access(QContactDetail::NoConstraint)
87 , m_detailId(lastDetailKey.fetchAndAddOrdered(valueToAdd: 1))
88 , m_hasValueBitfield(0) {}
89 QContactDetailPrivate(const QContactDetailPrivate& other)
90 : QSharedData(other)
91 , m_contexts(other.m_contexts)
92 , m_provenance(other.m_provenance)
93 , m_type(other.m_type)
94 , m_access(other.m_access)
95 , m_detailId(other.m_detailId)
96 , m_hasValueBitfield(other.m_hasValueBitfield)
97 , m_extraData(other.m_extraData) {}
98 virtual ~QContactDetailPrivate() {}
99
100 virtual QContactDetailPrivate *clone() {
101 // NOTE: this one must be called for extension (non-built-in) types ONLY
102 // otherwise slicing will occur on detach, leading to crashes!
103 Q_ASSERT(this->m_type == QContactDetail::TypeUndefined || this->m_type > QContactDetail::TypeVersion); // TypeVersion is the builtin type with largest type value.
104 return new QContactDetailPrivate(*this);
105 }
106
107 virtual bool operator==(const QContactDetailPrivate& other) const { // doesn't check detailId or provenance
108 if (m_type != other.m_type
109 || !bitfieldsEqual(first: m_hasValueBitfield, second: other.m_hasValueBitfield, ignore: FieldProvenanceBit)
110 || m_contexts != other.m_contexts
111 || m_access != other.m_access
112 || m_extraData.size() != other.m_extraData.size()) {
113 return false;
114 }
115
116 const QMap<int, QVariant> &thisValues(values());
117 const QMap<int, QVariant> &otherValues(other.values());
118 int thisSize = thisValues.contains(akey: QContactDetail::FieldProvenance) ? thisValues.size() - 1 : thisValues.size();
119 int otherSize = otherValues.contains(akey: QContactDetail::FieldProvenance) ? otherValues.size() - 1 : otherValues.size();
120 if (thisSize != otherSize)
121 return false;
122
123 QMap<int, QVariant>::const_iterator it = thisValues.constBegin(), end = thisValues.constEnd();
124 QMap<int, QVariant>::const_iterator otherIt;
125 for ( ; it != end; ++it) {
126 if (it.key() == QContactDetail::FieldProvenance)
127 continue;
128 otherIt = otherValues.constFind(akey: it.key());
129 if (otherIt == otherValues.constEnd())
130 return false;
131 if (it.value().canConvert<QList<int> >()) {
132 // QList<int> values must be compared as QList<int> not as QVariant<QList<int> >...
133 if (it.value().value<QList<int> >() != otherIt.value().value<QList<int> >())
134 return false;
135 } else if (it.value() != otherIt.value()) {
136 // Everything else can be compared directly by value.
137 return false;
138 }
139 }
140 return true;
141 }
142 bool operator!=(const QContactDetailPrivate& other) const {return !(other == *this);}
143
144 static void setAccessConstraints(QContactDetail *d, QContactDetail::AccessConstraints constraint)
145 {
146 d->d->m_access = constraint;
147 }
148
149 static void setProvenance(QContactDetail *d, const QString &newProvenance)
150 {
151 d->d->m_provenance = newProvenance;
152 d->d->setHasValueBitfieldBit(value: !newProvenance.isEmpty(), whichBit: FieldProvenanceBit);
153 }
154
155 static const QContactDetailPrivate* detailPrivate(const QContactDetail& detail)
156 {
157 return detail.d.constData();
158 }
159
160 // built-in fields hasValue bitfield bit
161 enum BuiltinFieldBitfieldBits {
162 FieldContextBit = 0,
163 FieldDetailUriBit,
164 FieldLinkedDetailUrisBit,
165 FieldProvenanceBit
166 };
167 // custom types can define more (for fields which are a complicated view of Field>FieldMaximumUserVisible data)
168 inline bool hasValueBitfieldBitSet(unsigned int whichBit) const {
169 unsigned int mask = 1 << whichBit;
170 return m_hasValueBitfield & mask;
171 }
172 inline void setHasValueBitfieldBit(bool _value, unsigned int whichBit) {
173 unsigned int mask = 1 << whichBit;
174 if (_value) {
175 m_hasValueBitfield |= mask; // set
176 } else {
177 m_hasValueBitfield &= ~mask; // clear
178 }
179 }
180 static inline bool bitfieldsEqual(int first, int second, unsigned int ignore) {
181 unsigned int mask = 1 << ignore;
182 return (first & ~mask) == (second & ~mask); // clear the ignored bit in both
183 }
184
185 virtual bool setValue(int field, const QVariant &_value) {
186 switch (field) {
187 case QContactDetail::FieldContext: {
188 if (_value.userType() == QMetaType::Int || _value.userType() == QMetaType::UInt) {
189 m_contexts = QList<int>() << _value.toInt();
190 } else {
191 m_contexts = _value.value<QList<int> >();
192 }
193 setHasValueBitfieldBit(value: true, whichBit: FieldContextBit);
194 return true;
195 }
196 case QContactDetail::FieldProvenance: {
197 m_provenance = _value.toString();
198 setHasValueBitfieldBit(value: !m_provenance.isEmpty(), whichBit: FieldProvenanceBit);
199 return true;
200 }
201 default: {
202 // add the data as an extraData field
203 m_extraData.insert(akey: field, avalue: _value);
204 // don't need to set hasValueBitfield bit for fields stored in extra data.
205 return true;
206 }
207 }
208 }
209
210 virtual bool removeValue(int field) {
211 switch (field) {
212 case QContactDetail::FieldContext: {
213 m_contexts = QList<int>();
214 setHasValueBitfieldBit(value: false, whichBit: FieldContextBit);
215 return true;
216 }
217 case QContactDetail::FieldProvenance: {
218 m_provenance = QString();
219 setHasValueBitfieldBit(value: false, whichBit: FieldProvenanceBit);
220 return true;
221 }
222 default: {
223 return m_extraData.remove(akey: field);
224 // don't need to clear hasValueBitfield bit for fields stored in extra data.
225 }
226 }
227 }
228
229 virtual bool hasValue(int field) const {
230 switch (field) {
231 case QContactDetail::FieldContext: return hasValueBitfieldBitSet(whichBit: FieldContextBit);
232 case QContactDetail::FieldProvenance: return hasValueBitfieldBitSet(whichBit: FieldProvenanceBit);
233 default: return m_extraData.contains(akey: field);
234 }
235 }
236
237 virtual bool isEmpty() const {
238 return m_hasValueBitfield == 0 && m_extraData.isEmpty();
239 }
240
241 virtual QMap<int, QVariant> values() const {
242 QMap<int, QVariant> retn;
243 if (hasValueBitfieldBitSet(whichBit: FieldContextBit)) {
244 retn.insert(akey: QContactDetail::FieldContext, avalue: QVariant::fromValue<QList<int> >(value: m_contexts));
245 }
246 if (hasValueBitfieldBitSet(whichBit: FieldProvenanceBit)) {
247 retn.insert(akey: QContactDetail::FieldProvenance, avalue: QVariant::fromValue<QString>(value: m_provenance));
248 }
249 QMap<int, QVariant>::const_iterator it = m_extraData.constBegin(), end = m_extraData.constEnd();
250 for ( ; it != end; ++it) {
251 if (it.key() <= QContactDetail::FieldMaximumUserVisible) {
252 retn.insert(akey: it.key(), avalue: it.value());
253 }
254 }
255 return retn;
256 }
257
258 virtual QVariant value(int field) const {
259 switch (field) {
260 case QContactDetail::FieldContext: return QVariant::fromValue<QList<int> >(value: m_contexts);
261 case QContactDetail::FieldProvenance: return QVariant::fromValue<QString>(value: m_provenance);
262 default: return m_extraData.value(akey: field);
263 }
264 }
265
266 static QContactDetailPrivate *construct(QContactDetail::DetailType detailType);
267};
268
269class QContactDetailBuiltinPrivateBase : public QContactDetailPrivate
270{
271public:
272 enum MemberType {
273 Bool,
274 Double,
275 Int,
276 IntList,
277 String,
278 StringList,
279 Date,
280 DateTime,
281 Url,
282 ByteArray,
283 Variant,
284 };
285
286 struct Member {
287 MemberType type;
288 size_t offset;
289 };
290
291 enum { BaseFieldOffset = 4 };
292
293 QContactDetailBuiltinPrivateBase(QContactDetail::DetailType type)
294 : QContactDetailPrivate(type)
295 {
296 }
297 QContactDetailBuiltinPrivateBase(const QContactDetailBuiltinPrivateBase& other)
298 : QContactDetailPrivate(other)
299 {
300 }
301
302 template<typename Subclass>
303 static const void* memberAddress(const Subclass *base, size_t offset)
304 {
305 return reinterpret_cast<const void*>(reinterpret_cast<const char *>(base) + offset);
306 }
307 template<typename Subclass>
308 static void* memberAddress(Subclass *base, size_t offset)
309 {
310 return reinterpret_cast<void*>(reinterpret_cast<char *>(base) + offset);
311 }
312
313 template<typename T, typename Subclass>
314 static const T* memberVariable(const Subclass *base, size_t offset)
315 {
316 return reinterpret_cast<const T*>(memberAddress(base, offset));
317 }
318 template<typename T, typename Subclass>
319 static T* memberVariable(Subclass *base, size_t offset)
320 {
321 return reinterpret_cast<T*>(memberAddress(base, offset));
322 }
323
324 template<typename Subclass>
325 void reinitialize(Subclass* us, const Member& member)
326 {
327 switch (member.type) {
328 case Bool: *memberVariable<bool>(us, member.offset) = false; return;
329 case Double: *memberVariable<double>(us, member.offset) = 0.0; return;
330 case Int: *memberVariable<int>(us, member.offset) = 0; return;
331 case IntList: reinitialize<QList<int> >(us, member); return;
332 case String: reinitialize<QString>(us, member); return;
333 case StringList: reinitialize<QStringList>(us, member); return;
334 case Date: reinitialize<QDate>(us, member); return;
335 case DateTime: reinitialize<QDateTime>(us, member); return;
336 case Url: reinitialize<QUrl>(us, member); return;
337 case ByteArray: reinitialize<QByteArray>(us, member); return;
338 case Variant: reinitialize<QVariant>(us, member); return;
339 default: qFatal(msg: "Unsupported field type");
340 }
341 }
342
343 template<typename Subclass>
344 static void setValueFromVariant(Subclass* us, const QVariant& value, const Member& member)
345 {
346 switch (member.type) {
347 case Bool: setValueFromVariant<bool>(us, value, member); return;
348 case Double: setValueFromVariant<double>(us, value, member); return;
349 case Int: setValueFromVariant<int>(us, value, member); return;
350 case IntList: setValueFromVariant<QList<int> >(us, value, member); return;
351 case String: setValueFromVariant<QString>(us, value, member); return;
352 case StringList: setValueFromVariant<QStringList>(us, value, member); return;
353 case Date: *memberVariable<QDate>(us, member.offset) = value.userType() == QMetaType::QDateTime ? value.value<QDateTime>().date() : value.value<QDate>(); return;
354 case DateTime: setValueFromVariant<QDateTime>(us, value, member); return;
355 case Url: setValueFromVariant<QUrl>(us, value, member); return;
356 case ByteArray: *memberVariable<QByteArray>(us, member.offset) = value.userType() == QMetaType::QString ? value.value<QString>().toUtf8() : value.value<QByteArray>(); return;
357 case Variant: *memberVariable<QVariant>(us, member.offset) = value; return;
358 default: qFatal(msg: "Unsupported field type");
359 }
360 }
361
362 template<typename Subclass>
363 static bool equal(const Subclass* us, const Subclass* them, const Member& member)
364 {
365 switch (member.type) {
366 case Bool: return equal<bool>(us, them, member);
367 case Double: return equal<double>(us, them, member);
368 case Int: return equal<int>(us, them, member);
369 case IntList: return equal<QList<int> >(us, them, member);
370 case String: return equal<QString>(us, them, member);
371 case StringList: return equal<QStringList>(us, them, member);
372 case Date: return equal<QDate>(us, them, member);
373 case DateTime: return equal<QDateTime>(us, them, member);
374 case Url: return equal<QUrl>(us, them, member);
375 case ByteArray: return equal<QByteArray>(us, them, member);
376 case Variant: return equal<QVariant>(us, them, member);
377 default: qFatal(msg: "Unsupported field type");
378 }
379 }
380
381 template<typename Subclass>
382 static QVariant toVariant(const Subclass* us, const Member& member)
383 {
384 switch (member.type) {
385 case Bool: return QVariant(*memberVariable<bool>(us, member.offset));
386 case Double: return QVariant(*memberVariable<double>(us, member.offset));
387 case Int: return QVariant(*memberVariable<int>(us, member.offset));
388 case IntList: return QVariant::fromValue(*memberVariable<QList<int> >(us, member.offset));
389 case String: return QVariant(*memberVariable<QString>(us, member.offset));
390 case StringList: return QVariant::fromValue(*memberVariable<QStringList>(us, member.offset));
391 case Date: return QVariant(*memberVariable<QDate>(us, member.offset));
392 case DateTime: { // if the value was likely set as a QDate, then return it as a QDate.
393 const QDateTime &dt(*memberVariable<QDateTime>(us, member.offset));
394 return (dt.timeSpec() == Qt::LocalTime && dt.time() == QTime(0,0,0,0))
395 ? QVariant(dt.date())
396 : QVariant(dt);
397 }
398 case Url: return QVariant(*memberVariable<QUrl>(us, member.offset));
399 case ByteArray: return QVariant(*memberVariable<QByteArray>(us, member.offset));
400 case Variant: return *memberVariable<QVariant>(us, member.offset);
401 default: qFatal(msg: "Unsupported field type");
402 }
403 }
404
405private:
406 template<typename T, typename Subclass>
407 void reinitialize(Subclass* us, const Member& member)
408 {
409 *memberVariable<T>(us, member.offset) = T();
410 }
411
412 template<typename T, typename Subclass>
413 static void setValueFromVariant(Subclass* us, const QVariant& value, const Member& member)
414 {
415 *memberVariable<T>(us, member.offset) = value.value<T>();
416 }
417
418 template<typename T, typename Subclass>
419 static bool equal(const Subclass* us, const Subclass* them, const Member& member)
420 {
421 return *memberVariable<T>(us, member.offset) == *memberVariable<int>(them, member.offset);
422 }
423};
424
425template <typename Subclass>
426class QContactDetailBuiltinPrivate : public QContactDetailBuiltinPrivateBase
427{
428public:
429 static const Member s_members[];
430
431 QContactDetailBuiltinPrivate(QContactDetail::DetailType type)
432 : QContactDetailBuiltinPrivateBase(type)
433 {
434 }
435
436 const Subclass *subclass() const
437 {
438 return static_cast<const Subclass *>(this);
439 }
440 Subclass *subclass()
441 {
442 return static_cast<Subclass *>(this);
443 }
444
445 QContactDetailPrivate *clone() {
446 return new Subclass(*subclass());
447 }
448
449 bool operator==(const QContactDetailBuiltinPrivate& other) const
450 {
451 Subclass *us(subclass());
452 const Subclass *them(other.subclass());
453 for (int i = 0; i < Subclass::FieldCount; ++i) {
454 if (!equal(us, them, s_members[i])) {
455 return false;
456 }
457 }
458 return QContactDetailPrivate::operator==(other);
459 }
460
461 template<typename T>
462 const T& memberValue(int field) const
463 {
464 return *memberVariable<T>(subclass(), s_members[field].offset);
465 }
466
467 template<typename T>
468 void setMemberValue(int field, const T& value)
469 {
470 *memberVariable<T>(subclass(), s_members[field].offset) = value;
471 setHasValueBitfieldBit(value: true, whichBit: field + BaseFieldOffset);
472 }
473
474 bool setValue(int field, const QVariant &value)
475 {
476 if (field < Subclass::FieldCount) {
477 setValueFromVariant(subclass(), value, s_members[field]);
478 setHasValueBitfieldBit(value: true, whichBit: field + BaseFieldOffset);
479 return true;
480 }
481 return QContactDetailPrivate::setValue(field, value: value);
482 }
483
484 bool removeValue(int field)
485 {
486 if (field < Subclass::FieldCount) {
487 reinitialize(subclass(), s_members[field]);
488 setHasValueBitfieldBit(value: false, whichBit: field + BaseFieldOffset);
489 return true;
490 }
491 return QContactDetailPrivate::removeValue(field);
492 }
493
494 bool hasValue(int field) const
495 {
496 if (field < Subclass::FieldCount) {
497 return hasValueBitfieldBitSet(whichBit: field + BaseFieldOffset);
498 }
499 return QContactDetailPrivate::hasValue(field);
500 }
501
502 QMap<int, QVariant> values() const
503 {
504 QMap<int, QVariant> retn = QContactDetailPrivate::values();
505 for (int i = 0; i < Subclass::FieldCount; ++i) {
506 if (hasValueBitfieldBitSet(whichBit: i + BaseFieldOffset)) {
507 retn.insert(i, value(field: i));
508 }
509 }
510 return retn;
511 }
512
513 QVariant value(int field) const
514 {
515 if (field < Subclass::FieldCount) {
516 return toVariant(subclass(), s_members[field]);
517 }
518 return QContactDetailPrivate::value(field);
519 }
520};
521
522QT_END_NAMESPACE_CONTACTS
523
524QT_BEGIN_NAMESPACE
525// allow shared data / detach for specific detail types
526template <> inline QTCONTACTS_PREPEND_NAMESPACE(QContactDetailPrivate) *QSharedDataPointer<QTCONTACTS_PREPEND_NAMESPACE(QContactDetailPrivate)>::clone()
527{
528 return d->clone();
529}
530QT_END_NAMESPACE
531
532#endif // QCONTACTDETAIL_P_H
533

source code of qtpim/src/contacts/qcontactdetail_p.h