24 #include "kalarmsettings.h"
25 #include "kalarmdirsettings.h"
29 #include <kalarmcal/collectionattribute.h>
30 #include <kalarmcal/compatibilityattribute.h>
31 #include <kalarmcal/version.h>
33 #include <akonadi/agentinstancecreatejob.h>
34 #include <akonadi/agentmanager.h>
35 #include <akonadi/collectionfetchjob.h>
36 #include <akonadi/collectionfetchscope.h>
37 #include <akonadi/collectionmodifyjob.h>
38 #include <akonadi/entitydisplayattribute.h>
39 #include <akonadi/resourcesynchronizationjob.h>
42 #include <kconfiggroup.h>
43 #include <kstandarddirs.h>
48 using namespace Akonadi;
49 using namespace KAlarmCal;
53 class CalendarCreator :
public QObject
58 CalendarCreator(
const QString& resourceType,
const KConfigGroup&);
60 CalendarCreator(CalEvent::Type,
const QString& file,
const QString& name);
61 bool isValid()
const {
return mAlarmType != CalEvent::EMPTY; }
62 CalEvent::Type alarmType()
const {
return mAlarmType; }
63 bool newCalendar()
const {
return mNew; }
64 QString resourceName()
const {
return mName; }
65 Collection::Id collectionId()
const {
return mCollectionId; }
66 QString path()
const {
return mPath; }
67 QString errorMessage()
const {
return mErrorMessage; }
71 void agentCreated(
KJob*);
74 void creating(
const QString& path);
75 void finished(CalendarCreator*);
78 void fetchCollection();
79 void collectionFetchResult(
KJob*);
80 void resourceSynchronised(
KJob*);
81 void modifyCollectionJobDone(
KJob*);
84 void finish(
bool cleanup);
85 bool writeLocalFileConfig();
86 bool writeLocalDirectoryConfig();
87 bool writeRemoteFileConfig();
88 template <
class Interface> Interface* writeBasicConfig();
90 enum ResourceType { LocalFile, LocalDir, RemoteFile };
93 CalEvent::Type mAlarmType;
94 ResourceType mResourceType;
99 Collection::Id mCollectionId;
100 int mCollectionFetchRetryCount;
109 class CalendarUpdater :
public QObject
113 CalendarUpdater(
const Collection& collection,
bool dirResource,
114 bool ignoreKeepFormat,
bool newCollection,
QObject* parent);
117 bool isDuplicate()
const {
return mDuplicate; }
119 static bool containsCollection(Collection::Id);
126 Akonadi::Collection mCollection;
128 const bool mDirResource;
129 const bool mIgnoreKeepFormat;
130 const bool mNewCollection;
131 const bool mDuplicate;
136 bool CalendarMigrator::mCompleted =
false;
138 CalendarMigrator::CalendarMigrator(
QObject* parent)
140 mExistingAlarmTypes(0)
163 if (!mInstance && !mCompleted)
179 void CalendarMigrator::migrateOrCreate()
185 const AgentInstance::List agents = AgentManager::self()->instances();
186 foreach (
const AgentInstance& agent, agents)
188 const QString type = agent.type().identifier();
193 CollectionFetchJob* job =
new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
194 job->fetchScope().setResource(agent.identifier());
195 mFetchesPending << job;
196 connect(job, SIGNAL(result(
KJob*)), SLOT(collectionFetchResult(
KJob*)));
206 const QString configFile = KStandardDirs::locateLocal(
"config",
QLatin1String(
"kresources/alarms/stdrc"));
207 const KConfig config(configFile, KConfig::SimpleConfig);
210 const KConfigGroup group = config.group(
"General");
212 + group.readEntry(
"PassiveResourceKeys",
QStringList());
215 CalendarCreator* creator;
216 foreach (
const QString&
id, keys)
218 const KConfigGroup configGroup = config.group(
QLatin1String(
"Resource_") +
id);
219 const QString resourceType = configGroup.readEntry(
"ResourceType",
QString());
230 creator =
new CalendarCreator(resourceType, configGroup);
231 if (!creator->isValid())
235 connect(creator, SIGNAL(finished(CalendarCreator*)), SLOT(calendarCreated(CalendarCreator*)));
237 mExistingAlarmTypes |= creator->alarmType();
238 mCalendarsPending << creator;
239 creator->createAgent(agentType,
this);
245 createDefaultResources();
253 void CalendarMigrator::collectionFetchResult(
KJob* j)
255 CollectionFetchJob* job =
static_cast<CollectionFetchJob*
>(j);
256 const QString id = job->fetchScope().resource();
258 kError() <<
"CollectionFetchJob" <<
id <<
"error: " << j->errorString();
261 const Collection::List collections = job->collections();
262 if (collections.isEmpty())
263 kError() <<
"No collections found for resource" << id;
265 mExistingAlarmTypes |= CalEvent::types(collections[0].contentMimeTypes());
273 createDefaultResources();
284 void CalendarMigrator::createDefaultResources()
287 CalendarCreator* creator;
288 if (!(mExistingAlarmTypes & CalEvent::ACTIVE))
290 creator =
new CalendarCreator(CalEvent::ACTIVE,
QLatin1String(
"calendar.ics"), i18nc(
"@info/plain",
"Active Alarms"));
291 connect(creator, SIGNAL(finished(CalendarCreator*)), SLOT(calendarCreated(CalendarCreator*)));
293 mCalendarsPending << creator;
294 creator->createAgent(
QLatin1String(
"akonadi_kalarm_resource"),
this);
296 if (!(mExistingAlarmTypes & CalEvent::ARCHIVED))
298 creator =
new CalendarCreator(CalEvent::ARCHIVED,
QLatin1String(
"expired.ics"), i18nc(
"@info/plain",
"Archived Alarms"));
299 connect(creator, SIGNAL(finished(CalendarCreator*)), SLOT(calendarCreated(CalendarCreator*)));
301 mCalendarsPending << creator;
302 creator->createAgent(
QLatin1String(
"akonadi_kalarm_resource"),
this);
304 if (!(mExistingAlarmTypes & CalEvent::TEMPLATE))
306 creator =
new CalendarCreator(CalEvent::TEMPLATE,
QLatin1String(
"template.ics"), i18nc(
"@info/plain",
"Alarm Templates"));
307 connect(creator, SIGNAL(finished(CalendarCreator*)), SLOT(calendarCreated(CalendarCreator*)));
309 mCalendarsPending << creator;
310 creator->createAgent(
QLatin1String(
"akonadi_kalarm_resource"),
this);
313 if (mCalendarsPending.
isEmpty())
324 void CalendarMigrator::creatingCalendar(
const QString& path)
333 void CalendarMigrator::calendarCreated(CalendarCreator* creator)
335 int i = mCalendarsPending.
indexOf(creator);
339 emit
creating(creator->path(), creator->collectionId(),
true);
341 if (!creator->errorMessage().isEmpty())
343 QString errmsg = creator->newCalendar()
344 ? i18nc(
"@info/plain",
"Failed to create default calendar <resource>%1</resource>", creator->resourceName())
345 : i18nc(
"@info/plain 'Import Alarms' is the name of a menu option",
346 "Failed to convert old configuration for calendar <resource>%1</resource>. "
347 "Please use Import Alarms to load its alarms into a new or existing calendar.", creator->resourceName());
348 const QString locn = i18nc(
"@info/plain File path or URL",
"Location: %1", creator->path());
349 if (creator->errorMessage().isEmpty())
350 errmsg = i18nc(
"@info",
"<para>%1</para><para>%2</para>", errmsg, locn);
352 errmsg = i18nc(
"@info",
"<para>%1</para><para>%2<nl/>(%3)</para>", errmsg, locn, creator->errorMessage());
355 creator->deleteLater();
358 if (mCalendarsPending.
isEmpty())
377 kDebug() << collection.id();
378 if (CalendarUpdater::containsCollection(collection.id()))
380 const AgentInstance agent = AgentManager::self()->instance(collection.resource());
381 const QString id = agent.type().identifier();
389 kError() <<
"Invalid agent type" << id;
399 CalendarUpdater::CalendarUpdater(
const Collection& collection,
bool dirResource,
400 bool ignoreKeepFormat,
bool newCollection,
QObject* parent)
401 : mCollection(collection),
403 mDirResource(dirResource),
404 mIgnoreKeepFormat(ignoreKeepFormat),
405 mNewCollection(newCollection),
406 mDuplicate(containsCollection(collection.id()))
408 mInstances.append(
this);
411 CalendarUpdater::~CalendarUpdater()
413 mInstances.removeAll(
this);
416 bool CalendarUpdater::containsCollection(Collection::Id
id)
418 for (
int i = 0, count = mInstances.count(); i < count; ++i)
420 if (mInstances[i]->mCollection.id() == id)
426 bool CalendarUpdater::update()
428 kDebug() << mCollection.id() << (mDirResource ?
"directory" :
"file");
431 && mCollection.hasAttribute<CompatibilityAttribute>())
433 const CompatibilityAttribute* compatAttr = mCollection.attribute<CompatibilityAttribute>();
434 const KACalendar::Compat compatibility = compatAttr->compatibility();
435 if ((compatibility & ~KACalendar::Converted)
437 && !(compatibility & ~(KACalendar::Convertible | KACalendar::Converted)))
440 if (!mIgnoreKeepFormat
441 && mCollection.hasAttribute<CollectionAttribute>()
442 && mCollection.attribute<CollectionAttribute>()->keepFormat())
443 kDebug() <<
"Not updating format (previous user choice)";
447 const QString versionString = KAlarmCal::getVersionString(compatAttr->version());
448 const QString msg = KAlarm::conversionPrompt(mCollection.name(), versionString,
false);
449 kDebug() <<
"Version" << versionString;
461 errmsg = i18nc(
"@info/plain",
"Invalid collection");
465 const AgentInstance agent = AgentManager::self()->instance(mCollection.resource());
467 CalendarMigrator::updateStorageFormat<OrgKdeAkonadiKAlarmDirSettingsInterface>(agent, errmsg, mParent);
469 CalendarMigrator::updateStorageFormat<OrgKdeAkonadiKAlarmSettingsInterface>(agent, errmsg, mParent);
474 i18nc(
"@info",
"%1<nl/>(%2)",
475 i18nc(
"@info/plain",
"Failed to update format of calendar <resource>%1</resource>", mCollection.name()),
497 template <
class Interface>
bool CalendarMigrator::updateStorageFormat(
const AgentInstance& agent,
QString& errorMessage,
QObject* parent)
500 Interface* iface = getAgentInterface<Interface>(agent, errorMessage,
parent);
503 kDebug() << errorMessage;
506 iface->setUpdateStorageFormat(
true);
507 iface->writeConfig();
520 Interface* iface =
new Interface(
QLatin1String(
"org.freedesktop.Akonadi.Resource.") + agent.identifier(),
522 if (!iface->isValid())
524 errorMessage = iface->lastError().message();
525 kDebug() <<
"D-Bus error accessing resource:" << errorMessage;
536 CalendarCreator::CalendarCreator(
const QString& resourceType,
const KConfigGroup& config)
537 : mAlarmType(CalEvent::EMPTY),
542 const char* pathKey = 0;
545 mResourceType = LocalFile;
546 pathKey =
"CalendarURL";
550 mResourceType = LocalDir;
551 pathKey =
"CalendarURL";
555 mResourceType = RemoteFile;
556 pathKey =
"DownloadUrl";
560 kError() <<
"Invalid resource type:" << resourceType;
564 switch (config.readEntry(
"AlarmType", (
int)0))
566 case 1: mAlarmType = CalEvent::ACTIVE;
break;
567 case 2: mAlarmType = CalEvent::ARCHIVED;
break;
568 case 4: mAlarmType = CalEvent::TEMPLATE;
break;
570 kError() <<
"Invalid alarm type for resource";
573 mName = config.readEntry(
"ResourceName",
QString());
574 mColour = config.readEntry(
"Color",
QColor());
575 mReadOnly = config.readEntry(
"ResourceIsReadOnly",
true);
576 mEnabled = config.readEntry(
"ResourceIsActive",
false);
577 mStandard = config.readEntry(
"Standard",
false);
578 kDebug() <<
"Migrating:" << mName <<
", type=" << mAlarmType <<
", path=" << mPath;
585 CalendarCreator::CalendarCreator(CalEvent::Type alarmType,
const QString& file,
const QString& name)
586 : mAlarmType(alarmType),
587 mResourceType(LocalFile),
596 mPath = KStandardDirs::locateLocal(
"appdata", file);
597 kDebug() <<
"New:" << mName <<
", type=" << mAlarmType <<
", path=" << mPath;
603 void CalendarCreator::createAgent(
const QString& agentType,
QObject* parent)
605 emit creating(mPath);
606 AgentInstanceCreateJob* job =
new AgentInstanceCreateJob(agentType, parent);
607 connect(job, SIGNAL(result(
KJob*)), SLOT(agentCreated(
KJob*)));
615 void CalendarCreator::agentCreated(
KJob* j)
619 mErrorMessage = j->errorString();
620 kError() <<
"AgentInstanceCreateJob error:" << mErrorMessage;
627 AgentInstanceCreateJob* job =
static_cast<AgentInstanceCreateJob*
>(j);
628 mAgent = job->instance();
629 mAgent.setName(mName);
631 switch (mResourceType)
634 ok = writeLocalFileConfig();
637 ok = writeLocalDirectoryConfig();
640 ok = writeRemoteFileConfig();
643 kError() <<
"Invalid resource type";
651 mAgent.reconfigure();
654 ResourceSynchronizationJob* sjob =
new ResourceSynchronizationJob(mAgent);
655 connect(sjob, SIGNAL(result(
KJob*)), SLOT(resourceSynchronised(
KJob*)));
663 void CalendarCreator::resourceSynchronised(
KJob* j)
669 kError() <<
"ResourceSynchronizationJob error: " << j->errorString();
671 mCollectionFetchRetryCount = 0;
678 void CalendarCreator::fetchCollection()
680 CollectionFetchJob* job =
new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
681 job->fetchScope().setResource(mAgent.identifier());
682 connect(job, SIGNAL(result(
KJob*)), SLOT(collectionFetchResult(
KJob*)));
686 bool CalendarCreator::writeLocalFileConfig()
688 OrgKdeAkonadiKAlarmSettingsInterface* iface = writeBasicConfig<OrgKdeAkonadiKAlarmSettingsInterface>();
691 iface->setMonitorFile(
true);
692 iface->writeConfig();
697 bool CalendarCreator::writeLocalDirectoryConfig()
699 OrgKdeAkonadiKAlarmDirSettingsInterface* iface = writeBasicConfig<OrgKdeAkonadiKAlarmDirSettingsInterface>();
702 iface->setMonitorFiles(
true);
703 iface->writeConfig();
708 bool CalendarCreator::writeRemoteFileConfig()
710 OrgKdeAkonadiKAlarmSettingsInterface* iface = writeBasicConfig<OrgKdeAkonadiKAlarmSettingsInterface>();
713 iface->setMonitorFile(
true);
714 iface->writeConfig();
719 template <
class Interface> Interface* CalendarCreator::writeBasicConfig()
721 Interface* iface = CalendarMigrator::getAgentInterface<Interface>(mAgent, mErrorMessage,
this);
724 iface->setReadOnly(mReadOnly);
725 iface->setDisplayName(mName);
726 iface->setPath(mPath);
727 iface->setAlarmTypes(CalEvent::mimeTypes(mAlarmType));
728 iface->setUpdateStorageFormat(
false);
737 void CalendarCreator::collectionFetchResult(
KJob* j)
742 mErrorMessage = j->errorString();
743 kError() <<
"CollectionFetchJob error: " << mErrorMessage;
747 CollectionFetchJob* job =
static_cast<CollectionFetchJob*
>(j);
748 const Collection::List collections = job->collections();
749 if (collections.isEmpty())
751 if (++mCollectionFetchRetryCount >= 10)
753 mErrorMessage = i18nc(
"@info/plain",
"New configuration timed out");
754 kError() <<
"Timeout fetching collection for resource";
760 kDebug() <<
"Retrying";
764 if (collections.count() > 1)
766 mErrorMessage = i18nc(
"@info/plain",
"New configuration was corrupt");
767 kError() <<
"Wrong number of collections for this resource:" << collections.count();
773 Collection collection = collections[0];
774 mCollectionId = collection.id();
775 collection.setContentMimeTypes(CalEvent::mimeTypes(mAlarmType));
776 EntityDisplayAttribute* dattr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
778 CollectionAttribute* attr = collection.attribute<CollectionAttribute>(Entity::AddIfMissing);
779 attr->setEnabled(mEnabled ? mAlarmType : CalEvent::EMPTY);
781 attr->setStandard(mAlarmType);
782 if (mColour.isValid())
783 attr->setBackgroundColor(mColour);
787 bool dirResource =
false;
788 switch (mResourceType)
801 bool duplicate =
false;
804 CalendarUpdater* updater =
new CalendarUpdater(collection, dirResource,
false,
true,
this);
805 duplicate = updater->isDuplicate();
806 keep = !updater->update();
811 attr->setKeepFormat(keep);
819 Collection c(collection.id());
820 CollectionAttribute* att = c.attribute<CollectionAttribute>(Entity::AddIfMissing);
822 CollectionModifyJob* cmjob =
new CollectionModifyJob(c,
this);
823 connect(cmjob, SIGNAL(result(
KJob*)),
this, SLOT(modifyCollectionJobDone(
KJob*)));
830 void CalendarCreator::modifyCollectionJobDone(
KJob* j)
832 Collection collection =
static_cast<CollectionModifyJob*
>(j)->collection();
835 mErrorMessage = j->errorString();
836 kError() <<
"CollectionFetchJob error: " << mErrorMessage;
841 kDebug() <<
"Completed:" << mName;
850 void CalendarCreator::finish(
bool cleanup)
855 AgentManager::self()->removeInstance(mAgent);
861 #include "calendarmigrator.moc"
void creating(const QString &path, Akonadi::Collection::Id id, bool finished)
Signal emitted when a resource is about to be created, and when creation has completed (successfully ...
static void updateToCurrentFormat(const Akonadi::Collection &, bool ignoreKeepFormat, QWidget *parent)
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
QDBusConnection sessionBus()
QModelIndex collectionIndex(Akonadi::Collection::Id id) const
int indexOf(const T &value, int from) const
static Interface * getAgentInterface(const Akonadi::AgentInstance &, QString &errorMessage, QObject *parent)
static AkonadiModel * instance()
int removeAll(const T &value)
static CalendarMigrator * instance()
friend class CalendarUpdater
static int warningYesNo(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous|WindowModal))
static MainWindow * mainMainWindow()
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Class to migrate KResources alarm calendars from pre-Akonadi versions of KAlarm, and to create defaul...
virtual bool setData(const QModelIndex &, const QVariant &value, int role)