[Telepathy-commits] [telepathy-qt4/master] ReadinessHelper: Add subclass support.

Andre Moreira Magalhaes (andrunko) andre.magalhaes at collabora.co.uk
Thu Mar 5 11:26:06 PST 2009


P.s: Tests/examples broken (will be fixed in a later patch).
---
 TelepathyQt4/Client/account-manager.cpp    |   32 +++++--
 TelepathyQt4/Client/account-manager.h      |   22 ++---
 TelepathyQt4/Client/account.cpp            |   41 ++++++---
 TelepathyQt4/Client/account.h              |   26 +++---
 TelepathyQt4/Client/connection-internal.h  |    4 +-
 TelepathyQt4/Client/connection-manager.cpp |   31 +++++--
 TelepathyQt4/Client/connection-manager.h   |   20 ++---
 TelepathyQt4/Client/connection.cpp         |   48 +++++++----
 TelepathyQt4/Client/connection.h           |   30 +++----
 TelepathyQt4/Client/pending-ready.cpp      |    9 +-
 TelepathyQt4/Client/pending-ready.h        |    5 +-
 TelepathyQt4/Client/readiness-helper.cpp   |  129 ++++++++++++++--------------
 TelepathyQt4/Client/readiness-helper.h     |   24 +++--
 13 files changed, 235 insertions(+), 186 deletions(-)

diff --git a/TelepathyQt4/Client/account-manager.cpp b/TelepathyQt4/Client/account-manager.cpp
index 01ff26e..a930076 100644
--- a/TelepathyQt4/Client/account-manager.cpp
+++ b/TelepathyQt4/Client/account-manager.cpp
@@ -30,7 +30,6 @@
 #include <TelepathyQt4/Client/Account>
 #include <TelepathyQt4/Client/PendingAccount>
 #include <TelepathyQt4/Client/PendingReady>
-#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Constants>
 
 #include <QQueue>
@@ -94,12 +93,12 @@ AccountManager::Private::Private(AccountManager *parent)
 {
     debug() << "Creating new AccountManager:" << parent->busName();
 
-    QMap<uint, ReadinessHelper::Introspectable> introspectables;
+    ReadinessHelper::Introspectables introspectables;
 
     // As AccountManager does not have predefined statuses let's simulate one (0)
     ReadinessHelper::Introspectable introspectableCore(
         QSet<uint>() << 0,                                           // makesSenseForStatuses
-        QSet<uint>(),                                                // dependsOnFeatures
+        Features(),                                                  // dependsOnFeatures
         QStringList(),                                               // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectMain,
         this);
@@ -107,6 +106,7 @@ AccountManager::Private::Private(AccountManager *parent)
 
     readinessHelper = new ReadinessHelper(parent, 0 /* status */,
             introspectables, parent);
+    readinessHelper->becomeReady(Features() << FeatureCore);
 
     init();
 }
@@ -150,6 +150,8 @@ void AccountManager::Private::setAccountPaths(QSet<QString> &set,
  * Object representing a Telepathy account manager.
  */
 
+const Feature AccountManager::FeatureCore = Feature(AccountManager::staticMetaObject.className(), 0);
+
 /**
  * Construct a new AccountManager object.
  *
@@ -369,9 +371,12 @@ PendingAccount *AccountManager::createAccount(const QString &connectionManager,
  * \return \c true if the object has finished its initial setup for basic
  *         functionality plus the given features
  */
-bool AccountManager::isReady(const QSet<uint> &features) const
+bool AccountManager::isReady(const Features &features) const
 {
-    return mPriv->readinessHelper->isReady(features);
+    if (features.isEmpty()) {
+        return mPriv->readinessHelper->isReady(Features() << FeatureCore, true);
+    }
+    return mPriv->readinessHelper->isReady(features, features.contains(FeatureCore));
 }
 
 /**
@@ -387,22 +392,26 @@ bool AccountManager::isReady(const QSet<uint> &features) const
  *         when this object has finished or failed initial setup for basic
  *         functionality plus the given features
  */
-PendingReady *AccountManager::becomeReady(const QSet<uint> &requestedFeatures)
+PendingReady *AccountManager::becomeReady(const Features &requestedFeatures)
 {
+    if (requestedFeatures.isEmpty()) {
+        return mPriv->readinessHelper->becomeReady(Features() << FeatureCore);
+    }
     return mPriv->readinessHelper->becomeReady(requestedFeatures);
+
 }
 
-QSet<uint> AccountManager::requestedFeatures() const
+Features AccountManager::requestedFeatures() const
 {
     return mPriv->readinessHelper->requestedFeatures();
 }
 
-QSet<uint> AccountManager::actualFeatures() const
+Features AccountManager::actualFeatures() const
 {
     return mPriv->readinessHelper->actualFeatures();
 }
 
-QSet<uint> AccountManager::missingFeatures() const
+Features AccountManager::missingFeatures() const
 {
     return mPriv->readinessHelper->missingFeatures();
 }
@@ -421,6 +430,11 @@ AccountManagerInterface *AccountManager::baseInterface() const
     return mPriv->baseInterface;
 }
 
