From de105275f779b5ee9cb8eba32d52d3bf38a4e14d Mon Sep 17 00:00:00 2001 From: Dario Freddi Date: Tue, 30 Mar 2010 22:35:59 +0200 Subject: [PATCH] Add a new signal, allKnownContactsChanged, to monitor contact addition/removal Signed-off-by: Dario Freddi --- TelepathyQt4/contact-manager.cpp | 53 ++++++++++++++++++++++++++++++++++++++ TelepathyQt4/contact-manager.h | 14 ++++++++++ tests/dbus/conn-roster.cpp | 41 +++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 0 deletions(-) diff --git a/TelepathyQt4/contact-manager.cpp b/TelepathyQt4/contact-manager.cpp index bb52f9d..e68b9ad 100644 --- a/TelepathyQt4/contact-manager.cpp +++ b/TelepathyQt4/contact-manager.cpp @@ -91,6 +91,7 @@ struct TELEPATHY_QT4_NO_EXPORT ContactManager::Private ContactManager *parent; WeakPtr connection; QMap > contacts; + Contacts cachedAllKnownContacts; QMap tracking; void ensureTracking(Contact::Feature feature); @@ -106,6 +107,10 @@ struct TELEPATHY_QT4_NO_EXPORT ContactManager::Private Contacts allKnownContacts() const; void updateContactsPresenceState(); + void computeKnownContactsChanges(const Contacts &added, + const Contacts &pendingAdded, + const Contacts &remotePendingAdded, + const Contacts &removed); }; ConnectionPtr ContactManager::connection() const @@ -797,6 +802,12 @@ void ContactManager::onSubscribeChannelMembersChanged( debug() << "Contact" << contact->id() << "removed from subscribe list"; contact->setSubscriptionState(Contact::PresenceStateNo); } + + // Perform the needed computation for allKnownContactsChanged + mPriv->computeKnownContactsChanges(groupMembersAdded, + groupLocalPendingMembersAdded, + groupRemotePendingMembersAdded, + groupMembersRemoved); } void ContactManager::onPublishChannelMembersChanged( @@ -830,6 +841,12 @@ void ContactManager::onPublishChannelMembersChanged( if (!groupLocalPendingMembersAdded.isEmpty()) { emit presencePublicationRequested(groupLocalPendingMembersAdded); } + + // Perform the needed computation for allKnownContactsChanged + mPriv->computeKnownContactsChanges(groupMembersAdded, + groupLocalPendingMembersAdded, + groupRemotePendingMembersAdded, + groupMembersRemoved); } void ContactManager::onDenyChannelMembersChanged( @@ -949,6 +966,8 @@ void ContactManager::setContactListChannels( } mPriv->updateContactsPresenceState(); + // Refresh the cache for the current known contacts + mPriv->cachedAllKnownContacts = allKnownContacts(); QMap::const_iterator i = contactListChannels.constBegin(); QMap::const_iterator end = contactListChannels.constEnd(); @@ -1095,6 +1114,40 @@ Contacts ContactManager::Private::allKnownContacts() const return contacts; } +void ContactManager::Private::computeKnownContactsChanges(const Tp::Contacts& added, + const Tp::Contacts& pendingAdded, + const Tp::Contacts& remotePendingAdded, + const Tp::Contacts& removed) +{ + // First of all, compute the real additions/removals based upon our cache + Tp::Contacts realAdded; + realAdded.unite(added); + realAdded.unite(pendingAdded); + realAdded.unite(remotePendingAdded); + realAdded.subtract(cachedAllKnownContacts); + Tp::Contacts realRemoved = removed; + realRemoved.intersect(cachedAllKnownContacts); + + // Check if realRemoved have been _really_ removed from all lists + foreach (const ContactListChannel &contactListChannel, contactListChannels) { + ChannelPtr channel = contactListChannel.channel; + if (!channel) { + continue; + } + realRemoved.subtract(channel->groupContacts()); + realRemoved.subtract(channel->groupLocalPendingContacts()); + realRemoved.subtract(channel->groupRemotePendingContacts()); + } + + // Are there any real changes? + if (!realAdded.isEmpty() || !realRemoved.isEmpty()) { + // Yes, update our "cache" and emit the signal + cachedAllKnownContacts.unite(realAdded); + cachedAllKnownContacts.subtract(realRemoved); + emit parent->allKnownContactsChanged(realAdded, realRemoved); + } +} + void ContactManager::Private::updateContactsPresenceState() { Contacts subscribeContacts; diff --git a/TelepathyQt4/contact-manager.h b/TelepathyQt4/contact-manager.h index 834916e..0b25bcf 100644 --- a/TelepathyQt4/contact-manager.h +++ b/TelepathyQt4/contact-manager.h @@ -113,6 +113,20 @@ Q_SIGNALS: void groupMembersChanged(const QString &group, const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupMembersRemoved); + /** + * This signal is emitted whenever some contacts got removed or added from + * ContactManager's known contact list. It is useful for monitoring which contacts + * are currently known by ContactManager. + * + * \param contactsAdded A set of contacts which were added to the known contact list + * \param contactsRemoved A set of contacts which were removed from the known contact list + * + * \note Please note that, in some protocols, this signal could stream newly added contacts + * with both presence subscription and publication state set to No. Be sure to watch + * over publication and/or subscription state changes if that is the case. + */ + void allKnownContactsChanged(const Tp::Contacts &contactsAdded, + const Tp::Contacts &contactsRemoved); private Q_SLOTS: void onAliasesChanged(const Tp::AliasPairList &); diff --git a/tests/dbus/conn-roster.cpp b/tests/dbus/conn-roster.cpp index 2d2c1fd..69ddb2f 100644 --- a/tests/dbus/conn-roster.cpp +++ b/tests/dbus/conn-roster.cpp @@ -33,6 +33,7 @@ protected Q_SLOTS: void expectConnInvalidated(); void expectPendingContactsFinished(Tp::PendingOperation *); void expectPresenceStateChanged(Tp::Contact::PresenceState); + void expectAllKnownContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed); private Q_SLOTS: void initTestCase(); @@ -48,6 +49,7 @@ private: ExampleContactListConnection *mConnService; ConnectionPtr mConn; QList mContacts; + int mHowManyKnownContacts; }; void TestConnRoster::expectConnInvalidated() @@ -83,6 +85,20 @@ void TestConnRoster::expectPendingContactsFinished(PendingOperation *op) mLoop->exit(0); } +void TestConnRoster::expectAllKnownContactsChanged(const Tp::Contacts& added, const Tp::Contacts& removed) +{ + qDebug() << added.size() << " contacts added, " << removed.size() << " contacts removed"; + mHowManyKnownContacts += added.size(); + mHowManyKnownContacts -= removed.size(); + if (mConn->contactManager()->allKnownContacts().size() != mHowManyKnownContacts) { + qWarning() << "Contacts number mismatch! Watched value: " << mHowManyKnownContacts + << "allKnownContacts(): " << mConn->contactManager()->allKnownContacts().size(); + mLoop->exit(1); + } else { + mLoop->exit(0); + } +} + void TestConnRoster::expectPresenceStateChanged(Contact::PresenceState state) { mLoop->exit(0); @@ -184,6 +200,7 @@ void TestConnRoster::testRoster() QCOMPARE(mLoop->exec(), 0); int i = 0; + foreach (const ContactPtr &contact, mContacts) { QVERIFY(connect(contact.data(), SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState)), @@ -252,6 +269,30 @@ void TestConnRoster::testRoster() ++i; } + + // Test allKnownContactsChanged. + // In this test, everytime a subscription is requested or rejected, allKnownContacts changes + // Cache the current value + mHowManyKnownContacts = mConn->contactManager()->allKnownContacts().size(); + // Watch for contacts changed + QVERIFY(connect(mConn->contactManager(), + SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts)), + SLOT(expectAllKnownContactsChanged(Tp::Contacts,Tp::Contacts)))); + + // Wait for the contacts to be built + ids = QStringList() << QString(QLatin1String("kctest1@example.com")) + << QString(QLatin1String("kctest2@example.com")); + QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(ids), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); + QCOMPARE(mLoop->exec(), 0); + + foreach (const ContactPtr &contact, mContacts) { + contact->requestPresenceSubscription(QLatin1String("add me now")); + + // allKnownContacts is supposed to change here. + QCOMPARE(mLoop->exec(), 0); + } } void TestConnRoster::cleanup() -- 1.7.0.3