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 | |
52 | QT_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 | */ |
126 | QContact::QContact() |
127 | : d(new QContactData) |
128 | { |
129 | clearDetails(); |
130 | } |
131 | |
132 | /*! Initializes this QContact from \a other */ |
133 | QContact::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 | */ |
144 | bool 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 | */ |
155 | void 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 | */ |
168 | QContact& QContact::operator=(const QContact& other) |
169 | { |
170 | d = other.d; |
171 | return *this; |
172 | } |
173 | |
174 | /*! Frees the memory used by this QContact */ |
175 | QContact::~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 | */ |
189 | QContactId 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 | */ |
207 | void 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 | |
221 | QContactType::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 | */ |
232 | void 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 | */ |
244 | QStringList 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 | */ |
258 | void 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 | */ |
268 | void 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 | */ |
280 | void 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 | */ |
303 | QContactDetail 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 | */ |
334 | QList<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 | */ |
373 | bool 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 | */ |
419 | bool 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 | */ |
471 | bool 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 | */ |
511 | bool 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 | */ |
532 | uint 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 |
542 | QDebug 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 | */ |
556 | QDataStream& 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 | */ |
565 | QDataStream& 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 | */ |
597 | QList<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 | */ |
629 | QList<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 | |
665 | QContactCollectionId QContact::collectionId() const |
666 | { |
667 | return d->m_collectionId; |
668 | } |
669 | |
670 | void 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 | */ |
686 | QList<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 | */ |
708 | bool 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 | */ |
729 | bool 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 | */ |
752 | QContactDetail 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 | */ |
781 | QMap<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 */ |
795 | void 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 | |
807 | void 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 | |
819 | QT_END_NAMESPACE_CONTACTS |
820 | |