+ReadinessHelper *AccountManager::readinessHelper() const
+{
+    return mPriv->readinessHelper;
+}
+
 /**** Private ****/
 void AccountManager::Private::init()
 {
diff --git a/TelepathyQt4/Client/account-manager.h b/TelepathyQt4/Client/account-manager.h
index 2717d03..db74f9c 100644
--- a/TelepathyQt4/Client/account-manager.h
+++ b/TelepathyQt4/Client/account-manager.h
@@ -31,6 +31,7 @@
 #include <TelepathyQt4/Client/DBus>
 #include <TelepathyQt4/Client/DBusProxy>
 #include <TelepathyQt4/Client/OptionalInterfaceFactory>
+#include <TelepathyQt4/Client/ReadinessHelper>
 
 #include <QDBusObjectPath>
 #include <QSet>
@@ -55,11 +56,7 @@ class AccountManager : public StatelessDBusProxy,
     Q_DISABLE_COPY(AccountManager)
 
 public:
-    enum Feature {
-        FeatureCore = 0,
-        _Padding = 0xFFFFFFFF
-    };
-    Q_DECLARE_FLAGS(Features, Feature)
+    static const Feature FeatureCore;
 
     AccountManager(QObject *parent = 0);
     AccountManager(const QDBusConnection &bus, QObject *parent = 0);
@@ -90,13 +87,12 @@ public:
 
     // TODO: enabledAccounts(), accountsByProtocol(), ... ?
 
-    bool isReady(const QSet<uint> &features = QSet<uint>()) const;
+    virtual bool isReady(const Features &features = Features()) const;
+    virtual PendingReady *becomeReady(const Features &requestedFeatures = Features());
 
-    PendingReady *becomeReady(const QSet<uint> &requestedFeatures = QSet<uint>());
-
-    QSet<uint> requestedFeatures() const;
-    QSet<uint> actualFeatures() const;
-    QSet<uint> missingFeatures() const;
+    virtual Features requestedFeatures() const;
+    virtual Features actualFeatures() const;
+    virtual Features missingFeatures() const;
 
 Q_SIGNALS:
     void accountCreated(const QString &path);
@@ -106,6 +102,8 @@ Q_SIGNALS:
 protected:
     AccountManagerInterface *baseInterface() const;
 
+    ReadinessHelper *readinessHelper() const;
+
 private Q_SLOTS:
     void gotMainProperties(QDBusPendingCallWatcher *);
     void onAccountValidityChanged(const QDBusObjectPath &, bool);
@@ -118,8 +116,6 @@ private:
     Private *mPriv;
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS(AccountManager::Features)
-
 } // Telepathy::Client
 } // Telepathy
 
diff --git a/TelepathyQt4/Client/account.cpp b/TelepathyQt4/Client/account.cpp
index 496f3e2..6358a72 100644
--- a/TelepathyQt4/Client/account.cpp
+++ b/TelepathyQt4/Client/account.cpp
@@ -33,7 +33,6 @@
 #include <TelepathyQt4/Client/PendingFailure>
 #include <TelepathyQt4/Client/PendingReady>
 #include <TelepathyQt4/Client/PendingVoidMethodCall>
-#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Constants>
 #include <TelepathyQt4/Debug>
 
@@ -146,12 +145,12 @@ Account::Private::Private(Account *parent, AccountManager *am)
         }
     }
 
-    QMap<uint, ReadinessHelper::Introspectable> introspectables;
+    ReadinessHelper::Introspectables introspectables;
 
     // As Account does not have predefined statuses let's simulate one (0)
     ReadinessHelper::Introspectable introspectableCore(
         QSet<uint>() << 0,                                                      // makesSenseForStatuses
-        QSet<uint>(),                                                           // dependsOnFeatures
+        Features(),                                                             // dependsOnFeatures
         QStringList(),                                                          // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectMain,
         this);
@@ -159,7 +158,7 @@ Account::Private::Private(Account *parent, AccountManager *am)
 
     ReadinessHelper::Introspectable introspectableAvatar(
         QSet<uint>() << 0,                                                      // makesSenseForStatuses
-        QSet<uint>() << FeatureCore,                                            // dependsOnFeatures (core)
+        Features() << FeatureCore,                                              // dependsOnFeatures (core)
         QStringList() << TELEPATHY_INTERFACE_ACCOUNT_INTERFACE_AVATAR,          // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectAvatar,
         this);
@@ -167,7 +166,7 @@ Account::Private::Private(Account *parent, AccountManager *am)
 
     ReadinessHelper::Introspectable introspectableProtocolInfo(
         QSet<uint>() << 0,                                                      // makesSenseForStatuses
-        QSet<uint>() << FeatureCore,                                            // dependsOnFeatures (core)
+        Features() << FeatureCore,                                              // dependsOnFeatures (core)
         QStringList(),                                                          // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectProtocolInfo,
         this);
@@ -175,6 +174,7 @@ Account::Private::Private(Account *parent, AccountManager *am)
 
     readinessHelper = new ReadinessHelper(parent, 0 /* status */,
             introspectables, parent);
+    readinessHelper->becomeReady(Features() << FeatureCore);
 
     init();
 }
@@ -195,6 +195,10 @@ Account::Private::~Private()
  * and will cease to be useful.
  */
 
