1 | /* |
2 | Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com> |
3 | |
4 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by |
6 | the Free Software Foundation; either version 2 of the License, or (at your |
7 | option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
12 | License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to the |
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17 | 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "specialcollectionshelperjobs_p.h" |
21 | |
22 | #include "dbusconnectionpool.h" |
23 | #include "specialcollectionattribute_p.h" |
24 | #include "specialcollections.h" |
25 | #include "servermanager.h" |
26 | |
27 | #include <akonadi/agentinstance.h> |
28 | #include <akonadi/agentinstancecreatejob.h> |
29 | #include <akonadi/agentmanager.h> |
30 | #include <akonadi/collectionfetchjob.h> |
31 | #include <akonadi/collectionfetchscope.h> |
32 | #include <akonadi/collectionmodifyjob.h> |
33 | #include <akonadi/entitydisplayattribute.h> |
34 | #include <akonadi/resourcesynchronizationjob.h> |
35 | |
36 | #include <KDebug> |
37 | #include <KLocalizedString> |
38 | #include <kcoreconfigskeleton.h> |
39 | |
40 | #include <QtDBus/QDBusConnectionInterface> |
41 | #include <QtDBus/QDBusInterface> |
42 | #include <QtDBus/QDBusServiceWatcher> |
43 | #include <QtCore/QMetaMethod> |
44 | #include <QtCore/QTime> |
45 | #include <QtCore/QTimer> |
46 | |
47 | #define LOCK_WAIT_TIMEOUT_SECONDS 10 |
48 | |
49 | using namespace Akonadi; |
50 | |
51 | // convenient methods to get/set the default resource id |
52 | static void setDefaultResourceId(KCoreConfigSkeleton *settings, const QString &value) |
53 | { |
54 | KConfigSkeletonItem *item = settings->findItem(QLatin1String("DefaultResourceId" )); |
55 | Q_ASSERT(item); |
56 | item->setProperty(value); |
57 | } |
58 | |
59 | static QString defaultResourceId(KCoreConfigSkeleton *settings) |
60 | { |
61 | const KConfigSkeletonItem *item = settings->findItem(QLatin1String("DefaultResourceId" )); |
62 | Q_ASSERT(item); |
63 | return item->property().toString(); |
64 | } |
65 | |
66 | static QString dbusServiceName() |
67 | { |
68 | QString service = QString::fromLatin1("org.kde.pim.SpecialCollections" ); |
69 | if (ServerManager::hasInstanceIdentifier()) { |
70 | return service + ServerManager::instanceIdentifier(); |
71 | } |
72 | return service; |
73 | } |
74 | |
75 | static QVariant::Type argumentType(const QMetaObject *mo, const QString &method) |
76 | { |
77 | QMetaMethod m; |
78 | for (int i = 0; i < mo->methodCount(); ++i) { |
79 | const QString signature = QString::fromLatin1(mo->method(i).signature()); |
80 | if (signature.startsWith(method)) { |
81 | m = mo->method(i); |
82 | } |
83 | } |
84 | |
85 | if (!m.signature()) { |
86 | return QVariant::Invalid; |
87 | } |
88 | |
89 | const QList<QByteArray> argTypes = m.parameterTypes(); |
90 | if (argTypes.count() != 1) { |
91 | return QVariant::Invalid; |
92 | } |
93 | |
94 | return QVariant::nameToType(argTypes.first()); |
95 | } |
96 | |
97 | // ===================== ResourceScanJob ============================ |
98 | |
99 | /** |
100 | @internal |
101 | */ |
102 | class Akonadi::ResourceScanJob::Private |
103 | { |
104 | public: |
105 | Private(KCoreConfigSkeleton *settings, ResourceScanJob *qq); |
106 | |
107 | void fetchResult(KJob *job); // slot |
108 | |
109 | ResourceScanJob *const q; |
110 | |
111 | // Input: |
112 | QString mResourceId; |
113 | KCoreConfigSkeleton *mSettings; |
114 | |
115 | // Output: |
116 | Collection mRootCollection; |
117 | Collection::List mSpecialCollections; |
118 | }; |
119 | |
120 | ResourceScanJob::Private::Private(KCoreConfigSkeleton *settings, ResourceScanJob *qq) |
121 | : q(qq) |
122 | , mSettings(settings) |
123 | { |
124 | } |
125 | |
126 | void ResourceScanJob::Private::fetchResult(KJob *job) |
127 | { |
128 | if (job->error()) { |
129 | kWarning() << job->errorText(); |
130 | return; |
131 | } |
132 | |
133 | CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob *>(job); |
134 | Q_ASSERT(fetchJob); |
135 | |
136 | Q_ASSERT(!mRootCollection.isValid()); |
137 | Q_ASSERT(mSpecialCollections.isEmpty()); |
138 | foreach (const Collection &collection, fetchJob->collections()) { |
139 | if (collection.parentCollection() == Collection::root()) { |
140 | if (mRootCollection.isValid()) { |
141 | kWarning() << "Resource has more than one root collection. I don't know what to do." ; |
142 | } else { |
143 | mRootCollection = collection; |
144 | } |
145 | } |
146 | |
147 | if (collection.hasAttribute<SpecialCollectionAttribute>()) { |
148 | mSpecialCollections.append(collection); |
149 | } |
150 | } |
151 | |
152 | kDebug() << "Fetched root collection" << mRootCollection.id() |
153 | << "and" << mSpecialCollections.count() << "local folders" |
154 | << "(total" << fetchJob->collections().count() << "collections)." ; |
155 | |
156 | if (!mRootCollection.isValid()) { |
157 | q->setError(Unknown); |
158 | q->setErrorText(i18n("Could not fetch root collection of resource %1." , mResourceId)); |
159 | q->emitResult(); |
160 | return; |
161 | } |
162 | |
163 | // We are done! |
164 | q->emitResult(); |
165 | } |
166 | |
167 | ResourceScanJob::ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent) |
168 | : Job(parent) |
169 | , d(new Private(settings, this)) |
170 | { |
171 | setResourceId(resourceId); |
172 | } |
173 | |
174 | ResourceScanJob::~ResourceScanJob() |
175 | { |
176 | delete d; |
177 | } |
178 | |
179 | QString ResourceScanJob::resourceId() const |
180 | { |
181 | return d->mResourceId; |
182 | } |
183 | |
184 | void ResourceScanJob::setResourceId(const QString &resourceId) |
185 | { |
186 | d->mResourceId = resourceId; |
187 | } |
188 | |
189 | Akonadi::Collection ResourceScanJob::rootResourceCollection() const |
190 | { |
191 | return d->mRootCollection; |
192 | } |
193 | |
194 | Akonadi::Collection::List ResourceScanJob::specialCollections() const |
195 | { |
196 | return d->mSpecialCollections; |
197 | } |
198 | |
199 | void ResourceScanJob::doStart() |
200 | { |
201 | if (d->mResourceId.isEmpty()) { |
202 | kError() << "No resource ID given." ; |
203 | setError(Job::Unknown); |
204 | setErrorText(i18n("No resource ID given." )); |
205 | emitResult(); |
206 | return; |
207 | } |
208 | |
209 | CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), |
210 | CollectionFetchJob::Recursive, this); |
211 | fetchJob->fetchScope().setResource(d->mResourceId); |
212 | fetchJob->fetchScope().setIncludeStatistics(true); |
213 | connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(fetchResult(KJob*))); |
214 | } |
215 | |
216 | // ===================== DefaultResourceJob ============================ |
217 | |
218 | /** |
219 | @internal |
220 | */ |
221 | class Akonadi::DefaultResourceJobPrivate |
222 | { |
223 | public: |
224 | DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq); |
225 | |
226 | void tryFetchResource(); |
227 | void resourceCreateResult(KJob *job); // slot |
228 | void resourceSyncResult(KJob *job); // slot |
229 | void collectionFetchResult(KJob *job); // slot |
230 | void collectionModifyResult(KJob *job); // slot |
231 | |
232 | DefaultResourceJob *const q; |
233 | KCoreConfigSkeleton *mSettings; |
234 | bool mResourceWasPreexisting; |
235 | int mPendingModifyJobs; |
236 | QString mDefaultResourceType; |
237 | QVariantMap mDefaultResourceOptions; |
238 | QList<QByteArray> mKnownTypes; |
239 | QMap<QByteArray, QString> mNameForTypeMap; |
240 | QMap<QByteArray, QString> mIconForTypeMap; |
241 | }; |
242 | |
243 | DefaultResourceJobPrivate::DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq) |
244 | : q(qq) |
245 | , mSettings(settings) |
246 | , mResourceWasPreexisting(true /* for safety, so as not to accidentally delete data */) |
247 | , mPendingModifyJobs(0) |
248 | { |
249 | } |
250 | |
251 | void DefaultResourceJobPrivate::tryFetchResource() |
252 | { |
253 | // Get the resourceId from config. Another instance might have changed it in the meantime. |
254 | mSettings->readConfig(); |
255 | |
256 | const QString resourceId = defaultResourceId(mSettings); |
257 | |
258 | kDebug() << "Read defaultResourceId" << resourceId << "from config." ; |
259 | |
260 | const AgentInstance resource = AgentManager::self()->instance(resourceId); |
261 | if (resource.isValid()) { |
262 | // The resource exists; scan it. |
263 | mResourceWasPreexisting = true; |
264 | kDebug() << "Found resource" << resourceId; |
265 | q->setResourceId(resourceId); |
266 | |
267 | CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, q); |
268 | fetchJob->fetchScope().setResource(resourceId); |
269 | fetchJob->fetchScope().setIncludeStatistics(true); |
270 | q->connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*))); |
271 | } else { |
272 | // Try harder: maybe the default resource has been removed and another one added |
273 | // without updating the config file, in this case search for a resource |
274 | // of the same type and the default name |
275 | const AgentInstance::List resources = AgentManager::self()->instances(); |
276 | foreach (const AgentInstance &resource, resources) { |
277 | if (resource.type().identifier() == mDefaultResourceType) { |
278 | if (resource.name() == mDefaultResourceOptions.value(QLatin1String("Name" )).toString()) { |
279 | // found a matching one... |
280 | setDefaultResourceId(mSettings, resource.identifier()); |
281 | mSettings->writeConfig(); |
282 | mResourceWasPreexisting = true; |
283 | kDebug() << "Found resource" << resource.identifier(); |
284 | q->setResourceId(resource.identifier()); |
285 | q->ResourceScanJob::doStart(); |
286 | return; |
287 | } |
288 | } |
289 | } |
290 | |
291 | // Create the resource. |
292 | mResourceWasPreexisting = false; |
293 | kDebug() << "Creating maildir resource." ; |
294 | const AgentType type = AgentManager::self()->type(mDefaultResourceType); |
295 | AgentInstanceCreateJob *job = new AgentInstanceCreateJob(type, q); |
296 | QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(resourceCreateResult(KJob*))); |
297 | job->start(); // non-Akonadi::Job |
298 | } |
299 | } |
300 | |
301 | void DefaultResourceJobPrivate::resourceCreateResult(KJob *job) |
302 | { |
303 | if (job->error()) { |
304 | kWarning() << job->errorText(); |
305 | //fail( i18n( "Failed to create the default resource (%1).", job->errorString() ) ); |
306 | q->setError(job->error()); |
307 | q->setErrorText(job->errorText()); |
308 | q->emitResult(); |
309 | return; |
310 | } |
311 | |
312 | AgentInstance agent; |
313 | |
314 | // Get the resource instance. |
315 | { |
316 | AgentInstanceCreateJob *createJob = qobject_cast<AgentInstanceCreateJob *>(job); |
317 | Q_ASSERT(createJob); |
318 | agent = createJob->instance(); |
319 | setDefaultResourceId(mSettings, agent.identifier()); |
320 | kDebug() << "Created maildir resource with id" << defaultResourceId(mSettings); |
321 | } |
322 | |
323 | const QString defaultId = defaultResourceId(mSettings); |
324 | |
325 | // Configure the resource. |
326 | { |
327 | agent.setName(mDefaultResourceOptions.value(QLatin1String("Name" )).toString()); |
328 | |
329 | QDBusInterface conf(QString::fromLatin1("org.freedesktop.Akonadi.Resource." ) + defaultId, |
330 | QString::fromLatin1("/Settings" ), QString()); |
331 | |
332 | if (!conf.isValid()) { |
333 | q->setError(-1); |
334 | q->setErrorText(i18n("Invalid resource identifier '%1'" , defaultId)); |
335 | q->emitResult(); |
336 | return; |
337 | } |
338 | |
339 | QMapIterator<QString, QVariant> it(mDefaultResourceOptions); |
340 | while (it.hasNext()) { |
341 | it.next(); |
342 | |
343 | if (it.key() == QLatin1String("Name" )) { |
344 | continue; |
345 | } |
346 | |
347 | const QString methodName = QString::fromLatin1("set%1" ).arg(it.key()); |
348 | const QVariant::Type argType = argumentType(conf.metaObject(), methodName); |
349 | if (argType == QVariant::Invalid) { |
350 | q->setError(Job::Unknown); |
351 | q->setErrorText(i18n("Failed to configure default resource via D-Bus." )); |
352 | q->emitResult(); |
353 | return; |
354 | } |
355 | |
356 | QDBusReply<void> reply = conf.call(methodName, it.value()); |
357 | if (!reply.isValid()) { |
358 | q->setError(Job::Unknown); |
359 | q->setErrorText(i18n("Failed to configure default resource via D-Bus." )); |
360 | q->emitResult(); |
361 | return; |
362 | } |
363 | } |
364 | |
365 | conf.call(QLatin1String("writeConfig" )); |
366 | |
367 | agent.reconfigure(); |
368 | } |
369 | |
370 | // Sync the resource. |
371 | { |
372 | ResourceSynchronizationJob *syncJob = new ResourceSynchronizationJob(agent, q); |
373 | QObject::connect(syncJob, SIGNAL(result(KJob*)), q, SLOT(resourceSyncResult(KJob*))); |
374 | syncJob->start(); // non-Akonadi |
375 | } |
376 | } |
377 | |
378 | void DefaultResourceJobPrivate::resourceSyncResult(KJob *job) |
379 | { |
380 | if (job->error()) { |
381 | kWarning() << job->errorText(); |
382 | //fail( i18n( "ResourceSynchronizationJob failed (%1).", job->errorString() ) ); |
383 | return; |
384 | } |
385 | |
386 | // Fetch the collections of the resource. |
387 | kDebug() << "Fetching maildir collections." ; |
388 | CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, q); |
389 | fetchJob->fetchScope().setResource(defaultResourceId(mSettings)); |
390 | QObject::connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*))); |
391 | } |
392 | |
393 | void DefaultResourceJobPrivate::collectionFetchResult(KJob *job) |
394 | { |
395 | if (job->error()) { |
396 | kWarning() << job->errorText(); |
397 | //fail( i18n( "Failed to fetch the root maildir collection (%1).", job->errorString() ) ); |
398 | return; |
399 | } |
400 | |
401 | CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob *>(job); |
402 | Q_ASSERT(fetchJob); |
403 | |
404 | const Collection::List collections = fetchJob->collections(); |
405 | kDebug() << "Fetched" << collections.count() << "collections." ; |
406 | |
407 | // Find the root maildir collection. |
408 | Collection::List toRecover; |
409 | Collection resourceCollection; |
410 | foreach (const Collection &collection, collections) { |
411 | if (collection.parentCollection() == Collection::root()) { |
412 | resourceCollection = collection; |
413 | toRecover.append(collection); |
414 | break; |
415 | } |
416 | } |
417 | |
418 | if (!resourceCollection.isValid()) { |
419 | q->setError(Job::Unknown); |
420 | q->setErrorText(i18n("Failed to fetch the resource collection." )); |
421 | q->emitResult(); |
422 | return; |
423 | } |
424 | |
425 | // Find all children of the resource collection. |
426 | foreach (const Collection &collection, collections) { |
427 | if (collection.parentCollection() == resourceCollection) { |
428 | toRecover.append(collection); |
429 | } |
430 | } |
431 | |
432 | QHash<QString, QByteArray> typeForName; |
433 | foreach (const QByteArray &type, mKnownTypes) { |
434 | const QString displayName = mNameForTypeMap.value(type); |
435 | typeForName[displayName] = type; |
436 | } |
437 | |
438 | // These collections have been created by the maildir resource, when it |
439 | // found the folders on disk. So give them the necessary attributes now. |
440 | Q_ASSERT(mPendingModifyJobs == 0); |
441 | foreach (Collection collection, toRecover) { // krazy:exclude=foreach |
442 | |
443 | if (collection.hasAttribute<SpecialCollectionAttribute>()) { |
444 | continue; |
445 | } |
446 | |
447 | // Find the type for the collection. |
448 | const QString name = collection.displayName(); |
449 | const QByteArray type = typeForName.value(name); |
450 | |
451 | if (!type.isEmpty()) { |
452 | kDebug() << "Recovering collection" << name; |
453 | setCollectionAttributes(collection, type, mNameForTypeMap, mIconForTypeMap); |
454 | |
455 | CollectionModifyJob *modifyJob = new CollectionModifyJob(collection, q); |
456 | QObject::connect(modifyJob, SIGNAL(result(KJob*)), q, SLOT(collectionModifyResult(KJob*))); |
457 | mPendingModifyJobs++; |
458 | } else { |
459 | kDebug() << "Searching for names: " << typeForName.keys(); |
460 | kDebug() << "Unknown collection name" << name << "-- not recovering." ; |
461 | } |
462 | } |
463 | |
464 | if (mPendingModifyJobs == 0) { |
465 | // Scan the resource. |
466 | q->setResourceId(defaultResourceId(mSettings)); |
467 | q->ResourceScanJob::doStart(); |
468 | } |
469 | } |
470 | |
471 | void DefaultResourceJobPrivate::collectionModifyResult(KJob *job) |
472 | { |
473 | if (job->error()) { |
474 | kWarning() << job->errorText(); |
475 | //fail( i18n( "Failed to modify the root maildir collection (%1).", job->errorString() ) ); |
476 | return; |
477 | } |
478 | |
479 | Q_ASSERT(mPendingModifyJobs > 0); |
480 | mPendingModifyJobs--; |
481 | kDebug() << "pendingModifyJobs now" << mPendingModifyJobs; |
482 | if (mPendingModifyJobs == 0) { |
483 | // Write the updated config. |
484 | kDebug() << "Writing defaultResourceId" << defaultResourceId(mSettings) << "to config." ; |
485 | mSettings->writeConfig(); |
486 | |
487 | // Scan the resource. |
488 | q->setResourceId(defaultResourceId(mSettings)); |
489 | q->ResourceScanJob::doStart(); |
490 | } |
491 | } |
492 | |
493 | DefaultResourceJob::DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent) |
494 | : ResourceScanJob(QString(), settings, parent) |
495 | , d(new DefaultResourceJobPrivate(settings, this)) |
496 | { |
497 | } |
498 | |
499 | DefaultResourceJob::~DefaultResourceJob() |
500 | { |
501 | delete d; |
502 | } |
503 | |
504 | void DefaultResourceJob::setDefaultResourceType(const QString &type) |
505 | { |
506 | d->mDefaultResourceType = type; |
507 | } |
508 | |
509 | void DefaultResourceJob::setDefaultResourceOptions(const QVariantMap &options) |
510 | { |
511 | d->mDefaultResourceOptions = options; |
512 | } |
513 | |
514 | void DefaultResourceJob::setTypes(const QList<QByteArray> &types) |
515 | { |
516 | d->mKnownTypes = types; |
517 | } |
518 | |
519 | void DefaultResourceJob::setNameForTypeMap(const QMap<QByteArray, QString> &map) |
520 | { |
521 | d->mNameForTypeMap = map; |
522 | } |
523 | |
524 | void DefaultResourceJob::setIconForTypeMap(const QMap<QByteArray, QString> &map) |
525 | { |
526 | d->mIconForTypeMap = map; |
527 | } |
528 | |
529 | void DefaultResourceJob::doStart() |
530 | { |
531 | d->tryFetchResource(); |
532 | } |
533 | |
534 | void DefaultResourceJob::slotResult(KJob *job) |
535 | { |
536 | if (job->error()) { |
537 | kWarning() << job->errorText(); |
538 | // Do some cleanup. |
539 | if (!d->mResourceWasPreexisting) { |
540 | // We only removed the resource instance if we have created it. |
541 | // Otherwise we might lose the user's data. |
542 | const AgentInstance resource = AgentManager::self()->instance(defaultResourceId(d->mSettings)); |
543 | kDebug() << "Removing resource" << resource.identifier(); |
544 | AgentManager::self()->removeInstance(resource); |
545 | } |
546 | } |
547 | |
548 | Job::slotResult(job); |
549 | } |
550 | |
551 | // ===================== GetLockJob ============================ |
552 | |
553 | class Akonadi::GetLockJob::Private |
554 | { |
555 | public: |
556 | Private(GetLockJob *qq); |
557 | |
558 | void doStart(); // slot |
559 | void serviceOwnerChanged(const QString &name, const QString &oldOwner, |
560 | const QString &newOwner); // slot |
561 | void timeout(); // slot |
562 | |
563 | GetLockJob *const q; |
564 | QTimer *mSafetyTimer; |
565 | }; |
566 | |
567 | GetLockJob::Private::Private(GetLockJob *qq) |
568 | : q(qq) |
569 | , mSafetyTimer(0) |
570 | { |
571 | } |
572 | |
573 | void GetLockJob::Private::doStart() |
574 | { |
575 | // Just doing registerService() and checking its return value is not sufficient, |
576 | // since we may *already* own the name, and then registerService() returns true. |
577 | |
578 | QDBusConnection bus = DBusConnectionPool::threadConnection(); |
579 | const bool alreadyLocked = bus.interface()->isServiceRegistered(dbusServiceName()); |
580 | const bool gotIt = bus.registerService(dbusServiceName()); |
581 | |
582 | if (gotIt && !alreadyLocked) { |
583 | //kDebug() << "Got lock immediately."; |
584 | q->emitResult(); |
585 | } else { |
586 | QDBusServiceWatcher *watcher = new QDBusServiceWatcher(dbusServiceName(), DBusConnectionPool::threadConnection(), |
587 | QDBusServiceWatcher::WatchForOwnerChange, q); |
588 | //kDebug() << "Waiting for lock."; |
589 | connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), |
590 | q, SLOT(serviceOwnerChanged(QString,QString,QString))); |
591 | |
592 | mSafetyTimer = new QTimer(q); |
593 | mSafetyTimer->setSingleShot(true); |
594 | mSafetyTimer->setInterval(LOCK_WAIT_TIMEOUT_SECONDS * 1000); |
595 | mSafetyTimer->start(); |
596 | connect(mSafetyTimer, SIGNAL(timeout()), q, SLOT(timeout())); |
597 | } |
598 | } |
599 | |
600 | void GetLockJob::Private::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) |
601 | { |
602 | if (newOwner.isEmpty()) { |
603 | const bool gotIt = DBusConnectionPool::threadConnection().registerService(dbusServiceName()); |
604 | if (gotIt) { |
605 | mSafetyTimer->stop(); |
606 | q->emitResult(); |
607 | } |
608 | } |
609 | } |
610 | |
611 | void GetLockJob::Private::timeout() |
612 | { |
613 | kWarning() << "Timeout trying to get lock. Check who has acquired the name" << dbusServiceName() << "on DBus, using qdbus or qdbusviewer." ; |
614 | q->setError(Job::Unknown); |
615 | q->setErrorText(i18n("Timeout trying to get lock." )); |
616 | q->emitResult(); |
617 | } |
618 | |
619 | GetLockJob::GetLockJob(QObject *parent) |
620 | : KJob(parent) |
621 | , d(new Private(this)) |
622 | { |
623 | } |
624 | |
625 | GetLockJob::~GetLockJob() |
626 | { |
627 | delete d; |
628 | } |
629 | |
630 | void GetLockJob::start() |
631 | { |
632 | QTimer::singleShot(0, this, SLOT(doStart())); |
633 | } |
634 | |
635 | void Akonadi::setCollectionAttributes(Akonadi::Collection &collection, const QByteArray &type, |
636 | const QMap<QByteArray, QString> &nameForType, |
637 | const QMap<QByteArray, QString> &iconForType) |
638 | { |
639 | { |
640 | EntityDisplayAttribute *attr = new EntityDisplayAttribute; |
641 | attr->setIconName(iconForType.value(type)); |
642 | attr->setDisplayName(nameForType.value(type)); |
643 | collection.addAttribute(attr); |
644 | } |
645 | |
646 | { |
647 | SpecialCollectionAttribute *attr = new SpecialCollectionAttribute; |
648 | attr->setCollectionType(type); |
649 | collection.addAttribute(attr); |
650 | } |
651 | } |
652 | |
653 | bool Akonadi::releaseLock() |
654 | { |
655 | return DBusConnectionPool::threadConnection().unregisterService(dbusServiceName()); |
656 | } |
657 | |
658 | #include "moc_specialcollectionshelperjobs_p.cpp" |
659 | |