| 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 | |