1 /**
2 * This file is part of TelepathyQt
3 *
4 * @copyright Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
5 * @copyright Copyright (C) 2010 Nokia Corporation
6 * @license LGPL 2.1
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <TelepathyQt/AccountSet>
24 #include "TelepathyQt/account-set-internal.h"
25
26 #include "TelepathyQt/_gen/account-set.moc.hpp"
27 #include "TelepathyQt/_gen/account-set-internal.moc.hpp"
28
29 #include "TelepathyQt/debug-internal.h"
30
31 #include <TelepathyQt/Account>
32 #include <TelepathyQt/AccountFilter>
33 #include <TelepathyQt/AccountManager>
34 #include <TelepathyQt/ConnectionCapabilities>
35 #include <TelepathyQt/ConnectionManager>
36
37 namespace Tp
38 {
39
Private(AccountSet * parent,const AccountManagerPtr & accountManager,const AccountFilterConstPtr & filter)40 AccountSet::Private::Private(AccountSet *parent,
41 const AccountManagerPtr &accountManager,
42 const AccountFilterConstPtr &filter)
43 : parent(parent),
44 accountManager(accountManager),
45 filter(filter),
46 ready(false)
47 {
48 init();
49 }
50
Private(AccountSet * parent,const AccountManagerPtr & accountManager,const QVariantMap & filterMap)51 AccountSet::Private::Private(AccountSet *parent,
52 const AccountManagerPtr &accountManager,
53 const QVariantMap &filterMap)
54 : parent(parent),
55 accountManager(accountManager),
56 ready(false)
57 {
58 AccountPropertyFilterPtr propertyFilter = AccountPropertyFilter::create();
59 for (QVariantMap::const_iterator i = filterMap.constBegin();
60 i != filterMap.constEnd(); ++i) {
61 propertyFilter->addProperty(i.key(), i.value());
62 }
63 filter = AccountFilterPtr::dynamicCast(propertyFilter);
64 init();
65 }
66
init()67 void AccountSet::Private::init()
68 {
69 if (filter->isValid()) {
70 connectSignals();
71 insertAccounts();
72 ready = true;
73 }
74 }
75
connectSignals()76 void AccountSet::Private::connectSignals()
77 {
78 parent->connect(accountManager.data(),
79 SIGNAL(newAccount(Tp::AccountPtr)),
80 SLOT(onNewAccount(Tp::AccountPtr)));
81 }
82
insertAccounts()83 void AccountSet::Private::insertAccounts()
84 {
85 foreach (const Tp::AccountPtr &account, accountManager->allAccounts()) {
86 insertAccount(account);
87 }
88 }
89
insertAccount(const Tp::AccountPtr & account)90 void AccountSet::Private::insertAccount(const Tp::AccountPtr &account)
91 {
92 QString accountPath = account->objectPath();
93 Q_ASSERT(!wrappers.contains(accountPath));
94 wrapAccount(account);
95 filterAccount(account);
96 }
97
removeAccount(const Tp::AccountPtr & account)98 void AccountSet::Private::removeAccount(const Tp::AccountPtr &account)
99 {
100 QString accountPath = account->objectPath();
101 Q_ASSERT(wrappers.contains(accountPath));
102 accounts.remove(accountPath);
103
104 AccountWrapper *wrapper = wrappers.take(accountPath);
105 Q_ASSERT(wrapper->disconnect(parent));
106 wrapper->deleteLater();
107
108 emit parent->accountRemoved(account);
109 }
110
wrapAccount(const AccountPtr & account)111 void AccountSet::Private::wrapAccount(const AccountPtr &account)
112 {
113 AccountWrapper *wrapper = new AccountWrapper(account, parent);
114 parent->connect(wrapper,
115 SIGNAL(accountRemoved(Tp::AccountPtr)),
116 SLOT(onAccountRemoved(Tp::AccountPtr)));
117 parent->connect(wrapper,
118 SIGNAL(accountPropertyChanged(Tp::AccountPtr,QString)),
119 SLOT(onAccountChanged(Tp::AccountPtr)));
120 parent->connect(wrapper,
121 SIGNAL(accountCapabilitiesChanged(Tp::AccountPtr,Tp::ConnectionCapabilities)),
122 SLOT(onAccountChanged(Tp::AccountPtr)));
123 wrappers.insert(account->objectPath(), wrapper);
124 }
125
filterAccount(const AccountPtr & account)126 void AccountSet::Private::filterAccount(const AccountPtr &account)
127 {
128 QString accountPath = account->objectPath();
129 Q_ASSERT(wrappers.contains(accountPath));
130 AccountWrapper *wrapper = wrappers[accountPath];
131
132 /* account changed, let's check if it matches filter */
133 if (accountMatchFilter(wrapper)) {
134 if (!accounts.contains(account->objectPath())) {
135 accounts.insert(account->objectPath(), account);
136 if (ready) {
137 emit parent->accountAdded(account);
138 }
139 }
140 } else {
141 if (accounts.contains(account->objectPath())) {
142 accounts.remove(account->objectPath());
143 if (ready) {
144 emit parent->accountRemoved(account);
145 }
146 }
147 }
148 }
149
accountMatchFilter(AccountWrapper * wrapper)150 bool AccountSet::Private::accountMatchFilter(AccountWrapper *wrapper)
151 {
152 if (!filter) {
153 return true;
154 }
155
156 return filter->matches(wrapper->account());
157 }
158
AccountWrapper(const AccountPtr & account,QObject * parent)159 AccountSet::Private::AccountWrapper::AccountWrapper(
160 const AccountPtr &account, QObject *parent)
161 : QObject(parent),
162 mAccount(account)
163 {
164 connect(account.data(),
165 SIGNAL(removed()),
166 SLOT(onAccountRemoved()));
167 connect(account.data(),
168 SIGNAL(propertyChanged(QString)),
169 SLOT(onAccountPropertyChanged(QString)));
170 connect(account.data(),
171 SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
172 SLOT(onAccountCapalitiesChanged(Tp::ConnectionCapabilities)));
173 }
174
~AccountWrapper()175 AccountSet::Private::AccountWrapper::~AccountWrapper()
176 {
177 }
178
onAccountRemoved()179 void AccountSet::Private::AccountWrapper::onAccountRemoved()
180 {
181 emit accountRemoved(mAccount);
182 }
183
onAccountPropertyChanged(const QString & propertyName)184 void AccountSet::Private::AccountWrapper::onAccountPropertyChanged(
185 const QString &propertyName)
186 {
187 emit accountPropertyChanged(mAccount, propertyName);
188 }
189
onAccountCapalitiesChanged(const ConnectionCapabilities & caps)190 void AccountSet::Private::AccountWrapper::onAccountCapalitiesChanged(
191 const ConnectionCapabilities &caps)
192 {
193 emit accountCapabilitiesChanged(mAccount, caps);
194 }
195
196 /**
197 * \class AccountSet
198 * \ingroup clientaccount
199 * \headerfile TelepathyQt/account-set.h <TelepathyQt/AccountSet>
200 *
201 * \brief The AccountSet class represents a set of Telepathy accounts
202 * filtered by a given criteria.
203 *
204 * AccountSet is automatically updated whenever accounts that match the given
205 * criteria are added, removed or updated.
206 *
207 * \section account_set_usage_sec Usage
208 *
209 * \subsection account_set_create_sec Creating an AccountSet object
210 *
211 * The easiest way to create AccountSet objects is through AccountManager. One
212 * can just use the AccountManager convenience methods such as
213 * AccountManager::validAccounts() to get a set of account objects
214 * representing valid accounts.
215 *
216 * For example:
217 *
218 * \code
219 *
220 * class MyClass : public QObject
221 * {
222 * QOBJECT
223 *
224 * public:
225 * MyClass(QObject *parent = 0);
226 * ~MyClass() { }
227 *
228 * private Q_SLOTS:
229 * void onAccountManagerReady(Tp::PendingOperation *);
230 * void onValidAccountAdded(const Tp::AccountPtr &);
231 * void onValidAccountRemoved(const Tp::AccountPtr &);
232 *
233 * private:
234 * AccountManagerPtr am;
235 * AccountSetPtr validAccountsSet;
236 * };
237 *
238 * MyClass::MyClass(QObject *parent)
239 * : QObject(parent)
240 * am(AccountManager::create())
241 * {
242 * connect(am->becomeReady(),
243 * SIGNAL(finished(Tp::PendingOperation*)),
244 * SLOT(onAccountManagerReady(Tp::PendingOperation*)));
245 * }
246 *
247 * void MyClass::onAccountManagerReady(Tp::PendingOperation *op)
248 * {
249 * if (op->isError()) {
250 * qWarning() << "Account manager cannot become ready:" <<
251 * op->errorName() << "-" << op->errorMessage();
252 * return;
253 * }
254 *
255 * validAccountsSet = am->validAccounts();
256 * connect(validAccountsSet.data(),
257 * SIGNAL(accountAdded(const Tp::AccountPtr &)),
258 * SLOT(onValidAccountAdded(const Tp::AccountPtr &)));
259 * connect(validAccountsSet.data(),
260 * SIGNAL(accountRemoved(const Tp::AccountPtr &)),
261 * SLOT(onValidAccountRemoved(const Tp::AccountPtr &)));
262 *
263 * QList<AccountPtr> accounts = validAccountsSet->accounts();
264 * // do something with accounts
265 * }
266 *
267 * void MyClass::onValidAccountAdded(const Tp::AccountPtr &account)
268 * {
269 * // do something with account
270 * }
271 *
272 * void MyClass::onValidAccountRemoved(const Tp::AccountPtr &account)
273 * {
274 * // do something with account
275 * }
276 *
277 * \endcode
278 *
279 * You can also define your own filter using AccountManager::filterAccounts:
280 *
281 * \code
282 *
283 * void MyClass::onAccountManagerReady(Tp::PendingOperation *op)
284 * {
285 * ...
286 *
287 * AccountPropertyFilterPtr filter = AccountPropertyFilter::create();
288 * filter->addProperty(QLatin1String("protocolName"), QLatin1String("jabber"));
289 * filter->addProperty(QLatin1String("enabled"), true);
290 *
291 * AccountSetPtr filteredAccountSet = am->filterAccounts(filter);
292 * // connect to AccountSet::accountAdded/accountRemoved signals
293 * QList<AccountPtr> accounts = filteredAccountSet->accounts();
294 * // do something with accounts
295 *
296 * ....
297 * }
298 *
299 * \endcode
300 *
301 * Note that for AccountSet to property work with AccountCapabilityFilter
302 * objects, the feature Account::FeatureCapabilities need to be enabled in all
303 * accounts return by the AccountManager passed as param in the constructor.
304 * The easiest way to do this is to enable AccountManager feature
305 * AccountManager::FeatureFilterByCapabilities.
306 *
307 * AccountSet can also be instantiated directly, but when doing it,
308 * the AccountManager object passed as param in the constructor must be ready
309 * for AccountSet properly work.
310 */
311
312 /**
313 * Construct a new AccountSet object.
314 *
315 * \param accountManager An account manager object used to filter accounts.
316 * The account manager object must be ready.
317 * \param filter The desired filter.
318 */
AccountSet(const AccountManagerPtr & accountManager,const AccountFilterConstPtr & filter)319 AccountSet::AccountSet(const AccountManagerPtr &accountManager,
320 const AccountFilterConstPtr &filter)
321 : Object(),
322 mPriv(new Private(this, accountManager, filter))
323 {
324 }
325
326 /**
327 * Construct a new AccountSet object.
328 *
329 * The \a filter must contain Account property names and values as map items.
330 *
331 * \param accountManager An account manager object used to filter accounts.
332 * The account manager object must be ready.
333 * \param filter The desired filter.
334 */
AccountSet(const AccountManagerPtr & accountManager,const QVariantMap & filter)335 AccountSet::AccountSet(const AccountManagerPtr &accountManager,
336 const QVariantMap &filter)
337 : Object(),
338 mPriv(new Private(this, accountManager, filter))
339 {
340 }
341
342 /**
343 * Class destructor.
344 */
~AccountSet()345 AccountSet::~AccountSet()
346 {
347 delete mPriv;
348 }
349
350 /**
351 * Return the account manager object used to filter accounts.
352 *
353 * \return A pointer to the AccountManager object.
354 */
accountManager() const355 AccountManagerPtr AccountSet::accountManager() const
356 {
357 return mPriv->accountManager;
358 }
359
360 /**
361 * Return the filter used to filter accounts.
362 *
363 * \return A read-only pointer the AccountFilter object.
364 */
filter() const365 AccountFilterConstPtr AccountSet::filter() const
366 {
367 return mPriv->filter;
368 }
369
370 /**
371 * Return a list of account objects that match filter.
372 *
373 * Change notification is via the accountAdded() and accountRemoved() signals.
374 *
375 * \return A list of pointers to Account objects.
376 * \sa accountAdded(), accountRemoved()
377 */
accounts() const378 QList<AccountPtr> AccountSet::accounts() const
379 {
380 return mPriv->accounts.values();
381 }
382
383 /**
384 * \fn void AccountSet::accountAdded(const Tp::AccountPtr &account)
385 *
386 * Emitted whenever an account that matches filter is added to
387 * this set.
388 *
389 * \param account The account that was added to this set.
390 * \sa accounts()
391 */
392
393 /**
394 * \fn void AccountSet::accountRemoved(const Tp::AccountPtr &account)
395 *
396 * Emitted whenever an account that matches filter is removed
397 * from this set.
398 *
399 * \param account The account that was removed from this set.
400 * \sa accounts()
401 */
402
onNewAccount(const AccountPtr & account)403 void AccountSet::onNewAccount(const AccountPtr &account)
404 {
405 mPriv->insertAccount(account);
406 }
407
onAccountRemoved(const AccountPtr & account)408 void AccountSet::onAccountRemoved(const AccountPtr &account)
409 {
410 mPriv->removeAccount(account);
411 }
412
onAccountChanged(const AccountPtr & account)413 void AccountSet::onAccountChanged(const AccountPtr &account)
414 {
415 mPriv->filterAccount(account);
416 }
417
418 } // Tp
419