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#include "qcontact.h"
35#include "qcontact_p.h"
36
37#ifndef QT_NO_DATASTREAM
38#include <QtCore/qdatastream.h>
39#endif
40#ifndef QT_NO_DEBUG_STREAM
41#include <QtCore/qdebug.h>
42#endif
43#include <QtCore/qset.h>
44
45#include "qcontactactiondescriptor.h"
46#include "qcontactdetail_p.h"
47#include "qcontactdetails.h"
48#include "qcontactmanager_p.h"
49#include "qcontactactionmanager_p.h"
50#include "qcontactaction.h"
51
52QT_BEGIN_NAMESPACE_CONTACTS
53
54/*!
55 \class QContact
56
57 \brief The QContact class represents an addressbook contact.
58
59 \inmodule QtContacts
60
61 \ingroup contacts-main
62
63 Individual contacts, groups, and other types of contacts are represented with
64 a QContact object. In addition to the type, a QContact consists of information
65 that belongs to the contact, some information about the relationships that the
66 contact has, and the preferred ways to interact with the contact.
67
68 A QContact object has a collection of details (like a name, phone numbers and
69 email addresses). Each detail (which can have multiple fields) is stored
70 in an appropriate subclass of QContactDetail, and the QContact allows
71 retrieving these details in various ways.
72
73 Depending on the details of the QContact, certain actions are available for a
74 contact. An instance of a QContact can return a list of actions that can be
75 performed on it, and a list of details supported by a specific action can be
76 retrieved (for example - a list of phone numbers supported by a specific "Call" action).
77 It is also possible to store one detail for each type of action that is the "preferred"
78 detail to use.
79
80 A QContact may have zero or more relationships with other contacts. For example,
81 a group contact would have a \c "HasMember" relationship with the QContacts that
82 are its members. Spouses, managers and assistants can also be represented this
83 way.
84
85 A QContact instance represents the in-memory version of an addressbook contact,
86 and has no tie to a specific QContactManager. It is possible for the contents
87 of a QContact to change independently of the contents that are stored persistently
88 in a QContactManager. A QContact has an ID associated with it when it is first
89 retrieved from a QContactManager, or after it has been first saved, and this allows
90 clients to track changes using the signals in QContactManager.
91
92 A QContact has a number of mandatory details:
93 \list
94 \li A QContactType, with the type of the contact (individual contact, group etc)
95 \endlist
96
97 \sa QContactManager, QContactDetail
98 */
99
100/*!
101 * \fn QList<T> QContact::details() const
102 * Returns a list of details of the template parameter type. The type must be
103 * a subclass of QContactDetail.
104 *
105 * For example:
106 * \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 3
107 */
108
109/*!
110 * \fn T QContact::detail() const
111 * Returns the first detail of the template parameter type, as returned by the template details() function.
112 * The type must be a subclass of QContactDetail.
113 */
114
115/*!
116 * \fn QContact::operator!=(const QContact &other) const
117 * Returns true if this contacts id or details are different to those of the \a other contact.
118 */
119
120/*!
121 Construct an empty contact.
122
123 The contact will have an empty id, and have type \l QContactType::TypeContact.
124 The isEmpty() function will return true.
125*/
126QContact::QContact()
127 : d(new QContactData)
128{
129 clearDetails();
130}
131
132/*! Initializes this QContact from \a other */
133QContact::QContact(const QContact& other)
134 : d(other.d)
135{
136}
137
138/*!
139 * Returns true if this QContact is empty, false if not.
140 *
141 * An empty QContact has no extra details.
142 * The type of the contact is irrelevant.
143 */
144bool QContact::isEmpty() const
145{
146 /* Every contact has a type field */
147 return (d->m_details.count() == 1);
148}
149
150/*!
151 * Removes all details of the contact.
152 * This function does not modify the id or type of the contact.
153 * Calling isEmpty() after calling this function will return true.
154 */
155void QContact::clearDetails()
156{
157 d->m_details.clear();
158
159 // insert the contact type detail.
160 QContactType contactType;
161 contactType.setType(QContactType::TypeContact);
162 contactType.d->m_access = QContactDetail::Irremovable;
163 d->m_details.insert(i: 0, t: contactType);
164}
165
166/*! Replace the contents of this QContact with \a other
167*/
168QContact& QContact::operator=(const QContact& other)
169{
170 d = other.d;
171 return *this;
172}
173
174/*! Frees the memory used by this QContact */
175QContact::~QContact()
176{
177}
178
179/*!
180 Returns the QContactId that identifies this contact.
181
182 This may have been set when the contact was retrieved from
183 a particular manager, or when the contact was first saved
184 in a manager. The QContactId is only valid with a specific
185 manager. See \l QContactManager::saveContact() for more
186 information.
187
188 */
189QContactId QContact::id() const
190{
191 return d.constData()->m_id;
192}
193
194/*!
195 * Sets the id of this contact to \a id.
196 *
197 * Note that this only affects this object, not any corresponding structures stored
198 * by a QContactManager.
199 *
200 * If you change the id of a contact and save the contact
201 * in a manager, the previously existing contact will still
202 * exist. You can do this to create copies (possibly modified)
203 * of an existing contact, or to save a contact in a different manager.
204 *
205 * \sa QContactManager::saveContact()
206 */
207void QContact::setId(const QContactId& id)
208{
209 d->m_id = id;
210}
211
212
213/*!
214 * Returns the type of the contact. Every contact has exactly one type which
215 * is either set manually (by saving a modified copy of the QContactType
216 * in the contact, or by calling \l setType()) or synthesized automatically.
217 *
218 * \sa setType()
219 */
220
221QContactType::TypeValues QContact::type() const
222{
223 // type is detail 0
224 QContactType::TypeValues type = static_cast<QContactType::TypeValues>(d.constData()->m_details.at(i: 0).value(field: QContactType::FieldType).toInt());
225 return type;
226}
227
228
229/*!
230 * Sets the type of the contact to the given \a type.
231 */
232void QContact::setType(const QContactType::TypeValues& type)
233{
234 // type is detail 0
235 d->m_details[0].setValue(field: QContactType::FieldType, value: type);
236 d->m_details[0].d->m_access = QContactDetail::Irremovable;
237}
238
239/*!
240 * Returns the list of tags for this contact. Tags are used for non-exclusive categorization.
241 *
242 * \sa QContactTag
243 */
244QStringList QContact::tags() const
245{
246 QStringList tags;
247 foreach (const QContactTag& tagDetail, details<QContactTag>()) {
248 tags.append(t: tagDetail.tag());
249 }
250 return tags;
251}
252
253/*!
254 * Removes all tags associated with the contact.
255 *
256 * \sa QContactTag
257 */
258void QContact::clearTags()
259{
260 d->removeOnly(type: QContactTag::Type);
261}
262
263/*!
264 * Adds the \a tag to this contact.
265 *
266 * \sa QContactTag
267 */
268void QContact::addTag(const QString& tag)
269{
270 QContactTag tagDetail;
271 tagDetail.setTag(tag);
272 saveDetail(detail: &tagDetail);
273}
274
275/*!
276 * Sets the list of tags associated with the contact to \a tags.
277 *
278 * \sa QContactTag
279 */
280void QContact::setTags(const QStringList& tags)
281{
282 d->removeOnly(type: QContactTag::Type);
283 foreach (const QString& tag, tags) {
284 addTag(tag);
285 }
286}
287
288
289
290/*!
291 \fn QContactDetail QContact::detail(QContactDetail::DetailType type) const
292 Returns the first detail stored in the contact which with the given \a type.
293 The \a type argument is typically the detail type constant provided by a
294 specific subclass of QContactDetail. For example:
295
296 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 0
297
298 It would usually be more convenient to use the template version of this function, in
299 the following manner:
300
301 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 1
302*/
303QContactDetail QContact::detail(QContactDetail::DetailType type) const
304{
305 // If type not defined, return first detail
306 if (type == QContactDetail::TypeUndefined)
307 return d.constData()->m_details.first();
308
309 // build the sub-list of matching details.
310 for (int i = 0; i < d.constData()->m_details.size(); i++) {
311 const QContactDetail& existing = d.constData()->m_details.at(i);
312 if (existing.d->m_type == type) {
313 return existing;
314 }
315 }
316
317 return QContactDetail();
318}
319
320/*!
321 \fn QList<QContactDetail> QContact::details(QContactDetail::DetailType type) const
322 Returns a list of details of the given \a type.
323
324 The \a type argument is typically the detail type constant provided by a
325 specific subclass of QContactDetail. For example:
326
327 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 2
328
329 It would usually be more convenient to use the template version of this function, in
330 the following manner:
331
332 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 3
333*/
334QList<QContactDetail> QContact::details(QContactDetail::DetailType type) const
335{
336 // build the sub-list of matching details.
337 QList<QContactDetail> sublist;
338
339 // special case
340 if (type == QContactDetail::TypeUndefined) {
341 sublist = d.constData()->m_details;
342 } else {
343 for (int i = 0; i < d->m_details.size(); i++) {
344 const QContactDetail& existing = d.constData()->m_details.at(i);
345 if (existing.d->m_type == type) {
346 sublist.append(t: existing);
347 }
348 }
349 }
350
351 return sublist;
352}
353
354/*!
355 * Appends the given \a detail to the list of stored details.
356 * This is a convenience method intended to be used e.g. by backend
357 * developers to populate an empty QContact object when fetching
358 * data from the backend.
359 * If \a detail is a QContactType, the existing contact type will
360 * be overwritten with \a detail. There is never more than one contact type
361 * in a contact.
362 *
363 * Note that if another detail of the same type and id has been previously saved in
364 * this contact, that detail is duplicated. For this reason, this method
365 * should not be used to update an existing contact object with a newer version
366 * of an existing detail. For this use case, the clients must use the
367 * saveDetail() method.
368 *
369 * Returns true if the detail was appended successfully, otherwise returns false.
370 *
371 * \sa saveDetail()
372 */
373bool QContact::appendDetail(const QContactDetail &detail)
374{
375 if (detail.isEmpty())
376 return false;
377
378 /* Also handle contact type specially - only one of them. */
379 if (detail.d->m_type == QContactType::Type) {
380 d->m_details[0] = detail;
381 d->m_details[0].d->m_access |= QContactDetail::Irremovable;
382 return true;
383 }
384 d->m_details.append(t: detail);
385 return true;
386}
387
388
389/*!
390 * Saves the given \a detail in the list of stored details, and sets the detail's id.
391 * If another detail of the same type and id has been previously saved in
392 * this contact, that detail is overwritten. Otherwise, a new id is generated
393 * and set in the detail, and the detail is added to the contact.
394 *
395 * If the detail's access constraint includes \c QContactDetail::ReadOnly,
396 * this function will return true and save the detail in the contact,
397 * however attempting to save the contact in a manager may fail (if that manager
398 * decides that the read only detail should not be updated).
399 * Details with the \c QContactDetail::ReadOnly constraint set are typically provided
400 * in a contact by the manager, and are usually information that is either
401 * synthesized, or not intended to be changed by the user (e.g. presence information
402 * for other contacts).
403 *
404 * If \a detail is a QContactType, the existing contact type will
405 * be overwritten with \a detail. There is never more than one contact type
406 * in a contact.
407 *
408 *
409 * Be aware that if a contact is retrieved (or reloaded) from the backend, the
410 * keys of any details it contains may have been changed by the backend, or other
411 * threads may have modified the contact details in the backend. Therefore,
412 * clients should reload the detail that they wish to save in a contact after retrieving
413 * the contact, in order to avoid creating unwanted duplicated details.
414 *
415 * Returns true if the detail was saved successfully, otherwise returns false.
416 *
417 * Note that the caller retains ownership of the detail.
418 */
419bool QContact::saveDetail(QContactDetail* detail)
420{
421 if (!detail)
422 return false;
423
424 /* Also handle contact type specially - only one of them. */
425 if (detail->d->m_type == QContactType::Type) {
426 detail->d->m_access |= QContactDetail::Irremovable;
427 d->m_details[0] = *detail;
428 return true;
429 }
430
431 // try to find the "old version" of this field
432 // ie, the one with the same type and id, but different value or attributes.
433 for (int i = 0; i < d.constData()->m_details.size(); i++) {
434 const QContactDetail& curr = d.constData()->m_details.at(i);
435 if (detail->d->m_type == curr.d->m_type &&
436 detail->d->m_detailId == curr.d->m_detailId) {
437 // update the detail constraints of the supplied detail
438 detail->d->m_access = curr.accessConstraints();
439 // Found the old version. Replace it with this one.
440 d->m_details[i] = *detail;
441 return true;
442 }
443 }
444 // this is a new detail! add it to the contact.
445 d->m_details.append(t: *detail);
446 return true;
447}
448
449/*!
450 * Removes the \a detail from the contact.
451 *
452 * The detail in the contact which has the same key as that of the given \a detail
453 * will be removed if it exists. Only the key is used for comparison - that is, the
454 * information in the detail may be different.
455 *
456 * Any action preferences for the matching detail is also removed.
457 *
458 * Be aware that if a contact is retrieved (or reloaded) from the backend, the
459 * keys of any details it contains may have been changed by the backend, or other
460 * threads may have modified the contact details in the backend. Therefore,
461 * clients should reload the detail that they wish to remove from a contact after retrieving
462 * the contact, in order to ensure that the remove operation is successful.
463 *
464 * If the detail's access constraint includes \c QContactDetail::Irremovable,
465 * this function will return false.
466 *
467 * Returns true if the detail was removed successfully, false if an error occurred.
468 *
469 * Note that the caller retains ownership of the detail.
470 */
471bool QContact::removeDetail(QContactDetail* detail)
472{
473 if (!detail)
474 return false;
475
476 // find the detail stored in the contact which has the same key as the detail argument
477 int removeIndex = -1;
478 for (int i = 0; i < d.constData()->m_details.size(); i++) {
479 if (d.constData()->m_details.at(i).key() == detail->key()) {
480 removeIndex = i;
481 break;
482 }
483 }
484
485 // make sure the detail exists (in some form) in the contact.
486 if (removeIndex < 0)
487 return false;
488
489 if (detail->accessConstraints() & QContactDetail::Irremovable)
490 return false;
491
492 if (!d.constData()->m_details.contains(t: *detail))
493 return false;
494
495 // remove any preferences we may have stored for the detail.
496 QStringList keys = d.constData()->m_preferences.keys();
497 for (int i = 0; i < keys.size(); i++) {
498 QString prefKey = keys.at(i);
499 if (d.constData()->m_preferences.value(akey: prefKey) == detail->d->m_detailId) {
500 d->m_preferences.remove(akey: prefKey);
501 }
502 }
503
504 // then remove the detail.
505 d->m_details.removeAt(i: removeIndex);
506 return true;
507}
508
509/*! Returns true if this contact is equal to the \a other contact, false if either the id or stored details are not the same
510*/
511bool QContact::operator==(const QContact& other) const
512{
513 // Id must be the same
514 if (other.d.constData()->m_id != d.constData()->m_id)
515 return false;
516 // There must be same amount of details
517 if (other.d.constData()->m_details.size() != d.constData()->m_details.size())
518 return false;
519 // All details must match
520 foreach (QContactDetail detail, other.d.constData()->m_details) {
521 if (!d.constData()->m_details.contains(t: detail))
522 return false;
523 }
524 // All equal
525 return true;
526}
527
528/*!
529 \relates QContact
530 Returns the hash value for \a key.
531*/
532uint qHash(const QContact &key)
533{
534 uint hash = qHash(id: key.id());
535 foreach (const QContactDetail& detail, key.details()) {
536 hash += qHash(key: detail);
537 }
538 return hash;
539}
540
541#ifndef QT_NO_DEBUG_STREAM
542QDebug operator<<(QDebug dbg, const QContact& contact)
543{
544 dbg.nospace() << "QContact(" << contact.id() << ")";
545 foreach (const QContactDetail& detail, contact.details()) {
546 dbg.space() << '\n' << detail;
547 }
548 return dbg.maybeSpace();
549}
550#endif
551
552#ifndef QT_NO_DATASTREAM
553/*!
554 * Writes \a contact to the stream \a out.
555 */
556QDataStream& operator<<(QDataStream& out, const QContact& contact)
557{
558 quint8 formatVersion = 1; // Version of QDataStream format for QContact
559 return out << formatVersion << contact.id() << contact.details() << contact.d->m_preferences;
560}
561
562/*!
563 * Reads a contact from stream \a in into \a contact.
564 */
565QDataStream& operator>>(QDataStream& in, QContact& contact)
566{
567 contact = QContact();
568 quint8 formatVersion;
569 in >> formatVersion;
570 if (formatVersion == 1) {
571 QContactId id;
572 QList<QContactDetail> details;
573 QMap<QString, int> preferences;
574 in >> id >> contact.d->m_details >> contact.d->m_preferences;
575 contact.setId(id);
576 } else {
577 in.setStatus(QDataStream::ReadCorruptData);
578 }
579 return in;
580}
581
582#endif
583
584/*!
585 Returns a list of relationships of the given \a relationshipType in which this contact is a participant.
586
587 If \a relationshipType is empty, all relationships will be returned.
588
589 \note This function only examines the relationships that were present when this contact
590 was retrieved from a manager. You can also query the manager directly, if you require
591 the most up to date information.
592
593 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 5
594
595 \sa QContactRelationshipFetchRequest, QContactManager::relationships()
596 */
597QList<QContactRelationship> QContact::relationships(const QString& relationshipType) const
598{
599 // if empty, then they want all relationships
600 if (relationshipType.isEmpty())
601 return d.constData()->m_relationshipsCache;
602
603 // otherwise, filter on type.
604 QList<QContactRelationship> retn;
605 for (int i = 0; i < d.constData()->m_relationshipsCache.size(); i++) {
606 QContactRelationship curr = d.constData()->m_relationshipsCache.at(i);
607 if (curr.relationshipType() == relationshipType) {
608 retn.append(t: curr);
609 }
610 }
611
612 return retn;
613}
614
615/*!
616 Returns a list of the ids of contacts which have a relationship of the given \a relationshipType with this contact.
617 The \a role parameter describes the role that the related contacts have in the relationship.
618
619 If \a relationshipType is empty, relationships of all types will be considered.
620
621 \note This function only examines the relationships that were present when this contact
622 was retrieved from a manager. You can also query the manager directly, if you require
623 the most up to date information.
624
625 \snippet qtcontactsdocsample/qtcontactsdocsample.cpp 6
626
627 \sa QContactRelationshipFetchRequest, QContactManager::relationships()
628 */
629QList<QContactId> QContact::relatedContacts(const QString& relationshipType, QContactRelationship::Role role) const
630{
631 QList<QContactId> retn;
632 for (int i = 0; i < d.constData()->m_relationshipsCache.size(); i++) {
633 QContactRelationship curr = d.constData()->m_relationshipsCache.at(i);
634 if (relationshipType.isEmpty() || curr.relationshipType() == relationshipType) {
635 // check that the other contacts fill the given role
636 if (role == QContactRelationship::First) {
637 if (curr.first() != d.constData()->m_id) {
638 if (!retn.contains(t: curr.first())) {
639 retn.append(t: curr.first());
640 }
641 }
642 } else if (role == QContactRelationship::Second) {
643 if (curr.first() == d.constData()->m_id) {
644 if (!retn.contains(t: curr.second())) {
645 retn.append(t: curr.second());
646 }
647 }
648 } else { // role == Either.
649 if (curr.first() == d.constData()->m_id) {
650 if (!retn.contains(t: curr.second())) {
651 retn.append(t: curr.second());
652 }
653 } else {
654 if (!retn.contains(t: curr.first())) {
655 retn.append(t: curr.first());
656 }
657 }
658 }
659 }
660 }
661
662 return retn;
663}
664
665QContactCollectionId QContact::collectionId() const
666{
667 return d->m_collectionId;
668}
669
670void QContact::setCollectionId(const QContactCollectionId &collectionId)
671{
672 d->m_collectionId = collectionId;
673}
674
675/*!
676 * Return a list of descriptors for the actions available to be performed on this contact.
677 *
678 * The actions considered can be restricted by the optional parameters
679 * The actions can be restricted to those provided by a specific service with the \a serviceName parameter.
680 * If \a serviceName is empty, actions provided by any service will be returned if the
681 * contact meets the required criteria (contains details of the correct type, etc).
682 *
683 * Each action that matches the above criteria will be tested to see if this contact is supported
684 * by the action, and a list of the action descriptors that are supported will be returned.
685 */
686QList<QContactActionDescriptor> QContact::availableActions(const QString& serviceName) const
687{
688 QList<QContactActionDescriptor> ret;
689 QList<QContactActionDescriptor> allds = QContactActionManager::instance()->availableActions(contact: *this);
690 foreach (const QContactActionDescriptor& d, allds) {
691 if (serviceName.isEmpty() || d.serviceName() == serviceName) {
692 ret.append(t: d);
693 }
694 }
695
696 return ret;
697}
698
699/*!
700 * Set a particular detail (\a preferredDetail) as the preferred detail for any actions with the given \a actionName.
701 *
702 * The \a preferredDetail object must exist in this object, and the \a actionName cannot be empty.
703 *
704 * Returns true if the preference could be recorded, and false otherwise.
705 *
706 * \sa preferredDetail()
707 */
708bool QContact::setPreferredDetail(const QString& actionName, const QContactDetail& preferredDetail)
709{
710 // if the given action name is empty, bad argument.
711 if (actionName.isEmpty())
712 return false;
713
714 // check to see whether the the given preferredDetail is saved in this contact
715 if (!d.constData()->m_details.contains(t: preferredDetail))
716 return false;
717
718 // otherwise, save the preference.
719 d->m_preferences.insert(akey: actionName, avalue: preferredDetail.d->m_detailId);
720 return true;
721}
722
723/*!
724 * Returns true if the given \a detail is a preferred detail for the given \a actionName,
725 * or for any action if the \a actionName is empty.
726 *
727 * \sa preferredDetail()
728 */
729bool QContact::isPreferredDetail(const QString& actionName, const QContactDetail& detail) const
730{
731 if (!d.constData()->m_details.contains(t: detail))
732 return false;
733
734 if (actionName.isEmpty())
735 return d.constData()->m_preferences.values().contains(t: detail.d->m_detailId);
736
737 QMap<QString, int>::const_iterator it = d.constData()->m_preferences.find(akey: actionName);
738 if (it != d.constData()->m_preferences.end() && it.value() == detail.d->m_detailId)
739 return true;
740
741 return false;
742}
743
744/*!
745 * Returns the preferred detail for a given \a actionName.
746 *
747 * If the \a actionName is empty, or there is no preference recorded for
748 * the supplied \a actionName, returns an empty QContactDetail.
749 *
750 * \sa preferredDetails()
751 */
752QContactDetail QContact::preferredDetail(const QString& actionName) const
753{
754 // if the given action name is empty, bad argument.
755 if (actionName.isEmpty())
756 return QContactDetail();
757
758 if (!d.constData()->m_preferences.contains(akey: actionName))
759 return QContactDetail();
760
761 QContactDetail retn;
762 int detId = d.constData()->m_preferences.value(akey: actionName);
763 for (int i = 0; i < d.constData()->m_details.size(); i++) {
764 QContactDetail det = d.constData()->m_details.at(i);
765 if (det.d->m_detailId == detId) {
766 // found it.
767 retn = det;
768 break;
769 }
770 }
771
772 return retn;
773}
774
775/*!
776 * Returns the recorded detail preferences for action names.
777 *
778 * Each entry in the map has the action name as the key, and the corresponding
779 * preferred detail as the value.
780 */
781QMap<QString, QContactDetail> QContact::preferredDetails() const
782{
783 QMap<QString, QContactDetail> ret;
784 QMap<QString, int>::const_iterator it = d.constData()->m_preferences.constBegin();
785 while (it != d.constData()->m_preferences.constEnd()) {
786 ret.insert(akey: it.key(), avalue: preferredDetail(actionName: it.key()));
787 ++it;
788 }
789
790 return ret;
791}
792
793
794/* Helper functions for QContactData */
795void QContactData::removeOnly(QContactDetail::DetailType type)
796{
797 QList<QContactDetail>::iterator dit = m_details.begin();
798 while (dit != m_details.end()) {
799 // XXX this doesn't check type
800 if (dit->type() == type)
801 dit = m_details.erase(it: dit);
802 else
803 ++dit;
804 }
805}
806
807void QContactData::removeOnly(const QSet<QContactDetail::DetailType>& types)
808{
809 QList<QContactDetail>::iterator dit = m_details.begin();
810 while (dit != m_details.end()) {
811 // XXX this doesn't check type
812 if (types.contains(value: dit->type()))
813 dit = m_details.erase(it: dit);
814 else
815 ++dit;
816 }
817}
818
819QT_END_NAMESPACE_CONTACTS
820

source code of qtpim/src/contacts/qcontact.cpp