From 78958055f889073f006c5628d7391bae589c3faf Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 15 May 2017 15:47:35 +0200 Subject: [PATCH] feat(src/components/contacts/ContactsListModel): on contact creation, try to merge with existing contact --- .../src/components/contact/ContactModel.cpp | 44 +++++++++++++ .../src/components/contact/ContactModel.hpp | 2 + .../src/components/contact/VcardModel.cpp | 63 +++++++++++++------ .../components/contacts/ContactsListModel.cpp | 25 ++++++-- .../components/contacts/ContactsListModel.hpp | 3 +- 5 files changed, 113 insertions(+), 24 deletions(-) diff --git a/linphone-desktop/src/components/contact/ContactModel.cpp b/linphone-desktop/src/components/contact/ContactModel.cpp index c3782dca7..9305c3fc3 100644 --- a/linphone-desktop/src/components/contact/ContactModel.cpp +++ b/linphone-desktop/src/components/contact/ContactModel.cpp @@ -138,6 +138,50 @@ next: // ----------------------------------------------------------------------------- +void ContactModel::mergeVcardModel (VcardModel *vcardModel) { + Q_ASSERT(vcardModel != nullptr); + + qInfo() << QStringLiteral("Merge vcard into contact:") << this << vcardModel; + + // 1. Merge avatar. + if (vcardModel->getAvatar().isEmpty()) + vcardModel->setAvatar(mVcardModel->getAvatar()); + + // 2. Merge sip addresses, companies, emails and urls. + for (const auto &sipAddress : mVcardModel->getSipAddresses()) + vcardModel->addSipAddress(sipAddress.toString()); + for (const auto &company : mVcardModel->getCompanies()) + vcardModel->addCompany(company.toString()); + for (const auto &email : mVcardModel->getEmails()) + vcardModel->addEmail(email.toString()); + for (const auto &url : mVcardModel->getUrls()) + vcardModel->addUrl(url.toString()); + + // 3. Merge address. + { + const QVariantMap &oldAddress = vcardModel->getAddress(); + QVariantMap newAddress = vcardModel->getAddress(); + + static const char *attributes[4] = { "street", "locality", "postalCode", "country" }; + bool needMerge = true; + + for (const auto &attribute : attributes) + if (!newAddress[attribute].toString().isEmpty()) { + needMerge = false; + break; + } + + if (needMerge) { + for (const auto &attribute : attributes) + newAddress[attribute] = oldAddress[attribute]; + } + } + + setVcardModel(vcardModel); +} + +// ----------------------------------------------------------------------------- + VcardModel *ContactModel::cloneVcardModel () const { shared_ptr vcard = mVcardModel->mVcard->clone(); Q_ASSERT(vcard != nullptr); diff --git a/linphone-desktop/src/components/contact/ContactModel.hpp b/linphone-desktop/src/components/contact/ContactModel.hpp index 1b2516a16..fede6cfce 100644 --- a/linphone-desktop/src/components/contact/ContactModel.hpp +++ b/linphone-desktop/src/components/contact/ContactModel.hpp @@ -50,6 +50,8 @@ public: VcardModel *getVcardModel () const; void setVcardModel (VcardModel *vcardModel); + void mergeVcardModel (VcardModel *vcardModel); + Q_INVOKABLE VcardModel *cloneVcardModel () const; signals: diff --git a/linphone-desktop/src/components/contact/VcardModel.cpp b/linphone-desktop/src/components/contact/VcardModel.cpp index 095b99dc7..9606aec93 100644 --- a/linphone-desktop/src/components/contact/VcardModel.cpp +++ b/linphone-desktop/src/components/contact/VcardModel.cpp @@ -43,18 +43,21 @@ using namespace std; // ============================================================================= template -inline shared_ptr findBelCardValue (const list > &list, const QString &value) { - string match = ::Utils::qStringToLinphoneString(value); - +inline shared_ptr findBelCardValue (const list > &list, const string &value) { auto it = find_if( - list.cbegin(), list.cend(), [&match](const shared_ptr &entry) { - return match == entry->getValue(); + list.cbegin(), list.cend(), [&value](const shared_ptr &entry) { + return value == entry->getValue(); } ); return it != list.cend() ? *it : nullptr; } +template +inline shared_ptr findBelCardValue (const list > &list, const QString &value) { + return findBelCardValue(list, ::Utils::qStringToLinphoneString(value)); +} + inline bool isLinphoneDesktopPhoto (const shared_ptr &photo) { return !photo->getValue().compare(0, sizeof(VCARD_SCHEME) - 1, VCARD_SCHEME); } @@ -141,6 +144,11 @@ QString VcardModel::getAvatar () const { ); } +inline QString getFileIdFromAppPath (const QString &path) { + const static QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::PROVIDER_ID); + return path.mid(appPrefix.length()); +} + bool VcardModel::setAvatar (const QString &path) { CHECK_VCARD_IS_WRITABLE(this); @@ -148,25 +156,30 @@ bool VcardModel::setAvatar (const QString &path) { QString fileId; QFile file; - // 1. Try to copy photo in avatars folder. + // 1. Try to copy photo in avatars folder if it's a right path file and + // not a application path like `image:`. if (!path.isEmpty()) { - file.setFileName(path); + if (path.startsWith("image:")) + fileId = getFileIdFromAppPath(path); + else { + file.setFileName(path); - if (!file.exists() || QImageReader::imageFormat(path).size() == 0) - return false; + if (!file.exists() || QImageReader::imageFormat(path).size() == 0) + return false; - QFileInfo info(file); - QString uuid = QUuid::createUuid().toString(); - fileId = QStringLiteral("%1.%2") - .arg(uuid.mid(1, uuid.length() - 2)) // Remove `{}`. - .arg(info.suffix()); + QFileInfo info(file); + QString uuid = QUuid::createUuid().toString(); + fileId = QStringLiteral("%1.%2") + .arg(uuid.mid(1, uuid.length() - 2)) // Remove `{}`. + .arg(info.suffix()); - QString dest = ::Utils::linphoneStringToQString(Paths::getAvatarsDirPath()) + fileId; + QString dest = ::Utils::linphoneStringToQString(Paths::getAvatarsDirPath()) + fileId; - if (!file.copy(dest)) - return false; + if (!file.copy(dest)) + return false; - qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)").arg(getUsername()).arg(dest); + qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)").arg(getUsername()).arg(dest); + } } // 2. Remove oldest photo. @@ -298,6 +311,9 @@ bool VcardModel::addSipAddress (const QString &sipAddress) { // Add sip address in belcard. shared_ptr belcard = mVcard->getVcard(); + if (findBelCardValue(belcard->getImpp(), interpretedSipAddress)) + return false; + shared_ptr value = belcard::BelCardGeneric::create(); value->setValue(interpretedSipAddress); @@ -359,6 +375,9 @@ bool VcardModel::addCompany (const QString &company) { CHECK_VCARD_IS_WRITABLE(this); shared_ptr belcard = mVcard->getVcard(); + if (findBelCardValue(belcard->getRoles(), company)) + return false; + shared_ptr value = belcard::BelCardGeneric::create(); value->setValue(::Utils::qStringToLinphoneString(company)); @@ -410,6 +429,9 @@ bool VcardModel::addEmail (const QString &email) { CHECK_VCARD_IS_WRITABLE(this); shared_ptr belcard = mVcard->getVcard(); + if (findBelCardValue(belcard->getEmails(), email)) + return false; + shared_ptr value = belcard::BelCardGeneric::create(); value->setValue(::Utils::qStringToLinphoneString(email)); @@ -421,6 +443,7 @@ bool VcardModel::addEmail (const QString &email) { qInfo() << QStringLiteral("Add new email on vcard: `%1`.").arg(email); emit vcardUpdated(); + return true; } @@ -461,6 +484,9 @@ bool VcardModel::addUrl (const QString &url) { CHECK_VCARD_IS_WRITABLE(this); shared_ptr belcard = mVcard->getVcard(); + if (findBelCardValue(belcard->getURLs(), url)) + return false; + shared_ptr value = belcard::BelCardGeneric::create(); value->setValue(::Utils::qStringToLinphoneString(url)); @@ -472,6 +498,7 @@ bool VcardModel::addUrl (const QString &url) { qInfo() << QStringLiteral("Add new url on vcard: `%1`.").arg(url); emit vcardUpdated(); + return true; } diff --git a/linphone-desktop/src/components/contacts/ContactsListModel.cpp b/linphone-desktop/src/components/contacts/ContactsListModel.cpp index 7679e7f82..43e555030 100644 --- a/linphone-desktop/src/components/contacts/ContactsListModel.cpp +++ b/linphone-desktop/src/components/contacts/ContactsListModel.cpp @@ -113,29 +113,44 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren // ----------------------------------------------------------------------------- ContactModel *ContactsListModel::findContactModelFromSipAddress (const QString &sipAddress) const { - auto it = find_if(mList.begin(), mList.end(), [sipAddress](ContactModel *contactModel) { + auto it = find_if(mList.begin(), mList.end(), [&sipAddress](ContactModel *contactModel) { return contactModel->getVcardModel()->getSipAddresses().contains(sipAddress); }); return it != mList.end() ? *it : nullptr; } +ContactModel *ContactsListModel::findContactModelFromUsername (const QString &username) const { + auto it = find_if(mList.begin(), mList.end(), [&username](ContactModel *contactModel) { + return contactModel->getVcardModel()->getUsername() == username; + }); + + return it != mList.end() ? *it : nullptr; +} + // ----------------------------------------------------------------------------- -ContactModel *ContactsListModel::addContact (VcardModel *vcard) { - ContactModel *contact = new ContactModel(this, vcard); +ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) { + // Try to merge vcardModel to an existing contact. + ContactModel *contact = findContactModelFromUsername(vcardModel->getUsername()); + if (contact) { + contact->mergeVcardModel(vcardModel); + return contact; + } + + contact = new ContactModel(this, vcardModel); App::getInstance()->getEngine()->setObjectOwnership(contact, QQmlEngine::CppOwnership); if ( mLinphoneFriends->addFriend(contact->mLinphoneFriend) != linphone::FriendListStatus::FriendListStatusOK ) { - qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcard; + qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcardModel; delete contact; return nullptr; } - qInfo() << QStringLiteral("Add contact from vcard:") << contact << vcard; + qInfo() << QStringLiteral("Add contact from vcard:") << contact << vcardModel; int row = mList.count(); diff --git a/linphone-desktop/src/components/contacts/ContactsListModel.hpp b/linphone-desktop/src/components/contacts/ContactsListModel.hpp index aa492d969..c93c3f788 100644 --- a/linphone-desktop/src/components/contacts/ContactsListModel.hpp +++ b/linphone-desktop/src/components/contacts/ContactsListModel.hpp @@ -48,8 +48,9 @@ public: bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override; ContactModel *findContactModelFromSipAddress (const QString &sipAddress) const; + ContactModel *findContactModelFromUsername (const QString &username) const; - Q_INVOKABLE ContactModel *addContact (VcardModel *vcard); + Q_INVOKABLE ContactModel *addContact (VcardModel *vcardModel); Q_INVOKABLE void removeContact (ContactModel *contact); Q_INVOKABLE void cleanAvatars ();