1 | /* |
2 | Copyright (c) 2006 Till Adam <adam@kde.org> |
3 | Copyright (c) 2007 Volker Krause <vkrause@kde.org> |
4 | Copyright (c) 2007 Bruno Virlet <bruno.virlet@gmail.com> |
5 | Copyright (c) 2008 Kevin Krammer <kevin.krammer@gmx.at> |
6 | |
7 | This library is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU Library General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or (at your |
10 | option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, but WITHOUT |
13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
15 | License for more details. |
16 | |
17 | You should have received a copy of the GNU Library General Public License |
18 | along with this library; see the file COPYING.LIB. If not, write to the |
19 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
20 | 02110-1301, USA. |
21 | */ |
22 | |
23 | #include "agentbase.h" |
24 | #include "agentbase_p.h" |
25 | |
26 | #include "agentmanager.h" |
27 | #include "changerecorder.h" |
28 | #include "controladaptor.h" |
29 | #include "dbusconnectionpool.h" |
30 | #include "itemfetchjob.h" |
31 | #include "kdepimlibs-version.h" |
32 | #include "monitor_p.h" |
33 | #include "servermanager_p.h" |
34 | #include "session.h" |
35 | #include "session_p.h" |
36 | #include "statusadaptor.h" |
37 | |
38 | #include <kaboutdata.h> |
39 | #include <kcmdlineargs.h> |
40 | #include <kdebug.h> |
41 | #include <kglobal.h> |
42 | #include <klocalizedstring.h> |
43 | #include <kstandarddirs.h> |
44 | |
45 | #include <Solid/PowerManagement> |
46 | |
47 | #include <QtCore/QDir> |
48 | #include <QtCore/QSettings> |
49 | #include <QtCore/QTimer> |
50 | #include <QtDBus/QtDBus> |
51 | #include <QApplication> |
52 | |
53 | #include <signal.h> |
54 | #include <stdlib.h> |
55 | #if defined __GLIBC__ |
56 | # include <malloc.h> // for dumping memory information |
57 | #endif |
58 | |
59 | //#define EXPERIMENTAL_INPROCESS_AGENTS 1 |
60 | |
61 | using namespace Akonadi; |
62 | |
63 | static AgentBase *sAgentBase = 0; |
64 | |
65 | AgentBase::Observer::Observer() |
66 | { |
67 | } |
68 | |
69 | AgentBase::Observer::~Observer() |
70 | { |
71 | } |
72 | |
73 | void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection) |
74 | { |
75 | Q_UNUSED(item); |
76 | Q_UNUSED(collection); |
77 | if (sAgentBase != 0) { |
78 | sAgentBase->d_ptr->changeProcessed(); |
79 | } |
80 | } |
81 | |
82 | void AgentBase::Observer::itemChanged(const Item &item, const QSet<QByteArray> &partIdentifiers) |
83 | { |
84 | Q_UNUSED(item); |
85 | Q_UNUSED(partIdentifiers); |
86 | if (sAgentBase != 0) { |
87 | sAgentBase->d_ptr->changeProcessed(); |
88 | } |
89 | } |
90 | |
91 | void AgentBase::Observer::itemRemoved(const Item &item) |
92 | { |
93 | Q_UNUSED(item); |
94 | if (sAgentBase != 0) { |
95 | sAgentBase->d_ptr->changeProcessed(); |
96 | } |
97 | } |
98 | |
99 | void AgentBase::Observer::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) |
100 | { |
101 | Q_UNUSED(collection); |
102 | Q_UNUSED(parent); |
103 | if (sAgentBase != 0) { |
104 | sAgentBase->d_ptr->changeProcessed(); |
105 | } |
106 | } |
107 | |
108 | void AgentBase::Observer::collectionChanged(const Collection &collection) |
109 | { |
110 | Q_UNUSED(collection); |
111 | if (sAgentBase != 0) { |
112 | sAgentBase->d_ptr->changeProcessed(); |
113 | } |
114 | } |
115 | |
116 | void AgentBase::Observer::collectionRemoved(const Collection &collection) |
117 | { |
118 | Q_UNUSED(collection); |
119 | if (sAgentBase != 0) { |
120 | sAgentBase->d_ptr->changeProcessed(); |
121 | } |
122 | } |
123 | |
124 | void AgentBase::ObserverV2::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest) |
125 | { |
126 | Q_UNUSED(item); |
127 | Q_UNUSED(source); |
128 | Q_UNUSED(dest); |
129 | if (sAgentBase != 0) { |
130 | sAgentBase->d_ptr->changeProcessed(); |
131 | } |
132 | } |
133 | |
134 | void AgentBase::ObserverV2::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) |
135 | { |
136 | Q_UNUSED(item); |
137 | Q_UNUSED(collection); |
138 | if (sAgentBase != 0) { |
139 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
140 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), |
141 | sAgentBase->d_ptr, SLOT(itemLinked(Akonadi::Item,Akonadi::Collection))); |
142 | sAgentBase->d_ptr->changeProcessed(); |
143 | } |
144 | } |
145 | |
146 | void AgentBase::ObserverV2::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) |
147 | { |
148 | Q_UNUSED(item); |
149 | Q_UNUSED(collection); |
150 | if (sAgentBase != 0) { |
151 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
152 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), |
153 | sAgentBase->d_ptr, SLOT(itemUnlinked(Akonadi::Item,Akonadi::Collection))); |
154 | sAgentBase->d_ptr->changeProcessed(); |
155 | } |
156 | } |
157 | |
158 | void AgentBase::ObserverV2::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest) |
159 | { |
160 | Q_UNUSED(collection); |
161 | Q_UNUSED(source); |
162 | Q_UNUSED(dest); |
163 | if (sAgentBase != 0) { |
164 | sAgentBase->d_ptr->changeProcessed(); |
165 | } |
166 | } |
167 | |
168 | void AgentBase::ObserverV2::collectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes) |
169 | { |
170 | Q_UNUSED(changedAttributes); |
171 | collectionChanged(collection); |
172 | } |
173 | |
174 | void AgentBase::ObserverV3::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags) |
175 | { |
176 | Q_UNUSED(items); |
177 | Q_UNUSED(addedFlags); |
178 | Q_UNUSED(removedFlags); |
179 | |
180 | if (sAgentBase != 0) { |
181 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
182 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>)), |
183 | sAgentBase->d_ptr, SLOT(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>))); |
184 | sAgentBase->d_ptr->changeProcessed(); |
185 | } |
186 | } |
187 | |
188 | void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection) |
189 | { |
190 | Q_UNUSED(items); |
191 | Q_UNUSED(sourceCollection); |
192 | Q_UNUSED(destinationCollection); |
193 | |
194 | if (sAgentBase != 0) { |
195 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
196 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection)), |
197 | sAgentBase->d_ptr, SLOT(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))); |
198 | sAgentBase->d_ptr->changeProcessed(); |
199 | } |
200 | } |
201 | |
202 | void AgentBase::ObserverV3::itemsRemoved(const Akonadi::Item::List &items) |
203 | { |
204 | Q_UNUSED(items); |
205 | |
206 | if (sAgentBase != 0) { |
207 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
208 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsRemoved(Akonadi::Item::List)), |
209 | sAgentBase->d_ptr, SLOT(itemsRemoved(Akonadi::Item::List))); |
210 | sAgentBase->d_ptr->changeProcessed(); |
211 | } |
212 | } |
213 | |
214 | void AgentBase::ObserverV3::itemsLinked(const Akonadi::Item::List &items, const Collection &collection) |
215 | { |
216 | Q_UNUSED(items); |
217 | Q_UNUSED(collection); |
218 | |
219 | if (sAgentBase != 0) { |
220 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
221 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection)), |
222 | sAgentBase->d_ptr, SLOT(itemsLinked(Akonadi::Item::List,Akonadi::Collection))); |
223 | sAgentBase->d_ptr->changeProcessed(); |
224 | } |
225 | } |
226 | |
227 | void AgentBase::ObserverV3::itemsUnlinked(const Akonadi::Item::List &items, const Collection &collection) |
228 | { |
229 | Q_UNUSED(items); |
230 | Q_UNUSED(collection) |
231 | |
232 | if (sAgentBase != 0) { |
233 | // not implementation, let's disconnect the signal to enable optimizations in Monitor |
234 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection)), |
235 | sAgentBase->d_ptr, SLOT(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))); |
236 | sAgentBase->d_ptr->changeProcessed(); |
237 | } |
238 | } |
239 | |
240 | void AgentBase::ObserverV4::tagAdded(const Tag &tag) |
241 | { |
242 | Q_UNUSED(tag); |
243 | |
244 | if (sAgentBase != 0) { |
245 | // not implementation, let's disconnect the signal to enable optimization in Monitor |
246 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(tagAdded(Akonadi::Tag)), |
247 | sAgentBase->d_ptr, SLOT(tagAdded(Akonadi::Tag))); |
248 | sAgentBase->d_ptr->changeProcessed(); |
249 | } |
250 | } |
251 | |
252 | void AgentBase::ObserverV4::tagChanged(const Tag &tag) |
253 | { |
254 | Q_UNUSED(tag); |
255 | |
256 | if (sAgentBase != 0) { |
257 | // not implementation, let's disconnect the signal to enable optimization in Monitor |
258 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(tagChanged(Akonadi::Tag)), |
259 | sAgentBase->d_ptr, SLOT(tagChanged(Akonadi::Tag))); |
260 | sAgentBase->d_ptr->changeProcessed(); |
261 | } |
262 | } |
263 | |
264 | void AgentBase::ObserverV4::tagRemoved(const Tag &tag) |
265 | { |
266 | Q_UNUSED(tag); |
267 | |
268 | if (sAgentBase != 0) { |
269 | // not implementation, let's disconnect the signal to enable optimization in Monitor |
270 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(tagRemoved(Akonadi::Tag)), |
271 | sAgentBase->d_ptr, SLOT(tagRemoved(Akonadi::Tag))); |
272 | sAgentBase->d_ptr->changeProcessed(); |
273 | } |
274 | } |
275 | |
276 | void AgentBase::ObserverV4::itemsTagsChanged(const Item::List &items, const QSet<Tag> &addedTags, const QSet<Tag> &removedTags) |
277 | { |
278 | Q_UNUSED(items); |
279 | Q_UNUSED(addedTags); |
280 | Q_UNUSED(removedTags); |
281 | |
282 | if (sAgentBase != 0) { |
283 | // not implementation, let's disconnect the signal to enable optimization in Monitor |
284 | QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>)), |
285 | sAgentBase->d_ptr, SLOT(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>))); |
286 | sAgentBase->d_ptr->changeProcessed(); |
287 | } |
288 | } |
289 | |
290 | //@cond PRIVATE |
291 | |
292 | AgentBasePrivate::AgentBasePrivate(AgentBase *parent) |
293 | : q_ptr(parent) |
294 | , mDBusConnection(QString()) |
295 | , mStatusCode(AgentBase::Idle) |
296 | , mProgress(0) |
297 | , mNeedsNetwork(false) |
298 | , mOnline(false) |
299 | , mDesiredOnlineState(false) |
300 | , mSettings(0) |
301 | , mChangeRecorder(0) |
302 | , mTracer(0) |
303 | , mObserver(0) |
304 | , mTemporaryOfflineTimer(0) |
305 | { |
306 | Internal::setClientType(Internal::Agent); |
307 | } |
308 | |
309 | AgentBasePrivate::~AgentBasePrivate() |
310 | { |
311 | mChangeRecorder->setConfig(0); |
312 | delete mSettings; |
313 | } |
314 | |
315 | void AgentBasePrivate::init() |
316 | { |
317 | Q_Q(AgentBase); |
318 | |
319 | /** |
320 | * Create a default session for this process. |
321 | */ |
322 | SessionPrivate::createDefaultSession(mId.toLatin1()); |
323 | |
324 | if (QThread::currentThread() != QCoreApplication::instance()->thread()) { |
325 | mDBusConnection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, q->identifier()); |
326 | Q_ASSERT(mDBusConnection.isConnected()); |
327 | } |
328 | |
329 | mTracer = new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), |
330 | QLatin1String("/tracing" ), |
331 | DBusConnectionPool::threadConnection(), q); |
332 | |
333 | new Akonadi__ControlAdaptor(q); |
334 | new Akonadi__StatusAdaptor(q); |
335 | if (!DBusConnectionPool::threadConnection().registerObject(QLatin1String("/" ), q, QDBusConnection::ExportAdaptors)) { |
336 | q->error(i18n("Unable to register object at dbus: %1" , DBusConnectionPool::threadConnection().lastError().message())); |
337 | } |
338 | |
339 | mSettings = new QSettings(QString::fromLatin1("%1/agent_config_%2" ).arg(Internal::xdgSaveDir("config" ), mId), QSettings::IniFormat); |
340 | |
341 | mChangeRecorder = new ChangeRecorder(q); |
342 | mChangeRecorder->ignoreSession(Session::defaultSession()); |
343 | mChangeRecorder->itemFetchScope().setCacheOnly(true); |
344 | mChangeRecorder->setConfig(mSettings); |
345 | |
346 | mDesiredOnlineState = mSettings->value(QLatin1String("Agent/DesiredOnlineState" ), true).toBool(); |
347 | mOnline = mDesiredOnlineState; |
348 | |
349 | // reinitialize the status message now that online state is available |
350 | mStatusMessage = defaultReadyMessage(); |
351 | |
352 | mName = mSettings->value(QLatin1String("Agent/Name" )).toString(); |
353 | if (mName.isEmpty()) { |
354 | mName = mSettings->value(QLatin1String("Resource/Name" )).toString(); |
355 | if (!mName.isEmpty()) { |
356 | mSettings->remove(QLatin1String("Resource/Name" )); |
357 | mSettings->setValue(QLatin1String("Agent/Name" ), mName); |
358 | } |
359 | } |
360 | |
361 | connect(mChangeRecorder, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), |
362 | SLOT(itemAdded(Akonadi::Item,Akonadi::Collection))); |
363 | connect(mChangeRecorder, SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)), |
364 | SLOT(itemChanged(Akonadi::Item,QSet<QByteArray>))); |
365 | connect(mChangeRecorder, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), |
366 | SLOT(collectionAdded(Akonadi::Collection,Akonadi::Collection))); |
367 | connect(mChangeRecorder, SIGNAL(collectionChanged(Akonadi::Collection)), |
368 | SLOT(collectionChanged(Akonadi::Collection))); |
369 | connect(mChangeRecorder, SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), |
370 | SLOT(collectionChanged(Akonadi::Collection,QSet<QByteArray>))); |
371 | connect(mChangeRecorder, SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)), |
372 | SLOT(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); |
373 | connect(mChangeRecorder, SIGNAL(collectionRemoved(Akonadi::Collection)), |
374 | SLOT(collectionRemoved(Akonadi::Collection))); |
375 | connect(mChangeRecorder, SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection)), |
376 | SLOT(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))); |
377 | connect(mChangeRecorder, SIGNAL(collectionUnsubscribed(Akonadi::Collection)), |
378 | SLOT(collectionUnsubscribed(Akonadi::Collection))); |
379 | |
380 | connect(q, SIGNAL(status(int,QString)), q, SLOT(slotStatus(int,QString))); |
381 | connect(q, SIGNAL(percent(int)), q, SLOT(slotPercent(int))); |
382 | connect(q, SIGNAL(warning(QString)), q, SLOT(slotWarning(QString))); |
383 | connect(q, SIGNAL(error(QString)), q, SLOT(slotError(QString))); |
384 | |
385 | connect(Solid::PowerManagement::notifier(), SIGNAL(resumingFromSuspend()), q, SLOT(slotResumedFromSuspend())); |
386 | |
387 | // Use reference counting to allow agents to finish internal jobs when the |
388 | // agent is stopped. |
389 | KGlobal::ref(); |
390 | if (QThread::currentThread() == QCoreApplication::instance()->thread()) { |
391 | KGlobal::setAllowQuit(true); |
392 | } |
393 | |
394 | // disable session management |
395 | if (KApplication::kApplication()) { |
396 | KApplication::kApplication()->disableSessionManagement(); |
397 | } |
398 | |
399 | mResourceTypeName = AgentManager::self()->instance(mId).type().name(); |
400 | setProgramName(); |
401 | |
402 | QTimer::singleShot(0, q, SLOT(delayedInit())); |
403 | } |
404 | |
405 | void AgentBasePrivate::delayedInit() |
406 | { |
407 | Q_Q(AgentBase); |
408 | |
409 | const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId); |
410 | if (!DBusConnectionPool::threadConnection().registerService(serviceId)) { |
411 | kFatal() << "Unable to register service" << serviceId << "at dbus:" << DBusConnectionPool::threadConnection().lastError().message(); |
412 | } |
413 | q->setOnlineInternal(mDesiredOnlineState); |
414 | |
415 | DBusConnectionPool::threadConnection().registerObject(QLatin1String("/Debug" ), this, QDBusConnection::ExportScriptableSlots); |
416 | } |
417 | |
418 | void AgentBasePrivate::setProgramName() |
419 | { |
420 | // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras) |
421 | QString programName = mResourceTypeName; |
422 | if (!mName.isEmpty()) { |
423 | programName = i18nc("Name and type of Akonadi resource" , "%1 of type %2" , mName, mResourceTypeName) ; |
424 | } |
425 | const_cast<KAboutData *>(KGlobal::mainComponent().aboutData())->setProgramName(ki18n(programName.toUtf8())); |
426 | } |
427 | |
428 | void AgentBasePrivate::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) |
429 | { |
430 | if (mObserver != 0) { |
431 | mObserver->itemAdded(item, collection); |
432 | } |
433 | } |
434 | |
435 | void AgentBasePrivate::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers) |
436 | { |
437 | if (mObserver != 0) { |
438 | mObserver->itemChanged(item, partIdentifiers); |
439 | } |
440 | } |
441 | |
442 | void AgentBasePrivate::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest) |
443 | { |
444 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
445 | if (mObserver) { |
446 | // inter-resource moves, requires we know which resources the source and destination are in though |
447 | if (!source.resource().isEmpty() && !dest.resource().isEmpty()) { |
448 | if (source.resource() != dest.resource()) { |
449 | if (source.resource() == q_ptr->identifier()) { // moved away from us |
450 | Akonadi::Item i(item); |
451 | i.setParentCollection(source); |
452 | mObserver->itemRemoved(i); |
453 | } else if (dest.resource() == q_ptr->identifier()) { // moved to us |
454 | mObserver->itemAdded(item, dest); |
455 | } else if (observer2) { |
456 | observer2->itemMoved(item, source, dest); |
457 | } else { |
458 | // not for us, not sure if we should get here at all |
459 | changeProcessed(); |
460 | } |
461 | return; |
462 | } |
463 | } |
464 | // intra-resource move |
465 | if (observer2) { |
466 | observer2->itemMoved(item, source, dest); |
467 | } else { |
468 | // ### we cannot just call itemRemoved here as this will already trigger changeProcessed() |
469 | // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway |
470 | // without using ObserverV2 |
471 | mObserver->itemAdded(item, dest); |
472 | // mObserver->itemRemoved( item ); |
473 | } |
474 | } |
475 | } |
476 | |
477 | void AgentBasePrivate::itemRemoved(const Akonadi::Item &item) |
478 | { |
479 | if (mObserver != 0) { |
480 | mObserver->itemRemoved(item); |
481 | } |
482 | } |
483 | |
484 | void AgentBasePrivate::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) |
485 | { |
486 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
487 | if (observer2) { |
488 | observer2->itemLinked(item, collection); |
489 | } else { |
490 | changeProcessed(); |
491 | } |
492 | } |
493 | |
494 | void AgentBasePrivate::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) |
495 | { |
496 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
497 | if (observer2) { |
498 | observer2->itemUnlinked(item, collection); |
499 | } else { |
500 | changeProcessed(); |
501 | } |
502 | } |
503 | |
504 | void AgentBasePrivate::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags) |
505 | { |
506 | AgentBase::ObserverV3 *observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver); |
507 | if (observer3) { |
508 | observer3->itemsFlagsChanged(items, addedFlags, removedFlags); |
509 | } else { |
510 | Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available" ); |
511 | } |
512 | } |
513 | |
514 | void AgentBasePrivate::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination) |
515 | { |
516 | AgentBase::ObserverV3 *observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver); |
517 | if (observer3) { |
518 | observer3->itemsMoved(items, source, destination); |
519 | } else { |
520 | Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available" ); |
521 | } |
522 | } |
523 | |
524 | void AgentBasePrivate::itemsRemoved(const Akonadi::Item::List &items) |
525 | { |
526 | AgentBase::ObserverV3 *observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver); |
527 | if (observer3) { |
528 | observer3->itemsRemoved(items); |
529 | } else { |
530 | Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available" ); |
531 | } |
532 | } |
533 | |
534 | void AgentBasePrivate::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) |
535 | { |
536 | if (!mObserver) { |
537 | changeProcessed(); |
538 | return; |
539 | } |
540 | |
541 | AgentBase::ObserverV3 *observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver); |
542 | if (observer3) { |
543 | observer3->itemsLinked(items, collection); |
544 | } else { |
545 | Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available" ); |
546 | } |
547 | } |
548 | |
549 | void AgentBasePrivate::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) |
550 | { |
551 | if (!mObserver) { |
552 | return; |
553 | } |
554 | |
555 | AgentBase::ObserverV3 *observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver); |
556 | if (observer3) { |
557 | observer3->itemsUnlinked(items, collection); |
558 | } else { |
559 | Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available" ); |
560 | } |
561 | } |
562 | |
563 | void AgentBasePrivate::tagAdded(const Akonadi::Tag &tag) |
564 | { |
565 | if (!mObserver) { |
566 | return; |
567 | } |
568 | |
569 | AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver); |
570 | if (observer4) { |
571 | observer4->tagAdded(tag); |
572 | } else { |
573 | changeProcessed(); |
574 | } |
575 | } |
576 | |
577 | void AgentBasePrivate::tagChanged(const Akonadi::Tag &tag) |
578 | { |
579 | if (!mObserver) { |
580 | return; |
581 | } |
582 | |
583 | AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver); |
584 | if (observer4) { |
585 | observer4->tagChanged(tag); |
586 | } else { |
587 | changeProcessed(); |
588 | } |
589 | } |
590 | |
591 | void AgentBasePrivate::tagRemoved(const Akonadi::Tag &tag) |
592 | { |
593 | if (!mObserver) { |
594 | return; |
595 | } |
596 | |
597 | AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver); |
598 | if (observer4) { |
599 | observer4->tagRemoved(tag);; |
600 | } else { |
601 | changeProcessed(); |
602 | } |
603 | } |
604 | |
605 | void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags) |
606 | { |
607 | if (!mObserver) { |
608 | return; |
609 | } |
610 | |
611 | AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver); |
612 | if (observer4) { |
613 | observer4->itemsTagsChanged(items, addedTags, removedTags); |
614 | } else { |
615 | changeProcessed(); |
616 | } |
617 | } |
618 | |
619 | void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) |
620 | { |
621 | if (mObserver != 0) { |
622 | mObserver->collectionAdded(collection, parent); |
623 | } |
624 | } |
625 | |
626 | void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection) |
627 | { |
628 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
629 | if (mObserver != 0 && observer2 == 0) { // For ObserverV2 we use the variant with the part identifiers |
630 | mObserver->collectionChanged(collection); |
631 | } |
632 | } |
633 | |
634 | void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes) |
635 | { |
636 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
637 | if (observer2 != 0) { |
638 | observer2->collectionChanged(collection, changedAttributes); |
639 | } |
640 | } |
641 | |
642 | void AgentBasePrivate::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest) |
643 | { |
644 | AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver); |
645 | if (observer2) { |
646 | observer2->collectionMoved(collection, source, dest); |
647 | } else if (mObserver) { |
648 | // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed() |
649 | // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway |
650 | // without using ObserverV2 |
651 | mObserver->collectionAdded(collection, dest); |
652 | } else { |
653 | changeProcessed(); |
654 | } |
655 | } |
656 | |
657 | void AgentBasePrivate::collectionRemoved(const Akonadi::Collection &collection) |
658 | { |
659 | if (mObserver != 0) { |
660 | mObserver->collectionRemoved(collection); |
661 | } |
662 | } |
663 | |
664 | void AgentBasePrivate::collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent) |
665 | { |
666 | Q_UNUSED(collection); |
667 | Q_UNUSED(parent); |
668 | changeProcessed(); |
669 | } |
670 | |
671 | void AgentBasePrivate::collectionUnsubscribed(const Akonadi::Collection &collection) |
672 | { |
673 | Q_UNUSED(collection); |
674 | changeProcessed(); |
675 | } |
676 | |
677 | void AgentBasePrivate::changeProcessed() |
678 | { |
679 | mChangeRecorder->changeProcessed(); |
680 | QTimer::singleShot(0, mChangeRecorder, SLOT(replayNext())); |
681 | } |
682 | |
683 | void AgentBasePrivate::slotStatus(int status, const QString &message) |
684 | { |
685 | mStatusMessage = message; |
686 | mStatusCode = 0; |
687 | |
688 | switch (status) { |
689 | case AgentBase::Idle: |
690 | if (mStatusMessage.isEmpty()) { |
691 | mStatusMessage = defaultReadyMessage(); |
692 | } |
693 | |
694 | mStatusCode = 0; |
695 | break; |
696 | case AgentBase::Running: |
697 | if (mStatusMessage.isEmpty()) { |
698 | mStatusMessage = defaultSyncingMessage(); |
699 | } |
700 | |
701 | mStatusCode = 1; |
702 | break; |
703 | case AgentBase::Broken: |
704 | if (mStatusMessage.isEmpty()) { |
705 | mStatusMessage = defaultErrorMessage(); |
706 | } |
707 | |
708 | mStatusCode = 2; |
709 | break; |
710 | |
711 | case AgentBase::NotConfigured: |
712 | if (mStatusMessage.isEmpty()) { |
713 | mStatusMessage = defaultUnconfiguredMessage(); |
714 | } |
715 | |
716 | mStatusCode = 3; |
717 | break; |
718 | |
719 | default: |
720 | Q_ASSERT(!"Unknown status passed" ); |
721 | break; |
722 | } |
723 | } |
724 | |
725 | void AgentBasePrivate::slotPercent(int progress) |
726 | { |
727 | mProgress = progress; |
728 | } |
729 | |
730 | void AgentBasePrivate::slotWarning(const QString &message) |
731 | { |
732 | mTracer->warning(QString::fromLatin1("AgentBase(%1)" ).arg(mId), message); |
733 | } |
734 | |
735 | void AgentBasePrivate::slotError(const QString &message) |
736 | { |
737 | mTracer->error(QString::fromLatin1("AgentBase(%1)" ).arg(mId), message); |
738 | } |
739 | |
740 | void AgentBasePrivate::slotNetworkStatusChange(Solid::Networking::Status stat) |
741 | { |
742 | Q_UNUSED(stat); |
743 | Q_Q(AgentBase); |
744 | q->setOnlineInternal(mDesiredOnlineState); |
745 | } |
746 | |
747 | void AgentBasePrivate::slotResumedFromSuspend() |
748 | { |
749 | if (mNeedsNetwork) { |
750 | slotNetworkStatusChange(Solid::Networking::status()); |
751 | } |
752 | } |
753 | |
754 | void AgentBasePrivate::slotTemporaryOfflineTimeout() |
755 | { |
756 | Q_Q(AgentBase); |
757 | q->setOnlineInternal(true); |
758 | } |
759 | |
760 | QString AgentBasePrivate::dumpNotificationListToString() const |
761 | { |
762 | return mChangeRecorder->dumpNotificationListToString(); |
763 | } |
764 | |
765 | void AgentBasePrivate::dumpMemoryInfo() const |
766 | { |
767 | // Send it to stdout, so we can debug user problems. |
768 | // since you have to explicitely call this |
769 | // it won't flood users with release builds. |
770 | QTextStream stream(stdout); |
771 | stream << dumpMemoryInfoToString(); |
772 | } |
773 | |
774 | QString AgentBasePrivate::dumpMemoryInfoToString() const |
775 | { |
776 | // man mallinfo for more info |
777 | QString str; |
778 | #if defined __GLIBC__ |
779 | struct mallinfo mi; |
780 | mi = mallinfo(); |
781 | QTextStream stream(&str); |
782 | stream |
783 | << "Total non-mmapped bytes (arena): " << mi.arena << '\n' |
784 | << "# of free chunks (ordblks): " << mi.ordblks << '\n' |
785 | << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n' |
786 | << "# of mapped regions (hblks): " << mi.hblks << '\n' |
787 | << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n' |
788 | << "Max. total allocated space (usmblks): " << mi.usmblks << '\n' |
789 | << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n' |
790 | << "Total allocated space (uordblks): " << mi.uordblks << '\n' |
791 | << "Total free space (fordblks): " << mi.fordblks << '\n' |
792 | << "Topmost releasable block (keepcost): " << mi.keepcost << '\n'; |
793 | #else |
794 | str = QLatin1String( "mallinfo() not supported" ); |
795 | #endif |
796 | return str; |
797 | } |
798 | |
799 | AgentBase::AgentBase(const QString &id) |
800 | : d_ptr(new AgentBasePrivate(this)) |
801 | { |
802 | sAgentBase = this; |
803 | d_ptr->mId = id; |
804 | d_ptr->init(); |
805 | } |
806 | |
807 | AgentBase::AgentBase(AgentBasePrivate *d, const QString &id) |
808 | : d_ptr(d) |
809 | { |
810 | sAgentBase = this; |
811 | d_ptr->mId = id; |
812 | d_ptr->init(); |
813 | } |
814 | |
815 | AgentBase::~AgentBase() |
816 | { |
817 | delete d_ptr; |
818 | } |
819 | |
820 | QString AgentBase::parseArguments(int argc, char **argv) |
821 | { |
822 | QString identifier; |
823 | if (argc < 3) { |
824 | kDebug() << "Not enough arguments passed..." ; |
825 | exit(1); |
826 | } |
827 | |
828 | for (int i = 1; i < argc - 1; ++i) { |
829 | if (QLatin1String(argv[i]) == QLatin1String("--identifier" )) { |
830 | identifier = QLatin1String(argv[i + 1]); |
831 | } |
832 | } |
833 | |
834 | if (identifier.isEmpty()) { |
835 | kDebug() << "Identifier argument missing" ; |
836 | exit(1); |
837 | } |
838 | |
839 | const QFileInfo fi(QString::fromLocal8Bit(argv[0])); |
840 | // strip off full path and possible .exe suffix |
841 | const QByteArray catalog = fi.baseName().toLatin1(); |
842 | |
843 | KCmdLineArgs::init(argc, argv, ServerManager::addNamespace(identifier).toLatin1(), catalog, ki18n("Akonadi Agent" ), KDEPIMLIBS_VERSION, |
844 | ki18n("Akonadi Agent" )); |
845 | |
846 | KCmdLineOptions options; |
847 | options.add("identifier <argument>" , ki18n("Agent identifier" )); |
848 | KCmdLineArgs::addCmdLineOptions(options); |
849 | |
850 | return identifier; |
851 | } |
852 | |
853 | // @endcond |
854 | |
855 | int AgentBase::init(AgentBase *r) |
856 | { |
857 | QApplication::setQuitOnLastWindowClosed(false); |
858 | KGlobal::locale()->insertCatalog(QLatin1String("libakonadi" )); |
859 | int rv = kapp->exec(); |
860 | delete r; |
861 | return rv; |
862 | } |
863 | |
864 | int AgentBase::status() const |
865 | { |
866 | Q_D(const AgentBase); |
867 | |
868 | return d->mStatusCode; |
869 | } |
870 | |
871 | QString AgentBase::statusMessage() const |
872 | { |
873 | Q_D(const AgentBase); |
874 | |
875 | return d->mStatusMessage; |
876 | } |
877 | |
878 | int AgentBase::progress() const |
879 | { |
880 | Q_D(const AgentBase); |
881 | |
882 | return d->mProgress; |
883 | } |
884 | |
885 | QString AgentBase::progressMessage() const |
886 | { |
887 | Q_D(const AgentBase); |
888 | |
889 | return d->mProgressMessage; |
890 | } |
891 | |
892 | bool AgentBase::isOnline() const |
893 | { |
894 | Q_D(const AgentBase); |
895 | |
896 | return d->mOnline; |
897 | } |
898 | |
899 | void AgentBase::setNeedsNetwork(bool needsNetwork) |
900 | { |
901 | Q_D(AgentBase); |
902 | d->mNeedsNetwork = needsNetwork; |
903 | |
904 | if (d->mNeedsNetwork) { |
905 | connect(Solid::Networking::notifier() |
906 | , SIGNAL(statusChanged(Solid::Networking::Status)) |
907 | , this, SLOT(slotNetworkStatusChange(Solid::Networking::Status)) |
908 | , Qt::UniqueConnection); |
909 | |
910 | } else { |
911 | disconnect(Solid::Networking::notifier(), 0, 0, 0); |
912 | setOnlineInternal(d->mDesiredOnlineState); |
913 | } |
914 | } |
915 | |
916 | void AgentBase::setOnline(bool state) |
917 | { |
918 | Q_D(AgentBase); |
919 | d->mDesiredOnlineState = state; |
920 | d->mSettings->setValue(QLatin1String("Agent/DesiredOnlineState" ), state); |
921 | setOnlineInternal(state); |
922 | } |
923 | |
924 | void AgentBase::setTemporaryOffline(int makeOnlineInSeconds) |
925 | { |
926 | Q_D(AgentBase); |
927 | |
928 | // if not currently online, avoid bringing it online after the timeout |
929 | if (!d->mOnline) { |
930 | return; |
931 | } |
932 | |
933 | setOnlineInternal(false); |
934 | |
935 | if (!d->mTemporaryOfflineTimer) { |
936 | d->mTemporaryOfflineTimer = new QTimer(d); |
937 | d->mTemporaryOfflineTimer->setSingleShot(true); |
938 | connect(d->mTemporaryOfflineTimer, SIGNAL(timeout()), this, SLOT(slotTemporaryOfflineTimeout())); |
939 | } |
940 | d->mTemporaryOfflineTimer->setInterval(makeOnlineInSeconds * 1000); |
941 | d->mTemporaryOfflineTimer->start(); |
942 | } |
943 | |
944 | void AgentBase::setOnlineInternal( bool state ) |
945 | { |
946 | Q_D(AgentBase); |
947 | if (state && d->mNeedsNetwork) { |
948 | const Solid::Networking::Status stat = Solid::Networking::status(); |
949 | if (stat != Solid::Networking::Unknown && stat != Solid::Networking::Connected) { |
950 | //Don't go online if the resource needs network but there is none |
951 | state = false; |
952 | } |
953 | } |
954 | d->mOnline = state; |
955 | |
956 | if (d->mTemporaryOfflineTimer) { |
957 | d->mTemporaryOfflineTimer->stop(); |
958 | } |
959 | |
960 | const QString newMessage = d->defaultReadyMessage(); |
961 | if ( d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken ) { |
962 | emit status( d->mStatusCode, newMessage ); |
963 | } |
964 | |
965 | doSetOnline(state); |
966 | emit onlineChanged(state); |
967 | } |
968 | |
969 | void AgentBase::doSetOnline(bool online) |
970 | { |
971 | Q_UNUSED(online); |
972 | } |
973 | |
974 | void AgentBase::configure(WId windowId) |
975 | { |
976 | Q_UNUSED(windowId); |
977 | emit configurationDialogAccepted(); |
978 | } |
979 | |
980 | #ifdef Q_OS_WIN //krazy:exclude=cpp |
981 | void AgentBase::configure(qlonglong windowId) |
982 | { |
983 | configure(reinterpret_cast<WId>(windowId)); |
984 | } |
985 | #endif |
986 | |
987 | WId AgentBase::winIdForDialogs() const |
988 | { |
989 | const bool registered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered(QLatin1String("org.freedesktop.akonaditray" )); |
990 | if (!registered) { |
991 | return 0; |
992 | } |
993 | |
994 | QDBusInterface dbus(QLatin1String("org.freedesktop.akonaditray" ), QLatin1String("/Actions" ), |
995 | QLatin1String("org.freedesktop.Akonadi.Tray" )); |
996 | const QDBusMessage reply = dbus.call(QLatin1String("getWinId" )); |
997 | |
998 | if (reply.type() == QDBusMessage::ErrorMessage) { |
999 | return 0; |
1000 | } |
1001 | |
1002 | const WId winid = (WId)reply.arguments().at(0).toLongLong(); |
1003 | |
1004 | return winid; |
1005 | } |
1006 | |
1007 | void AgentBase::quit() |
1008 | { |
1009 | Q_D(AgentBase); |
1010 | aboutToQuit(); |
1011 | |
1012 | if (d->mSettings) { |
1013 | d->mChangeRecorder->setConfig(0); |
1014 | d->mSettings->sync(); |
1015 | } |
1016 | |
1017 | KGlobal::deref(); |
1018 | } |
1019 | |
1020 | void AgentBase::aboutToQuit() |
1021 | { |
1022 | } |
1023 | |
1024 | void AgentBase::cleanup() |
1025 | { |
1026 | Q_D(AgentBase); |
1027 | // prevent the monitor from picking up deletion signals for our own data if we are a resource |
1028 | // and thus avoid that we kill our own data as last act before our own death |
1029 | d->mChangeRecorder->blockSignals(true); |
1030 | |
1031 | aboutToQuit(); |
1032 | |
1033 | const QString fileName = d->mSettings->fileName(); |
1034 | |
1035 | /* |
1036 | * First destroy the settings object... |
1037 | */ |
1038 | d->mChangeRecorder->setConfig(0); |
1039 | delete d->mSettings; |
1040 | d->mSettings = 0; |
1041 | |
1042 | /* |
1043 | * ... then remove the file from hd. |
1044 | */ |
1045 | QFile::remove(fileName); |
1046 | |
1047 | /* |
1048 | * ... and remove the changes file from hd. |
1049 | */ |
1050 | QFile::remove(fileName + QLatin1String("_changes.dat" )); |
1051 | |
1052 | /* |
1053 | * ... and also remove the agent configuration file if there is one. |
1054 | */ |
1055 | QString configFile = KStandardDirs::locateLocal("config" , config()->name()); |
1056 | QFile::remove(configFile); |
1057 | |
1058 | KGlobal::deref(); |
1059 | } |
1060 | |
1061 | void AgentBase::registerObserver(Observer *observer) |
1062 | { |
1063 | // TODO in theory we should re-connect change recorder signals here that we disconnected previously |
1064 | d_ptr->mObserver = observer; |
1065 | |
1066 | const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d_ptr->mObserver) != 0); |
1067 | const bool hasObserverV4 = (dynamic_cast<AgentBase::ObserverV4 *>(d_ptr->mObserver) != 0); |
1068 | |
1069 | disconnect(d_ptr->mChangeRecorder, SIGNAL(tagAdded(Akonadi::Tag)), |
1070 | d_ptr, SLOT(tagAdded(Akonadi::Tag))); |
1071 | disconnect(d_ptr->mChangeRecorder, SIGNAL(tagChanged(Akonadi::Tag)), |
1072 | d_ptr, SLOT(tagChanged(Akonadi::Tag))); |
1073 | disconnect(d_ptr->mChangeRecorder, SIGNAL(tagRemoved(Akonadi::Tag)), |
1074 | d_ptr, SLOT(tagRemoved(Akonadi::Tag))); |
1075 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>)), |
1076 | d_ptr, SLOT(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>))); |
1077 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>)), |
1078 | d_ptr, SLOT(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>))); |
1079 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection)), |
1080 | d_ptr, SLOT(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))); |
1081 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsRemoved(Akonadi::Item::List)), |
1082 | d_ptr, SLOT(itemsRemoved(Akonadi::Item::List))); |
1083 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection)), |
1084 | d_ptr, SLOT(itemsLinked(Akonadi::Item::List,Akonadi::Collection))); |
1085 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection)), |
1086 | d_ptr, SLOT(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))); |
1087 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), |
1088 | d_ptr, SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); |
1089 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemRemoved(Akonadi::Item)), |
1090 | d_ptr, SLOT(itemRemoved(Akonadi::Item))); |
1091 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), |
1092 | d_ptr, SLOT(itemLinked(Akonadi::Item,Akonadi::Collection))); |
1093 | disconnect(d_ptr->mChangeRecorder, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), |
1094 | d_ptr, SLOT(itemUnlinked(Akonadi::Item,Akonadi::Collection))); |
1095 | |
1096 | if (hasObserverV4) { |
1097 | connect(d_ptr->mChangeRecorder, SIGNAL(tagAdded(Akonadi::Tag)), |
1098 | d_ptr, SLOT(tagAdded(Akonadi::Tag))); |
1099 | connect(d_ptr->mChangeRecorder, SIGNAL(tagChanged(Akonadi::Tag)), |
1100 | d_ptr, SLOT(tagChanged(Akonadi::Tag))); |
1101 | connect(d_ptr->mChangeRecorder, SIGNAL(tagRemoved(Akonadi::Tag)), |
1102 | d_ptr, SLOT(tagRemoved(Akonadi::Tag))); |
1103 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>)), |
1104 | d_ptr, SLOT(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>))); |
1105 | } |
1106 | |
1107 | if (hasObserverV3) { |
1108 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>)), |
1109 | d_ptr, SLOT(itemsFlagsChanged(Akonadi::Item::List,QSet<QByteArray>,QSet<QByteArray>))); |
1110 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection)), |
1111 | d_ptr, SLOT(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))); |
1112 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsRemoved(Akonadi::Item::List)), |
1113 | d_ptr, SLOT(itemsRemoved(Akonadi::Item::List))); |
1114 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection)), |
1115 | d_ptr, SLOT(itemsLinked(Akonadi::Item::List,Akonadi::Collection))); |
1116 | connect(d_ptr->mChangeRecorder, SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection)), |
1117 | d_ptr, SLOT(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))); |
1118 | } else { |
1119 | // V2 - don't connect these if we have V3 |
1120 | connect(d_ptr->mChangeRecorder, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), |
1121 | d_ptr, SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); |
1122 | connect(d_ptr->mChangeRecorder, SIGNAL(itemRemoved(Akonadi::Item)), |
1123 | d_ptr, SLOT(itemRemoved(Akonadi::Item))); |
1124 | connect(d_ptr->mChangeRecorder, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), |
1125 | d_ptr, SLOT(itemLinked(Akonadi::Item,Akonadi::Collection))); |
1126 | connect(d_ptr->mChangeRecorder, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), |
1127 | d_ptr, SLOT(itemUnlinked(Akonadi::Item,Akonadi::Collection))); |
1128 | } |
1129 | } |
1130 | |
1131 | QString AgentBase::identifier() const |
1132 | { |
1133 | return d_ptr->mId; |
1134 | } |
1135 | |
1136 | void AgentBase::setAgentName(const QString &name) |
1137 | { |
1138 | Q_D(AgentBase); |
1139 | if (name == d->mName) { |
1140 | return; |
1141 | } |
1142 | |
1143 | // TODO: rename collection |
1144 | d->mName = name; |
1145 | |
1146 | if (d->mName.isEmpty() || d->mName == d->mId) { |
1147 | d->mSettings->remove(QLatin1String("Resource/Name" )); |
1148 | d->mSettings->remove(QLatin1String("Agent/Name" )); |
1149 | } else |
1150 | d->mSettings->setValue(QLatin1String("Agent/Name" ), d->mName); |
1151 | |
1152 | d->mSettings->sync(); |
1153 | |
1154 | d->setProgramName(); |
1155 | |
1156 | emit agentNameChanged(d->mName); |
1157 | } |
1158 | |
1159 | QString AgentBase::agentName() const |
1160 | { |
1161 | Q_D(const AgentBase); |
1162 | if (d->mName.isEmpty()) { |
1163 | return d->mId; |
1164 | } else { |
1165 | return d->mName; |
1166 | } |
1167 | } |
1168 | |
1169 | void AgentBase::changeProcessed() |
1170 | { |
1171 | Q_D(AgentBase); |
1172 | d->changeProcessed(); |
1173 | } |
1174 | |
1175 | ChangeRecorder *AgentBase::changeRecorder() const |
1176 | { |
1177 | return d_ptr->mChangeRecorder; |
1178 | } |
1179 | |
1180 | KSharedConfigPtr AgentBase::config() |
1181 | { |
1182 | if (QCoreApplication::instance()->thread() == QThread::currentThread()) { |
1183 | return KGlobal::config(); |
1184 | } else { |
1185 | return componentData().config(); |
1186 | } |
1187 | } |
1188 | |
1189 | void AgentBase::abort() |
1190 | { |
1191 | emit abortRequested(); |
1192 | } |
1193 | |
1194 | void AgentBase::reconfigure() |
1195 | { |
1196 | emit reloadConfiguration(); |
1197 | } |
1198 | |
1199 | extern QThreadStorage<KComponentData *> s_agentComponentDatas; |
1200 | |
1201 | KComponentData AgentBase::componentData() |
1202 | { |
1203 | if (QThread::currentThread() == QCoreApplication::instance()->thread()) { |
1204 | if (s_agentComponentDatas.hasLocalData()) { |
1205 | return *(s_agentComponentDatas.localData()); |
1206 | } else { |
1207 | return KGlobal::mainComponent(); |
1208 | } |
1209 | } |
1210 | |
1211 | Q_ASSERT(s_agentComponentDatas.hasLocalData()); |
1212 | return *(s_agentComponentDatas.localData()); |
1213 | } |
1214 | |
1215 | #include "moc_agentbase.cpp" |
1216 | #include "moc_agentbase_p.cpp" |
1217 | |