/**
* This file is part of TelepathyQt
*
* @copyright Copyright (C) 2010 Collabora Ltd.
* @copyright Copyright (C) 2010 Nokia Corporation
* @license LGPL 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include
#include "TelepathyQt/account-set-internal.h"
#include "TelepathyQt/_gen/account-set.moc.hpp"
#include "TelepathyQt/_gen/account-set-internal.moc.hpp"
#include "TelepathyQt/debug-internal.h"
#include
#include
#include
#include
#include
namespace Tp
{
AccountSet::Private::Private(AccountSet *parent,
const AccountManagerPtr &accountManager,
const AccountFilterConstPtr &filter)
: parent(parent),
accountManager(accountManager),
filter(filter),
ready(false)
{
init();
}
AccountSet::Private::Private(AccountSet *parent,
const AccountManagerPtr &accountManager,
const QVariantMap &filterMap)
: parent(parent),
accountManager(accountManager),
ready(false)
{
AccountPropertyFilterPtr propertyFilter = AccountPropertyFilter::create();
for (QVariantMap::const_iterator i = filterMap.constBegin();
i != filterMap.constEnd(); ++i) {
propertyFilter->addProperty(i.key(), i.value());
}
filter = AccountFilterPtr::dynamicCast(propertyFilter);
init();
}
void AccountSet::Private::init()
{
if (filter->isValid()) {
connectSignals();
insertAccounts();
ready = true;
}
}
void AccountSet::Private::connectSignals()
{
parent->connect(accountManager.data(),
SIGNAL(newAccount(Tp::AccountPtr)),
SLOT(onNewAccount(Tp::AccountPtr)));
}
void AccountSet::Private::insertAccounts()
{
foreach (const Tp::AccountPtr &account, accountManager->allAccounts()) {
insertAccount(account);
}
}
void AccountSet::Private::insertAccount(const Tp::AccountPtr &account)
{
QString accountPath = account->objectPath();
Q_ASSERT(!wrappers.contains(accountPath));
wrapAccount(account);
filterAccount(account);
}
void AccountSet::Private::removeAccount(const Tp::AccountPtr &account)
{
QString accountPath = account->objectPath();
Q_ASSERT(wrappers.contains(accountPath));
accounts.remove(accountPath);
AccountWrapper *wrapper = wrappers.take(accountPath);
Q_ASSERT(wrapper->disconnect(parent));
wrapper->deleteLater();
emit parent->accountRemoved(account);
}
void AccountSet::Private::wrapAccount(const AccountPtr &account)
{
AccountWrapper *wrapper = new AccountWrapper(account, parent);
parent->connect(wrapper,
SIGNAL(accountRemoved(Tp::AccountPtr)),
SLOT(onAccountRemoved(Tp::AccountPtr)));
parent->connect(wrapper,
SIGNAL(accountPropertyChanged(Tp::AccountPtr,QString)),
SLOT(onAccountChanged(Tp::AccountPtr)));
parent->connect(wrapper,
SIGNAL(accountCapabilitiesChanged(Tp::AccountPtr,Tp::ConnectionCapabilities)),
SLOT(onAccountChanged(Tp::AccountPtr)));
wrappers.insert(account->objectPath(), wrapper);
}
void AccountSet::Private::filterAccount(const AccountPtr &account)
{
QString accountPath = account->objectPath();
Q_ASSERT(wrappers.contains(accountPath));
AccountWrapper *wrapper = wrappers[accountPath];
/* account changed, let's check if it matches filter */
if (accountMatchFilter(wrapper)) {
if (!accounts.contains(account->objectPath())) {
accounts.insert(account->objectPath(), account);
if (ready) {
emit parent->accountAdded(account);
}
}
} else {
if (accounts.contains(account->objectPath())) {
accounts.remove(account->objectPath());
if (ready) {
emit parent->accountRemoved(account);
}
}
}
}
bool AccountSet::Private::accountMatchFilter(AccountWrapper *wrapper)
{
if (!filter) {
return true;
}
return filter->matches(wrapper->account());
}
AccountSet::Private::AccountWrapper::AccountWrapper(
const AccountPtr &account, QObject *parent)
: QObject(parent),
mAccount(account)
{
connect(account.data(),
SIGNAL(removed()),
SLOT(onAccountRemoved()));
connect(account.data(),
SIGNAL(propertyChanged(QString)),
SLOT(onAccountPropertyChanged(QString)));
connect(account.data(),
SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
SLOT(onAccountCapalitiesChanged(Tp::ConnectionCapabilities)));
}
AccountSet::Private::AccountWrapper::~AccountWrapper()
{
}
void AccountSet::Private::AccountWrapper::onAccountRemoved()
{
emit accountRemoved(mAccount);
}
void AccountSet::Private::AccountWrapper::onAccountPropertyChanged(
const QString &propertyName)
{
emit accountPropertyChanged(mAccount, propertyName);
}
void AccountSet::Private::AccountWrapper::onAccountCapalitiesChanged(
const ConnectionCapabilities &caps)
{
emit accountCapabilitiesChanged(mAccount, caps);
}
/**
* \class AccountSet
* \ingroup clientaccount
* \headerfile TelepathyQt/account-set.h
*
* \brief The AccountSet class represents a set of Telepathy accounts
* filtered by a given criteria.
*
* AccountSet is automatically updated whenever accounts that match the given
* criteria are added, removed or updated.
*
* \section account_set_usage_sec Usage
*
* \subsection account_set_create_sec Creating an AccountSet object
*
* The easiest way to create AccountSet objects is through AccountManager. One
* can just use the AccountManager convenience methods such as
* AccountManager::validAccounts() to get a set of account objects
* representing valid accounts.
*
* For example:
*
* \code
*
* class MyClass : public QObject
* {
* QOBJECT
*
* public:
* MyClass(QObject *parent = 0);
* ~MyClass() { }
*
* private Q_SLOTS:
* void onAccountManagerReady(Tp::PendingOperation *);
* void onValidAccountAdded(const Tp::AccountPtr &);
* void onValidAccountRemoved(const Tp::AccountPtr &);
*
* private:
* AccountManagerPtr am;
* AccountSetPtr validAccountsSet;
* };
*
* MyClass::MyClass(QObject *parent)
* : QObject(parent)
* am(AccountManager::create())
* {
* connect(am->becomeReady(),
* SIGNAL(finished(Tp::PendingOperation*)),
* SLOT(onAccountManagerReady(Tp::PendingOperation*)));
* }
*
* void MyClass::onAccountManagerReady(Tp::PendingOperation *op)
* {
* if (op->isError()) {
* qWarning() << "Account manager cannot become ready:" <<
* op->errorName() << "-" << op->errorMessage();
* return;
* }
*
* validAccountsSet = am->validAccounts();
* connect(validAccountsSet.data(),
* SIGNAL(accountAdded(const Tp::AccountPtr &)),
* SLOT(onValidAccountAdded(const Tp::AccountPtr &)));
* connect(validAccountsSet.data(),
* SIGNAL(accountRemoved(const Tp::AccountPtr &)),
* SLOT(onValidAccountRemoved(const Tp::AccountPtr &)));
*
* QList accounts = validAccountsSet->accounts();
* // do something with accounts
* }
*
* void MyClass::onValidAccountAdded(const Tp::AccountPtr &account)
* {
* // do something with account
* }
*
* void MyClass::onValidAccountRemoved(const Tp::AccountPtr &account)
* {
* // do something with account
* }
*
* \endcode
*
* You can also define your own filter using AccountManager::filterAccounts:
*
* \code
*
* void MyClass::onAccountManagerReady(Tp::PendingOperation *op)
* {
* ...
*
* AccountPropertyFilterPtr filter = AccountPropertyFilter::create();
* filter->addProperty(QLatin1String("protocolName"), QLatin1String("jabber"));
* filter->addProperty(QLatin1String("enabled"), true);
*
* AccountSetPtr filteredAccountSet = am->filterAccounts(filter);
* // connect to AccountSet::accountAdded/accountRemoved signals
* QList accounts = filteredAccountSet->accounts();
* // do something with accounts
*
* ....
* }
*
* \endcode
*
* Note that for AccountSet to property work with AccountCapabilityFilter
* objects, the feature Account::FeatureCapabilities need to be enabled in all
* accounts return by the AccountManager passed as param in the constructor.
* The easiest way to do this is to enable AccountManager feature
* AccountManager::FeatureFilterByCapabilities.
*
* AccountSet can also be instantiated directly, but when doing it,
* the AccountManager object passed as param in the constructor must be ready
* for AccountSet properly work.
*/
/**
* Construct a new AccountSet object.
*
* \param accountManager An account manager object used to filter accounts.
* The account manager object must be ready.
* \param filter The desired filter.
*/
AccountSet::AccountSet(const AccountManagerPtr &accountManager,
const AccountFilterConstPtr &filter)
: Object(),
mPriv(new Private(this, accountManager, filter))
{
}
/**
* Construct a new AccountSet object.
*
* The \a filter must contain Account property names and values as map items.
*
* \param accountManager An account manager object used to filter accounts.
* The account manager object must be ready.
* \param filter The desired filter.
*/
AccountSet::AccountSet(const AccountManagerPtr &accountManager,
const QVariantMap &filter)
: Object(),
mPriv(new Private(this, accountManager, filter))
{
}
/**
* Class destructor.
*/
AccountSet::~AccountSet()
{
delete mPriv;
}
/**
* Return the account manager object used to filter accounts.
*
* \return A pointer to the AccountManager object.
*/
AccountManagerPtr AccountSet::accountManager() const
{
return mPriv->accountManager;
}
/**
* Return the filter used to filter accounts.
*
* \return A read-only pointer the AccountFilter object.
*/
AccountFilterConstPtr AccountSet::filter() const
{
return mPriv->filter;
}
/**
* Return a list of account objects that match filter.
*
* Change notification is via the accountAdded() and accountRemoved() signals.
*
* \return A list of pointers to Account objects.
* \sa accountAdded(), accountRemoved()
*/
QList AccountSet::accounts() const
{
return mPriv->accounts.values();
}
/**
* \fn void AccountSet::accountAdded(const Tp::AccountPtr &account)
*
* Emitted whenever an account that matches filter is added to
* this set.
*
* \param account The account that was added to this set.
* \sa accounts()
*/
/**
* \fn void AccountSet::accountRemoved(const Tp::AccountPtr &account)
*
* Emitted whenever an account that matches filter is removed
* from this set.
*
* \param account The account that was removed from this set.
* \sa accounts()
*/
void AccountSet::onNewAccount(const AccountPtr &account)
{
mPriv->insertAccount(account);
}
void AccountSet::onAccountRemoved(const AccountPtr &account)
{
mPriv->removeAccount(account);
}
void AccountSet::onAccountChanged(const AccountPtr &account)
{
mPriv->filterAccount(account);
}
} // Tp