+const Feature Account::FeatureCore = Feature(Account::staticMetaObject.className(), 0);
+const Feature Account::FeatureAvatar = Feature(Account::staticMetaObject.className(), 1);
+const Feature Account::FeatureProtocolInfo = Feature(Account::staticMetaObject.className(), 2);
+
 /**
  * Construct a new Account object.
  *
@@ -374,7 +378,7 @@ PendingOperation *Account::setNickname(const QString &value)
  */
 const Telepathy::Avatar &Account::avatar() const
 {
-    if (!isReady(QSet<uint>() << FeatureAvatar)) {
+    if (!isReady(Features() << FeatureAvatar)) {
         warning() << "Trying to retrieve avatar from account, but "
                      "avatar is not supported or was not requested. "
                      "Use becomeReady(FeatureAvatar)";
@@ -439,7 +443,7 @@ PendingOperation *Account::updateParameters(const QVariantMap &set,
  */
 ProtocolInfo *Account::protocolInfo() const
 {
-    if (!isReady(QSet<uint>() << FeatureProtocolInfo)) {
+    if (!isReady(Features() << FeatureProtocolInfo)) {
         warning() << "Trying to retrieve protocol info from account, but "
                      "protocol info is not supported or was not requested. "
                      "Use becomeReady(FeatureProtocolInfo)";
@@ -651,9 +655,12 @@ PendingOperation *Account::remove()
  * \return \c true if the object has finished its initial setup for basic
  *         functionality plus the given features
  */
-bool Account::isReady(const QSet<uint> &features) const
+bool Account::isReady(const Features &features) const
 {
-    return mPriv->readinessHelper->isReady(features);
+    if (features.isEmpty()) {
+        return mPriv->readinessHelper->isReady(Features() << FeatureCore, true);
+    }
+    return mPriv->readinessHelper->isReady(features, features.contains(FeatureCore));
 }
 
 /**
@@ -668,22 +675,25 @@ bool Account::isReady(const QSet<uint> &features) const
  * \return A PendingReady object which will emit finished
  *         when this object has finished or failed its initial setup.
  */
-PendingReady *Account::becomeReady(const QSet<uint> &requestedFeatures)
+PendingReady *Account::becomeReady(const Features &requestedFeatures)
 {
+    if (requestedFeatures.isEmpty()) {
+        return mPriv->readinessHelper->becomeReady(Features() << FeatureCore);
+    }
     return mPriv->readinessHelper->becomeReady(requestedFeatures);
 }
 
-QSet<uint> Account::requestedFeatures() const
+Features Account::requestedFeatures() const
 {
     return mPriv->readinessHelper->requestedFeatures();
 }
 
-QSet<uint> Account::actualFeatures() const
+Features Account::actualFeatures() const
 {
     return mPriv->readinessHelper->actualFeatures();
 }
 
-QSet<uint> Account::missingFeatures() const
+Features Account::missingFeatures() const
 {
     return mPriv->readinessHelper->missingFeatures();
 }
@@ -750,6 +760,11 @@ AccountInterface *Account::baseInterface() const
     return mPriv->baseInterface;
 }
 
+ReadinessHelper *Account::readinessHelper() const
+{
+    return mPriv->readinessHelper;
+}
+
 /**** Private ****/
 void Account::Private::init()
 {
diff --git a/TelepathyQt4/Client/account.h b/TelepathyQt4/Client/account.h
index 53c60ac..d38ec83 100644
--- a/TelepathyQt4/Client/account.h
+++ b/TelepathyQt4/Client/account.h
@@ -31,6 +31,7 @@
 #include <TelepathyQt4/Client/DBus>
 #include <TelepathyQt4/Client/DBusProxy>
 #include <TelepathyQt4/Client/OptionalInterfaceFactory>
+#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Constants>
 
 #include <QSet>
@@ -59,13 +60,9 @@ class Account : public StatelessDBusProxy,
     Q_DISABLE_COPY(Account)
 
 public:
-    enum Feature {
-        FeatureCore = 0,
-        FeatureAvatar = 1,
-        FeatureProtocolInfo = 2,
-        _Padding = 0xFFFFFFFF
-    };
-    Q_DECLARE_FLAGS(Features, Feature)
+    static const Feature FeatureCore;
+    static const Feature FeatureAvatar;
+    static const Feature FeatureProtocolInfo;
 
     Account(AccountManager *am, const QString &objectPath,
             QObject *parent = 0);
@@ -130,13 +127,12 @@ public:
 
     PendingOperation *remove();
 
-    bool isReady(const QSet<uint> &features = QSet<uint>()) const;
+    virtual bool isReady(const Features &features = Features()) const;
+    virtual PendingReady *becomeReady(const Features &requestedFeatures = Features());
 
-    PendingReady *becomeReady(const QSet<uint> &requestedFeatures = QSet<uint>());
-
-    QSet<uint> requestedFeatures() const;
-    QSet<uint> actualFeatures() const;
-    QSet<uint> missingFeatures() const;
+    virtual Features requestedFeatures() const;
+    virtual Features actualFeatures() const;
+    virtual Features missingFeatures() const;
 
     QStringList interfaces() const;
 
@@ -185,6 +181,8 @@ Q_SIGNALS:
 protected:
     AccountInterface *baseInterface() const;
 
+    ReadinessHelper *readinessHelper() const;
+
 private Q_SLOTS:
     void gotMainProperties(QDBusPendingCallWatcher *);
     void gotAvatar(QDBusPendingCallWatcher *);
@@ -199,8 +197,6 @@ private:
     Private *mPriv;
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS(Account::Features)
-
 } // Telepathy::Client
 } // Telepathy
 
diff --git a/TelepathyQt4/Client/connection-internal.h b/TelepathyQt4/Client/connection-internal.h
index dead1f0..c39e752 100644
--- a/TelepathyQt4/Client/connection-internal.h
+++ b/TelepathyQt4/Client/connection-internal.h
@@ -38,14 +38,14 @@ class Connection::PendingConnect : public PendingOperation
     Q_OBJECT
 
 public:
-    PendingConnect(Connection *parent, const QSet<uint> &requestedFeatures);
+    PendingConnect(Connection *parent, const Features &requestedFeatures);
 
 private Q_SLOTS:
     void onConnectReply(QDBusPendingCallWatcher *);
     void onBecomeReadyReply(Telepathy::Client::PendingOperation *);
 
 private:
-    QSet<uint> requestedFeatures;
+    Features requestedFeatures;
 };
 
 } // Telepathy::Client
diff --git a/TelepathyQt4/Client/connection-manager.cpp b/TelepathyQt4/Client/connection-manager.cpp
index bc57f3d..4898da7 100644
--- a/TelepathyQt4/Client/connection-manager.cpp
+++ b/TelepathyQt4/Client/connection-manager.cpp
@@ -32,7 +32,6 @@
 #include <TelepathyQt4/Client/DBus>
 #include <TelepathyQt4/Client/PendingConnection>
 #include <TelepathyQt4/Client/PendingReady>
-#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Constants>
 #include <TelepathyQt4/ManagerFile>
 #include <TelepathyQt4/Types>
@@ -290,12 +289,12 @@ ConnectionManager::Private::Private(ConnectionManager *parent, const QString &na
 {
     debug() << "Creating new ConnectionManager:" << parent->busName();
 
-    QMap<uint, ReadinessHelper::Introspectable> introspectables;
+    ReadinessHelper::Introspectables introspectables;
 
     // As ConnectionManager does not have predefined statuses let's simulate one (0)
     ReadinessHelper::Introspectable introspectableCore(
         QSet<uint>() << 0,                                           // makesSenseForStatuses
-        QSet<uint>(),                                                // dependsOnFeatures
+        Features(),                                                  // dependsOnFeatures
         QStringList(),                                               // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectMain,
         this);
@@ -303,6 +302,7 @@ ConnectionManager::Private::Private(ConnectionManager *parent, const QString &na
 
     readinessHelper = new ReadinessHelper(parent, 0 /* status */,
             introspectables, parent);
+    readinessHelper->becomeReady(Features() << FeatureCore);
 }
 
 ConnectionManager::Private::~Private()
@@ -348,6 +348,8 @@ ProtocolInfo *ConnectionManager::Private::protocol(const QString &protocolName)
  * applications.
  */
 
+const Feature ConnectionManager::FeatureCore = Feature(ConnectionManager::staticMetaObject.className(), 0);
+
 /**
  * Construct a new ConnectionManager object.
  *
@@ -468,9 +470,12 @@ PendingConnection *ConnectionManager::requestConnection(const QString &protocol,
  * \param features The features which should be tested
  * \return \c true if the object has finished initial setup.
  */
-bool ConnectionManager::isReady(const QSet<uint> &features) const
+bool ConnectionManager::isReady(const Features &features) const
 {
-    return mPriv->readinessHelper->isReady(features);
+    if (features.isEmpty()) {
+        return mPriv->readinessHelper->isReady(Features() << FeatureCore, true);
+    }
+    return mPriv->readinessHelper->isReady(features, features.contains(FeatureCore));
 }
 
 /**
@@ -486,22 +491,25 @@ bool ConnectionManager::isReady(const QSet<uint> &features) const
  *         when this object has finished or failed initial setup for basic
  *         functionality plus the given features
  */
-PendingReady *ConnectionManager::becomeReady(const QSet<uint> &requestedFeatures)
+PendingReady *ConnectionManager::becomeReady(const Features &requestedFeatures)
 {
+    if (requestedFeatures.isEmpty()) {
+        return mPriv->readinessHelper->becomeReady(Features() << FeatureCore);
+    }
     return mPriv->readinessHelper->becomeReady(requestedFeatures);
 }
 
-QSet<uint> ConnectionManager::requestedFeatures() const
+Features ConnectionManager::requestedFeatures() const
 {
     return mPriv->readinessHelper->requestedFeatures();
 }
 
-QSet<uint> ConnectionManager::actualFeatures() const
+Features ConnectionManager::actualFeatures() const
 {
     return mPriv->readinessHelper->actualFeatures();
 }
 
-QSet<uint> ConnectionManager::missingFeatures() const
+Features ConnectionManager::missingFeatures() const
 {
     return mPriv->readinessHelper->missingFeatures();
 }
@@ -534,6 +542,11 @@ ConnectionManagerInterface *ConnectionManager::baseInterface() const
     return mPriv->baseInterface;
 }
 
+ReadinessHelper *ConnectionManager::readinessHelper() const
+{
+    return mPriv->readinessHelper;
+}
+
 /**** Private ****/
 bool ConnectionManager::Private::parseConfigFile()
 {
diff --git a/TelepathyQt4/Client/connection-manager.h b/TelepathyQt4/Client/connection-manager.h
index 4a0da56..014ebef 100644
--- a/TelepathyQt4/Client/connection-manager.h
+++ b/TelepathyQt4/Client/connection-manager.h
@@ -31,6 +31,7 @@
 #include <TelepathyQt4/Client/DBus>
 #include <TelepathyQt4/Client/DBusProxy>
 #include <TelepathyQt4/Client/OptionalInterfaceFactory>
+#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Constants>
 
 #include <QSet>
@@ -120,11 +121,7 @@ class ConnectionManager : public StatelessDBusProxy,
     Q_OBJECT
 
 public:
-    enum Feature {
-        FeatureCore = 0,
-        _Padding = 0xFFFFFFFF
-    };
-    Q_DECLARE_FLAGS(Features, Feature)
+    static const Feature FeatureCore;
 
     ConnectionManager(const QString &name, QObject *parent = 0);
     ConnectionManager(const QDBusConnection &bus,
@@ -147,19 +144,20 @@ public:
         return OptionalInterfaceFactory<ConnectionManager>::interface<DBus::PropertiesInterface>();
     }
 
-    bool isReady(const QSet<uint> &features = QSet<uint>()) const;
+    virtual bool isReady(const Features &features = Features()) const;
+    virtual PendingReady *becomeReady(const Features &requestedFeatures = Features());
 
-    PendingReady *becomeReady(const QSet<uint> &requestedFeatures = QSet<uint>());
-
-    QSet<uint> requestedFeatures() const;
-    QSet<uint> actualFeatures() const;
-    QSet<uint> missingFeatures() const;
+    virtual Features requestedFeatures() const;
+    virtual Features actualFeatures() const;
+    virtual Features missingFeatures() const;
 
     static PendingStringList *listNames(const QDBusConnection &bus = QDBusConnection::sessionBus());
 
 protected:
     ConnectionManagerInterface *baseInterface() const;
 
+    ReadinessHelper *readinessHelper() const;
+
 private Q_SLOTS:
     void gotMainProperties(QDBusPendingCallWatcher *);
     void gotProtocols(QDBusPendingCallWatcher *);
diff --git a/TelepathyQt4/Client/connection.cpp b/TelepathyQt4/Client/connection.cpp
index 4879a0f..5215923 100644
--- a/TelepathyQt4/Client/connection.cpp
+++ b/TelepathyQt4/Client/connection.cpp
@@ -38,7 +38,6 @@
 #include <TelepathyQt4/Client/PendingReady>
 #include <TelepathyQt4/Client/PendingReadyChannel>
 #include <TelepathyQt4/Client/PendingVoidMethodCall>
-#include <TelepathyQt4/Client/ReadinessHelper>
 #include <TelepathyQt4/Client/ReferencedHandles>
 
 #include <QMap>
@@ -171,19 +170,19 @@ Connection::Private::Private(Connection *parent)
       handleContext(0),
       contactManager(new ContactManager(parent))
 {
-    QMap<uint, ReadinessHelper::Introspectable> introspectables;
+    ReadinessHelper::Introspectables introspectables;
 
     ReadinessHelper::Introspectable introspectableCore(
         QSet<uint>() << Connection::StatusDisconnected << Connection::StatusConnected, // makesSenseForStatuses
-        QSet<uint>(),                                                                  // dependsOnFeatures
-        QStringList(),                                                                 // dependsOnInterfaces
+        Features(),                                                                    // dependsOnFeatures (none)
+        QStringList(),                                                                 // dependsOnInterfaces (none)
         (ReadinessHelper::IntrospectFunc) &Private::introspectMain,
         this);
     introspectables[FeatureCore] = introspectableCore;
 
     ReadinessHelper::Introspectable introspectableSelfContact(
         QSet<uint>() << Connection::StatusConnected,                                   // makesSenseForStatuses
-        QSet<uint>() << FeatureCore,                                                   // dependsOnFeatures (core)
+        Features() << FeatureCore,                                                     // dependsOnFeatures (core)
         QStringList() << TELEPATHY_INTERFACE_CONNECTION_INTERFACE_CONTACTS,            // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectSelfContact,
         this);
@@ -191,7 +190,7 @@ Connection::Private::Private(Connection *parent)
 
     ReadinessHelper::Introspectable introspectableSimplePresence(
         QSet<uint>() << Connection::StatusConnected,                                   // makesSenseForStatuses
-        QSet<uint>() << FeatureCore,                                                   // dependsOnFeatures (core)
+        Features() << FeatureCore,                                                     // dependsOnFeatures (core)
         QStringList() << TELEPATHY_INTERFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,     // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectSimplePresence,
         this);
@@ -199,7 +198,7 @@ Connection::Private::Private(Connection *parent)
 
     ReadinessHelper::Introspectable introspectableRoster(
         QSet<uint>() << Connection::StatusConnected,                                   // makesSenseForStatuses
-        QSet<uint>() << 0,                                                             // dependsOnFeatures (core)
+        Features() << FeatureCore,                                                     // dependsOnFeatures (core)
         QStringList() << TELEPATHY_INTERFACE_CONNECTION_INTERFACE_CONTACTS,            // dependsOnInterfaces
         (ReadinessHelper::IntrospectFunc) &Private::introspectRoster,
         this);
@@ -210,6 +209,7 @@ Connection::Private::Private(Connection *parent)
     parent->connect(readinessHelper,
             SIGNAL(statusReady(uint)),
             SLOT(onStatusReady(uint)));
+    readinessHelper->becomeReady(Features() << FeatureCore);
 
     init();
 }
@@ -386,7 +386,7 @@ void Connection::Private::introspectRoster(Connection::Private *self)
     }
 }
 
-Connection::PendingConnect::PendingConnect(Connection *parent, const QSet<uint> &requestedFeatures)
+Connection::PendingConnect::PendingConnect(Connection *parent, const Features &requestedFeatures)
     : PendingOperation(parent),
       requestedFeatures(requestedFeatures)
 {
@@ -450,6 +450,11 @@ QMutex Connection::Private::handleContextsLock;
  * in the different states.
  */
 
+const Feature Connection::FeatureCore = Feature(Connection::staticMetaObject.className(), 0);
+const Feature Connection::FeatureSelfContact = Feature(Connection::staticMetaObject.className(), 1);
+const Feature Connection::FeatureSimplePresence = Feature(Connection::staticMetaObject.className(), 2);
+const Feature Connection::FeatureRoster = Feature(Connection::staticMetaObject.className(), 3);
+
 /**
  * Construct a new Connection object.
  *
@@ -565,7 +570,7 @@ uint Connection::selfHandle() const
  */
 SimpleStatusSpecMap Connection::allowedPresenceStatuses() const
 {
-    if (!isReady(QSet<uint>() << FeatureSimplePresence)) {
+    if (!isReady(Features() << FeatureSimplePresence)) {
         warning() << "Trying to retrieve simple presence from connection, but "
                      "simple presence is not supported or was not requested. "
                      "Use becomeReady(FeatureSimplePresence)";
@@ -1017,6 +1022,11 @@ ConnectionInterface *Connection::baseInterface() const
     return mPriv->baseInterface;
 }
 
+ReadinessHelper *Connection::readinessHelper() const
+{
+    return mPriv->readinessHelper;
+}
+
 /**
  * Asynchronously creates a channel satisfying the given request.
  *
@@ -1250,9 +1260,12 @@ PendingHandles *Connection::referenceHandles(uint handleType, const UIntList &ha
  * \return \c true if the object has finished its initial setup for basic
  *         functionality plus the given features
  */
-bool Connection::isReady(const QSet<uint> &features) const
+bool Connection::isReady(const Features &features) const
 {
-    return mPriv->readinessHelper->isReady(features);
+    if (features.isEmpty()) {
+        return mPriv->readinessHelper->isReady(Features() << FeatureCore, true);
+    }
+    return mPriv->readinessHelper->isReady(features, features.contains(FeatureCore));
 }
 
 /**
@@ -1268,22 +1281,25 @@ bool Connection::isReady(const QSet<uint> &features) const
  *         when this object has finished or failed initial setup for basic
  *         functionality plus the given features
  */
-PendingReady *Connection::becomeReady(const QSet<uint> &requestedFeatures)
+PendingReady *Connection::becomeReady(const Features &requestedFeatures)
 {
+    if (requestedFeatures.isEmpty()) {
+        return mPriv->readinessHelper->becomeReady(Features() << FeatureCore);
+    }
     return mPriv->readinessHelper->becomeReady(requestedFeatures);
 }
 
-QSet<uint> Connection::requestedFeatures() const
+Features Connection::requestedFeatures() const
 {
     return mPriv->readinessHelper->requestedFeatures();
 }
 
-QSet<uint> Connection::actualFeatures() const
+Features Connection::actualFeatures() const
 {
     return mPriv->readinessHelper->actualFeatures();
 }
 
-QSet<uint> Connection::missingFeatures() const
+Features Connection::missingFeatures() const
 {
     return mPriv->readinessHelper->missingFeatures();
 }
@@ -1301,7 +1317,7 @@ QSet<uint> Connection::missingFeatures() const
  *         for basic functionality, plus the given features, has succeeded or
  *         failed
  */
-PendingOperation *Connection::requestConnect(const QSet<uint> &requestedFeatures)
+PendingOperation *Connection::requestConnect(const Features &requestedFeatures)
 {
     return new PendingConnect(this, requestedFeatures);
 }
diff --git a/TelepathyQt4/Client/connection.h b/TelepathyQt4/Client/connection.h
index 48dd5dd..51ebbbf 100644
--- a/TelepathyQt4/Client/connection.h
+++ b/TelepathyQt4/Client/connection.h
@@ -31,6 +31,7 @@
 #include <TelepathyQt4/Client/DBus>
 #include <TelepathyQt4/Client/DBusProxy>
 #include <TelepathyQt4/Client/OptionalInterfaceFactory>
+#include <TelepathyQt4/Client/ReadinessHelper>
 
 #include <TelepathyQt4/Constants>
 #include <TelepathyQt4/Types>
@@ -62,14 +63,10 @@ class Connection : public StatefulDBusProxy,
     Q_ENUMS(Status)
 
 public:
-    enum Feature {
-        FeatureCore = 0,
-        FeatureSelfContact = 1,
-        FeatureSimplePresence = 2,
-        FeatureRoster = 4,
-        _Padding = 0xFFFFFFFF
-    };
-    Q_DECLARE_FLAGS(Features, Feature)
+    static const Feature FeatureCore;
+    static const Feature FeatureSelfContact;
+    static const Feature FeatureSimplePresence;
+    static const Feature FeatureRoster;
 
     enum Status {
         StatusDisconnected = Telepathy::ConnectionStatusDisconnected,
@@ -160,7 +157,7 @@ public:
 
     PendingChannel *ensureChannel(const QVariantMap &request);
 
-    PendingOperation *requestConnect(const QSet<uint> &requestedFeatures = QSet<uint>());
+    PendingOperation *requestConnect(const Features &requestedFeatures = Features());
 
     PendingOperation *requestDisconnect();
 
@@ -173,13 +170,12 @@ public:
     QStringList contactAttributeInterfaces() const;
     ContactManager *contactManager() const;
 
-    bool isReady(const QSet<uint> &features = QSet<uint>()) const;
-
-    PendingReady *becomeReady(const QSet<uint> &requestedFeatures = QSet<uint>());
+    virtual bool isReady(const Features &features = Features()) const;
+    virtual PendingReady *becomeReady(const Features &requestedFeatures = Features());
 
-    QSet<uint> requestedFeatures() const;
-    QSet<uint> actualFeatures() const;
-    QSet<uint> missingFeatures() const;
+    virtual Features requestedFeatures() const;
+    virtual Features actualFeatures() const;
+    virtual Features missingFeatures() const;
 
 Q_SIGNALS:
     void statusChanged(uint newStatus, uint newStatusReason);
@@ -190,6 +186,8 @@ Q_SIGNALS:
 protected:
     ConnectionInterface *baseInterface() const;
 
+    ReadinessHelper *readinessHelper() const;
+
 private Q_SLOTS:
     void onStatusReady(uint);
     void onStatusChanged(uint, uint);
@@ -223,8 +221,6 @@ private:
     Private *mPriv;
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS(Connection::Features)
-
 } // Telepathy::Client
 } // Telepathy
 
diff --git a/TelepathyQt4/Client/pending-ready.cpp b/TelepathyQt4/Client/pending-ready.cpp
index 825e82c..9729d95 100644
--- a/TelepathyQt4/Client/pending-ready.cpp
+++ b/TelepathyQt4/Client/pending-ready.cpp
@@ -43,13 +43,13 @@ namespace Client
 
 struct PendingReady::Private
 {
-    Private(const QSet<uint> &requestedFeatures, QObject *object) :
+    Private(const Features &requestedFeatures, QObject *object) :
         requestedFeatures(requestedFeatures),
         object(object)
     {
     }
 
-    QSet<uint> requestedFeatures;
+    Features requestedFeatures;
     QObject *object;
 };
 
@@ -67,7 +67,8 @@ struct PendingReady::Private
  *
  * \param object The object that will become ready.
  */
-PendingReady::PendingReady(const QSet<uint> &requestedFeatures, QObject *object)
+PendingReady::PendingReady(const Features &requestedFeatures,
+        QObject *object)
     : PendingOperation(object),
       mPriv(new Private(requestedFeatures, object))
 {
@@ -97,7 +98,7 @@ QObject *PendingReady::object() const
  *
  * \return Features.
  */
-QSet<uint> PendingReady::requestedFeatures() const
+Features PendingReady::requestedFeatures() const
 {
     return mPriv->requestedFeatures;
 }
diff --git a/TelepathyQt4/Client/pending-ready.h b/TelepathyQt4/Client/pending-ready.h
index 92bda3f..f4f0cdf 100644
--- a/TelepathyQt4/Client/pending-ready.h
+++ b/TelepathyQt4/Client/pending-ready.h
@@ -44,11 +44,12 @@ public:
     ~PendingReady();
 
     QObject *object() const;
-    QSet<uint> requestedFeatures() const;
+
+    Features requestedFeatures() const;
 
 private:
     Q_DISABLE_COPY(PendingReady);
-    PendingReady(const QSet<uint> &requestedFeatures, QObject *object);
+    PendingReady(const Features &requestedFeatures, QObject *object);
 
     struct Private;
     friend struct Private;
diff --git a/TelepathyQt4/Client/readiness-helper.cpp b/TelepathyQt4/Client/readiness-helper.cpp
index 03034ef..eff418f 100644
--- a/TelepathyQt4/Client/readiness-helper.cpp
+++ b/TelepathyQt4/Client/readiness-helper.cpp
@@ -40,12 +40,11 @@ struct ReadinessHelper::Private
     Private(ReadinessHelper *parent,
             DBusProxy *proxy,
             uint currentStatus,
-            const QMap<uint, Introspectable> &introspectables);
+            const Introspectables &introspectables);
     ~Private();
 
     void setCurrentStatus(uint newStatus);
-    void introspectCore();
-    void setIntrospectCompleted(uint feature, bool success);
+    void setIntrospectCompleted(Feature feature, bool success);
     void iterateIntrospection();
 
     void abortOperations(const QString &errorName, const QString &errorMessage);
@@ -54,14 +53,14 @@ struct ReadinessHelper::Private
     DBusProxy *proxy;
     uint currentStatus;
     QStringList interfaces;
-    QMap<uint, Introspectable> introspectables;
+    Introspectables introspectables;
     QSet<uint> supportedStatuses;
-    QSet<uint> supportedFeatures;
-    QSet<uint> satisfiedFeatures;
-    QSet<uint> requestedFeatures;
-    QSet<uint> missingFeatures;
-    QSet<uint> pendingFeatures;
-    QSet<uint> inFlightFeatures;
+    Features supportedFeatures;
+    Features satisfiedFeatures;
+    Features requestedFeatures;
+    Features missingFeatures;
+    Features pendingFeatures;
+    Features inFlightFeatures;
     QList<PendingReady *> pendingOperations;
 
     bool pendingStatusChange;
@@ -72,7 +71,7 @@ ReadinessHelper::Private::Private(
         ReadinessHelper *parent,
         DBusProxy *proxy,
         uint currentStatus,
-        const QMap<uint, Introspectable> &introspectables)
+        const Introspectables &introspectables)
     : parent(parent),
       proxy(proxy),
       currentStatus(currentStatus),
@@ -80,12 +79,10 @@ ReadinessHelper::Private::Private(
       pendingStatusChange(false),
       pendingStatus(-1)
 {
-    // we must have an introspectable for core
-    Q_ASSERT(introspectables.contains(0));
-
-    QMap<uint, Introspectable>::const_iterator i = introspectables.constBegin();
-    while (i != introspectables.constEnd()) {
-        uint feature = i.key();
+    Introspectables::const_iterator i = introspectables.constBegin();
+    Introspectables::const_iterator end = introspectables.constEnd();
+    while (i != end) {
+        Feature feature = i.key();
         Introspectable introspectable = i.value();
         Q_ASSERT(introspectable.introspectFunc != 0);
         supportedStatuses += introspectable.makesSenseForStatuses;
@@ -95,10 +92,6 @@ ReadinessHelper::Private::Private(
 
     debug() << "ReadinessHelper: supportedStatuses =" << supportedStatuses;
     debug() << "ReadinessHelper: supportedFeatures =" << supportedFeatures;
-
-    if (supportedStatuses.contains(currentStatus)) {
-        introspectCore();
-    }
 }
 
 ReadinessHelper::Private::~Private()
@@ -117,7 +110,7 @@ void ReadinessHelper::Private::setCurrentStatus(uint newStatus)
         pendingFeatures = requestedFeatures;
 
         if (supportedStatuses.contains(currentStatus)) {
-            introspectCore();
+            QTimer::singleShot(0, parent, SLOT(iterateIntrospection()));
         } else {
             emit parent->statusReady(currentStatus);
         }
@@ -128,15 +121,7 @@ void ReadinessHelper::Private::setCurrentStatus(uint newStatus)
     }
 }
 
-void ReadinessHelper::Private::introspectCore()
-{
-    debug() << "Status changed to" << currentStatus << "- introspecting core";
-    requestedFeatures += 0;
-    pendingFeatures += 0;
-    QTimer::singleShot(0, parent, SLOT(iterateIntrospection()));
-}
-
-void ReadinessHelper::Private::setIntrospectCompleted(uint feature, bool success)
+void ReadinessHelper::Private::setIntrospectCompleted(Feature feature, bool success)
 {
     debug() << "ReadinessHelper::setIntrospectCompleted: feature:" << feature <<
         "- success:" << success;
@@ -185,11 +170,12 @@ void ReadinessHelper::Private::iterateIntrospection()
 
     // take care to flag anything with dependencies in missing, and the
     // stuff depending on them, as missing
-    QMap<uint, Introspectable>::const_iterator i = introspectables.constBegin();
-    while (i != introspectables.constEnd()) {
-        uint feature = i.key();
+    Introspectables::const_iterator i = introspectables.constBegin();
+    Introspectables::const_iterator end = introspectables.constEnd();
+    while (i != end) {
+        Feature feature = i.key();
         Introspectable introspectable = i.value();
-        QSet<uint> dependsOnFeatures = introspectable.dependsOnFeatures;
+        Features dependsOnFeatures = introspectable.dependsOnFeatures;
         if (!dependsOnFeatures.intersect(missingFeatures).isEmpty()) {
             missingFeatures += feature;
         }
@@ -217,8 +203,8 @@ void ReadinessHelper::Private::iterateIntrospection()
     pendingFeatures -= (satisfiedFeatures + missingFeatures);
 
     // find out which features don't have dependencies that are still pending
-    QSet<uint> readyToIntrospect;
-    foreach (uint feature, pendingFeatures) {
+    Features readyToIntrospect;
+    foreach (Feature feature, pendingFeatures) {
         // missing doesn't have to be considered here anymore
         if ((introspectables[feature].dependsOnFeatures - satisfiedFeatures).isEmpty()) {
             readyToIntrospect.insert(feature);
@@ -227,7 +213,7 @@ void ReadinessHelper::Private::iterateIntrospection()
 
     // now readyToIntrospect should contain all the features which have
     // all their feature dependencies satisfied
-    foreach (uint feature, readyToIntrospect) {
+    foreach (Feature feature, readyToIntrospect) {
         if (inFlightFeatures.contains(feature)) {
             continue;
         }
@@ -243,18 +229,15 @@ void ReadinessHelper::Private::iterateIntrospection()
             return; // will be called with a single-shot soon again
         }
 
-        if (feature != 0) {
-            foreach (const QString &interface, introspectable.dependsOnInterfaces) {
-                if (!interfaces.contains(interface)) {
-                    // Core is a dependency for everything, so interfaces are
-                    // introspected - if not all of them are present, the feature can't
-                    // possibly be satisfied
-                    debug() << "feature" << feature << "depends on interfaces" <<
-                        introspectable.dependsOnInterfaces << ", but interface" << interface <<
-                        "is not present";
-                    setIntrospectCompleted(feature, false);
-                    return; // will be called with a single-shot soon again
-                }
+        foreach (const QString &interface, introspectable.dependsOnInterfaces) {
+            if (!interfaces.contains(interface)) {
+                // If a feature is ready to introspect and depends on a interface
+                // that is not present the feature can't possibly be satisfied
+                debug() << "feature" << feature << "depends on interfaces" <<
+                    introspectable.dependsOnInterfaces << ", but interface" << interface <<
+                    "is not present";
+                setIntrospectCompleted(feature, false);
+                return; // will be called with a single-shot soon again
             }
         }
 
@@ -275,7 +258,7 @@ void ReadinessHelper::Private::abortOperations(const QString &errorName,
 
 ReadinessHelper::ReadinessHelper(DBusProxy *proxy,
         uint currentStatus,
-        const QMap<uint, Introspectable> &introspectables,
+        const Introspectables &introspectables,
         QObject *parent)
     : QObject(parent),
       mPriv(new Private(this, proxy, currentStatus, introspectables))
@@ -290,6 +273,25 @@ ReadinessHelper::~ReadinessHelper()
     delete mPriv;
 }
 
+void ReadinessHelper::addIntrospectables(const Introspectables &introspectables)
+{
+    // QMap::unite will create multiple items if the key is already in the map
+    // so let's make sure we don't duplicate keys
+    Introspectables::const_iterator i = introspectables.constBegin();
+    Introspectables::const_iterator end = introspectables.constEnd();
+    while (i != end) {
+        Feature feature = i.key();
+        if (mPriv->introspectables.contains(feature)) {
+            warning() << "ReadinessHelper::addIntrospectables: trying to add an "
+                "introspectable for feature" << feature << "but introspectable "
+                "for this feature already exists";
+        } else {
+            mPriv->introspectables.insert(feature, i.value());
+        }
+        ++i;
+    }
+}
+
 uint ReadinessHelper::currentStatus() const
 {
     return mPriv->currentStatus;
@@ -310,46 +312,41 @@ void ReadinessHelper::setInterfaces(const QStringList &interfaces)
     mPriv->interfaces = interfaces;
 }
 
-QSet<uint> ReadinessHelper::requestedFeatures() const
+Features ReadinessHelper::requestedFeatures() const
 {
     return mPriv->requestedFeatures;
 }
 
-QSet<uint> ReadinessHelper::actualFeatures() const
+Features ReadinessHelper::actualFeatures() const
 {
     return mPriv->satisfiedFeatures;
 }
 
-QSet<uint> ReadinessHelper::missingFeatures() const
+Features ReadinessHelper::missingFeatures() const
 {
     return mPriv->missingFeatures;
 }
 
-bool ReadinessHelper::isReady(QSet<uint> features) const
+bool ReadinessHelper::isReady(const Features &features, bool onlySatisfied) const
 {
     if (!mPriv->proxy->isValid()) {
         return false;
     }
 
-    if (features.isEmpty()) {
-        features << 0; // it is empty, consider core
-    }
+    Q_ASSERT(!features.isEmpty());
 
-    // if we ask if core is ready, core should be on satisfiedFeatures
-    if (features.contains(0)) {
+    if (onlySatisfied) {
         return (features - mPriv->satisfiedFeatures).isEmpty();
     } else {
         return (features - (mPriv->satisfiedFeatures + mPriv->missingFeatures)).isEmpty();
     }
 }
 
-PendingReady *ReadinessHelper::becomeReady(QSet<uint> requestedFeatures)
+PendingReady *ReadinessHelper::becomeReady(const Features &requestedFeatures)
 {
-    if (requestedFeatures.isEmpty()) {
-        requestedFeatures << 0; // it is empty, consider core
-    }
+    Q_ASSERT(!requestedFeatures.isEmpty());
 
-    QSet<uint> supportedFeatures = mPriv->supportedFeatures;
+    Features supportedFeatures = mPriv->supportedFeatures;
     if (supportedFeatures.intersect(requestedFeatures) != requestedFeatures) {
         debug() << "ReadinessHelper::becomeReady called with invalid features: requestedFeatures =" <<
             requestedFeatures << "- supportedFeatures =" << mPriv->supportedFeatures;
@@ -387,7 +384,7 @@ PendingReady *ReadinessHelper::becomeReady(QSet<uint> requestedFeatures)
     return operation;
 }
 
-void ReadinessHelper::setIntrospectCompleted(uint feature, bool success)
+void ReadinessHelper::setIntrospectCompleted(Feature feature, bool success)
 {
     if (!mPriv->proxy->isValid()) {
         // proxy became invalid, ignore here
diff --git a/TelepathyQt4/Client/readiness-helper.h b/TelepathyQt4/Client/readiness-helper.h
index 4096923..4389fea 100644
--- a/TelepathyQt4/Client/readiness-helper.h
+++ b/TelepathyQt4/Client/readiness-helper.h
@@ -39,6 +39,9 @@ namespace Client
 
 class PendingReady;
 
+typedef QPair<QString, uint> Feature;
+typedef QSet<Feature> Features;
+
 class ReadinessHelper : public QObject
 {
     Q_OBJECT
@@ -55,7 +58,7 @@ public:
         }
 
         Introspectable(const QSet<uint> &makesSenseForStatuses,
-                const QSet<uint> &dependsOnFeatures,
+                const Features &dependsOnFeatures,
                 const QStringList &dependsOnInterfaces,
                 IntrospectFunc introspectFunc,
                 void *introspectFuncData)
@@ -71,32 +74,35 @@ public:
         friend class ReadinessHelper;
 
         QSet<uint> makesSenseForStatuses;
-        QSet<uint> dependsOnFeatures;
+        Features dependsOnFeatures;
         QStringList dependsOnInterfaces;
         IntrospectFunc introspectFunc;
         void *introspectFuncData;
     };
+    typedef QMap<Feature, Introspectable> Introspectables;
 
     ReadinessHelper(DBusProxy *proxy,
             uint currentStatus,
-            const QMap<uint, Introspectable> &introspectables,
+            const Introspectables &introspectables,
             QObject *parent = 0);
     ~ReadinessHelper();
 
+    void addIntrospectables(const Introspectables &introspectables);
+
     uint currentStatus() const;
     void setCurrentStatus(uint currentStatus);
 
     QStringList interfaces() const;
     void setInterfaces(const QStringList &interfaces);
 
-    QSet<uint> requestedFeatures() const;
-    QSet<uint> actualFeatures() const;
-    QSet<uint> missingFeatures() const;
+    Features requestedFeatures() const;
+    Features actualFeatures() const;
+    Features missingFeatures() const;
 
-    bool isReady(QSet<uint> features) const;
-    PendingReady *becomeReady(QSet<uint> requestedFeatures);
+    bool isReady(const Features &features, bool onlySatisfied) const;
+    PendingReady *becomeReady(const Features &requestedFeatures);
 
-    void setIntrospectCompleted(uint feature, bool success);
+    void setIntrospectCompleted(Feature feature, bool success);
 
 Q_SIGNALS:
     void statusReady(uint status);
-- 
1.5.6.5




More information about the telepathy-commits mailing list