Commit 028b483f authored by David Jarvie's avatar David Jarvie
Browse files

Move Akonadi resource migration to the Akonadi plugin

parent c993655c
......@@ -39,16 +39,13 @@ endif()
set(KDEPIM_VERSION "${PIM_VERSION}${KDEPIM_DEV_VERSION} (${RELEASE_SERVICE_VERSION})")
set(KIMAP_LIB_VERSION "5.20.40")
set(AKONADI_VERSION "5.20.40")
set(AKONADI_MIMELIB_VERSION "5.20.40")
set(AKONADI_CONTACT_VERSION "5.20.40")
set(KMAILTRANSPORT_LIB_VERSION "5.20.40")
set(KPIMTEXTEDIT_LIB_VERSION "5.20.40")
set(IDENTITYMANAGEMENT_LIB_VERSION "5.20.40")
set(AKONADI_VERSION "5.20.40")
set(KMIME_LIB_VERSION "5.20.40")
set(AKONADIKALARM_LIB_VERSION "5.20.40")
set(PIMCOMMON_LIB_VERSION "5.20.40")
set(KDEPIM_LIB_VERSION "${PIM_VERSION}")
set(KDEPIM_LIB_SOVERSION "5")
......@@ -57,9 +54,11 @@ set(QT_REQUIRED_VERSION "5.15.2")
find_package(Qt${QT_MAJOR_VERSION} ${QT_REQUIRED_VERSION} CONFIG REQUIRED DBus Gui Network Widgets)
set(CALENDARUTILS_LIB_VERSION "5.20.40")
option(FILE_RESOURCES "Use file system resources instead of Akonadi resources." TRUE)
option(ENABLE_AKONADI_PLUGIN "Build the Akonadi plugin" ON)
add_feature_info(AKONADI_PLUGIN ${ENABLE_AKONADI_PLUGIN} "Provides features dependent on Akonadi (including birthday import,
email functions, email address book, first run resource migration)")
option (ENABLE_WAKE_FROM_SUSPEND "Enable wake-from-suspend alarms (requires KAuth)" ON)
option(ENABLE_WAKE_FROM_SUSPEND "Enable wake-from-suspend alarms (requires KAuth)" ON)
if (ENABLE_WAKE_FROM_SUSPEND)
find_package(KF5Auth ${KF5_MIN_VERSION})
if (NOT KF5Auth_FOUND)
......@@ -74,6 +73,7 @@ find_package(KF5Codecs ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5Completion ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5Config ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5ConfigWidgets ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5Contacts ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5Crash ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5DBusAddons ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5GlobalAccel ${KF5_MIN_VERSION} REQUIRED)
......@@ -81,6 +81,7 @@ find_package(KF5GuiAddons ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5Holidays ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5I18n ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5IdleTime ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5ItemModels ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5JobWidgets ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5KCMUtils ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG REQUIRED)
......@@ -98,18 +99,18 @@ set_package_properties(KF5DocTools PROPERTIES DESCRIPTION
TYPE OPTIONAL
)
# Find KDE PIM packages
find_package(KF5IMAP ${KIMAP_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiContact ${AKONADI_CONTACT_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiMime ${AKONADI_MIMELIB_VERSION} CONFIG REQUIRED)
find_package(KF5CalendarUtils ${CALENDARUTILS_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5MailTransportAkonadi ${KMAILTRANSPORT_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5PimCommon ${PIMCOMMON_LIB_VERSION} CONFIG REQUIRED)
find_package(KF5PimTextEdit ${KPIMTEXTEDIT_LIB_VERSION} CONFIG REQUIRED)
if (ENABLE_AKONADI_PLUGIN)
find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiContact ${AKONADI_CONTACT_VERSION} CONFIG REQUIRED)
find_package(KF5AkonadiMime ${AKONADI_MIMELIB_VERSION} CONFIG REQUIRED)
endif()
configure_file(kalarm-version-string.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kalarm-version-string.h @ONLY)
......
......@@ -4,31 +4,33 @@ include_directories(
)
add_subdirectory(kalarmcalendar)
add_subdirectory(akonadiplugin)
if (ENABLE_AKONADI_PLUGIN)
add_subdirectory(akonadiplugin)
endif()
add_subdirectory(appicons)
add_subdirectory(pixmaps)
add_subdirectory(autostart)
########### next target ###############
set(kalarmplugin_common_SRCS)
set(kalarmpluginlib_common_SRCS)
ecm_qt_declare_logging_category(kalarmplugin_common_SRCS
HEADER kalarmplugin_debug.h
IDENTIFIER KALARMPLUGIN_LOG
CATEGORY_NAME org.kde.pim.kalarm.plugin
DESCRIPTION "kalarm (plugin)"
EXPORT KALARMPLUGIN
ecm_qt_declare_logging_category(kalarmpluginlib_common_SRCS
HEADER kalarmpluginlib_debug.h
IDENTIFIER KALARMPLUGINLIB_LOG
CATEGORY_NAME org.kde.pim.kalarm.pluginlib
DESCRIPTION "kalarm (pluginlib)"
EXPORT KALARMPLUGINLIB
)
add_library(kalarmplugin)
target_sources(kalarmplugin PRIVATE
${kalarmplugin_common_SRCS}
${kalarmpluginlib_common_SRCS}
pluginbase.cpp
pluginmanager.cpp
)
generate_export_header(kalarmplugin BASE_NAME kalarmplugin)
generate_export_header(kalarmplugin BASE_NAME kalarmpluginlib)
target_link_libraries(kalarmplugin PRIVATE
kalarmcalendar
......@@ -137,8 +139,6 @@ set(resources_SRCS
resources/fileresourcecalendarupdater.cpp
resources/singlefileresource.cpp
resources/singlefileresourceconfigdialog.cpp
resources/migration/collectionattribute.cpp
resources/migration/compatibilityattribute.cpp
resources/migration/dirresourceimportdialog.cpp
resources/migration/fileresourcemigrator.cpp
resources/calendarfunctions.h
......@@ -160,8 +160,6 @@ set(resources_SRCS
resources/fileresourcecalendarupdater.h
resources/singlefileresource.h
resources/singlefileresourceconfigdialog.h
resources/migration/collectionattribute.h
resources/migration/compatibilityattribute.h
resources/migration/dirresourceimportdialog.h
resources/migration/fileresourcemigrator.h
)
......@@ -324,8 +322,6 @@ target_link_libraries(kalarm_bin
KF5::KIOFileWidgets
KF5::Crash
Phonon::phonon4qt${QT_MAJOR_VERSION}
KF5::AkonadiCore
KF5::AkonadiMime
KF5::CalendarCore
KF5::CalendarUtils
KF5::Contacts
......@@ -334,7 +330,6 @@ target_link_libraries(kalarm_bin
KF5::MailTransportAkonadi
KF5::MailTransport
KF5::Mime
KF5::PimCommon
)
if (ENABLE_WAKE_FROM_SUSPEND)
......
......@@ -8,10 +8,14 @@ kcoreaddons_add_plugin(akonadiplugin
SOURCES
akonadiplugin.cpp
akonadicollectionsearch.cpp
akonadiresourcemigrator.cpp
birthdaymodel.cpp
collectionattribute.cpp
akonadiplugin.h
akonadicollectionsearch.h
akonadiresourcemigrator.h
birthdaymodel.h
collectionattribute.h
INSTALL_NAMESPACE "kalarm"
)
......@@ -19,27 +23,25 @@ set_target_properties(akonadiplugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE
ecm_qt_declare_logging_category(akonadiplugin
HEADER akonadiplugin_debug.h
IDENTIFIER AKONADIPLUGIN_LOG
IDENTIFIER AKONADIPLUGIN_LOG
CATEGORY_NAME org.kde.pim.kalarm.akonadiplugin
DEFAULT_SEVERITY Warning
DESCRIPTION "kalarm (akonadi plugin)"
EXPORT AKONADIPLUGIN
EXPORT AKONADIPLUGIN
)
generate_export_header(akonadiplugin BASE_NAME akonadiplugin)
target_link_libraries(akonadiplugin
kalarmplugin
# KF5::Completion
kalarmcalendar
KF5::CalendarCore
KF5::I18n
KF5::Mime
# KF5::XmlGui
KF5::AkonadiCore
KF5::AkonadiMime
KF5::AkonadiContact
KF5::AkonadiWidgets
KF5::MailTransportAkonadi
KF5::MailTransport
# KF5::PimCommon
)
......@@ -158,6 +158,25 @@ void AkonadiPlugin::deleteEvent(const QString& mimeType, const QString& gid, con
new AkonadiCollectionSearch(mimeType, gid, uid, true); // this auto-deletes when complete
}
void AkonadiPlugin::initiateAkonadiResourceMigration()
{
AkonadiResourceMigrator* akonadiMigrator = AkonadiResourceMigrator::instance();
if (akonadiMigrator)
{
connect(akonadiMigrator, &AkonadiResourceMigrator::migrationComplete, this, &AkonadiPlugin::akonadiMigrationComplete);
connect(akonadiMigrator, &AkonadiResourceMigrator::fileResource, this, &AkonadiPlugin::migrateFileResource);
connect(akonadiMigrator, &AkonadiResourceMigrator::dirResource, this, &AkonadiPlugin::migrateDirResource);
akonadiMigrator->initiateMigration();
}
}
void AkonadiPlugin::deleteAkonadiResource(const QString& resourceName)
{
AkonadiResourceMigrator* akonadiMigrator = AkonadiResourceMigrator::instance();
if (akonadiMigrator)
akonadiMigrator->deleteAkonadiResource(resourceName);
}
#include "akonadiplugin.moc"
// vim: et sw=4:
......@@ -44,6 +44,14 @@ public:
/** Delete a KOrganizer event. */
void deleteEvent(const QString& mimeType, const QString& gid = {}, const QString& uid = {}) override;
/** Initiate Akonadi resource migration. */
void initiateAkonadiResourceMigration() override;
/** Delete a named Akonadi resource.
* This should be called after the resource has been migrated.
*/
void deleteAkonadiResource(const QString& resourceName) override;
};
// vim: et sw=4:
/*
* akonadiresourcemigrator.cpp - migrates KAlarm Akonadi resources
* Program: kalarm
* SPDX-FileCopyrightText: 2011-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "akonadiresourcemigrator.h"
#include "collectionattribute.h"
#include "akonadiplugin_debug.h"
#include <Akonadi/AgentManager>
#include <Akonadi/AttributeFactory>
#include <Akonadi/CollectionFetchJob>
#include <Akonadi/CollectionFetchScope>
#include <Akonadi/CollectionModifyJob>
using namespace KAlarmCal;
//clazy:excludeall=non-pod-global-static
namespace
{
const QString KALARM_RESOURCE(QStringLiteral("akonadi_kalarm_resource"));
const QString KALARM_DIR_RESOURCE(QStringLiteral("akonadi_kalarm_dir_resource"));
// Holds an Akonadi collection's properties.
struct CollectionProperties
{
QColor backgroundColour;
CalEvent::Types alarmTypes;
CalEvent::Types enabledTypes {CalEvent::EMPTY};
CalEvent::Types standardTypes {CalEvent::EMPTY};
bool readOnly;
// Fetch the properties of a collection which has been fetched by CollectionFetchJob.
explicit CollectionProperties(const Akonadi::Collection&);
};
const Akonadi::Collection::Rights WritableRights = Akonadi::Collection::CanChangeItem | Akonadi::Collection::CanCreateItem | Akonadi::Collection::CanDeleteItem;
}
AkonadiResourceMigrator* AkonadiResourceMigrator::mInstance = nullptr;
bool AkonadiResourceMigrator::mCompleted = false;
/******************************************************************************
* Constructor.
*/
AkonadiResourceMigrator::AkonadiResourceMigrator(QObject* parent)
: QObject(parent)
{
}
AkonadiResourceMigrator::~AkonadiResourceMigrator()
{
qCDebug(AKONADIPLUGIN_LOG) << "~AkonadiResourceMigrator";
mInstance = nullptr;
mCompleted = true;
}
/******************************************************************************
* Create and return the unique AkonadiResourceMigrator instance.
*/
AkonadiResourceMigrator* AkonadiResourceMigrator::instance()
{
if (!mInstance && !mCompleted)
mInstance = new AkonadiResourceMigrator;
return mInstance;
}
/******************************************************************************
* Initiate migration of old Akonadi calendars, and create default file system
* resources.
*/
void AkonadiResourceMigrator::initiateMigration()
{
connect(Akonadi::ServerManager::self(), &Akonadi::ServerManager::stateChanged, this, &AkonadiResourceMigrator::checkServer);
auto akstate = Akonadi::ServerManager::state();
mAkonadiStarted = (akstate == Akonadi::ServerManager::NotRunning);
checkServer(akstate);
}
/******************************************************************************
* Called when the Akonadi server manager changes state.
* Once it is running, migrate any Akonadi KAlarm resources.
*/
void AkonadiResourceMigrator::checkServer(Akonadi::ServerManager::State state)
{
switch (state)
{
case Akonadi::ServerManager::Running:
migrateResources();
break;
case Akonadi::ServerManager::Stopping:
// Wait until the server has stopped, so that we can restart it.
return;
default:
if (Akonadi::ServerManager::start())
return; // wait for the server to change to Running state
// Can't start Akonadi, so give up trying to migrate.
qCWarning(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::checkServer: Failed to start Akonadi server";
terminate(false);
break;
}
disconnect(Akonadi::ServerManager::self(), nullptr, this, nullptr);
}
/******************************************************************************
* Initiate migration of Akonadi KAlarm resources.
* Reply = true if migration initiated;
* = false if no KAlarm Akonadi resources found.
*/
void AkonadiResourceMigrator::migrateResources()
{
qCDebug(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::migrateResources: initiated";
mCollectionPaths.clear();
mFetchesPending.clear();
Akonadi::AttributeFactory::registerAttribute<CollectionAttribute>();
// Create jobs to fetch all KAlarm Akonadi collections.
bool migrating = false;
const Akonadi::AgentInstance::List agents = Akonadi::AgentManager::self()->instances();
for (const Akonadi::AgentInstance& agent : agents)
{
const QString type = agent.type().identifier();
if (type == KALARM_RESOURCE || type == KALARM_DIR_RESOURCE)
{
Akonadi::CollectionFetchJob* job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::FirstLevel);
job->fetchScope().setResource(agent.identifier());
mFetchesPending[job] = (type == KALARM_DIR_RESOURCE);
connect(job, &KJob::result, this, &AkonadiResourceMigrator::collectionFetchResult);
migrating = true;
}
}
if (!migrating)
terminate(false); // there are no Akonadi resources to migrate
}
/******************************************************************************
* Called when an Akonadi collection fetch job has completed.
* Check for, and remove, any Akonadi resources which duplicate use of calendar
* files/directories.
*/
void AkonadiResourceMigrator::collectionFetchResult(KJob* j)
{
auto job = qobject_cast<Akonadi::CollectionFetchJob*>(j);
const QString id = job->fetchScope().resource();
if (j->error())
qCCritical(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::collectionFetchResult: CollectionFetchJob" << id << "error: " << j->errorString();
else
{
const Akonadi::Collection::List collections = job->collections();
if (collections.isEmpty())
qCCritical(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::collectionFetchResult: No collections found for resource" << id;
else
{
// Note that a KAlarm Akonadi agent contains only one collection.
const Akonadi::Collection& collection(collections[0]);
const bool dirType = mFetchesPending.value(job, false);
const AkResourceData thisRes(job->fetchScope().resource(), collection, dirType);
bool saveThis = true;
auto it = mCollectionPaths.constFind(collection.remoteId());
if (it != mCollectionPaths.constEnd())
{
// Remove the resource which, in decreasing order of priority:
// - Is disabled;
// - Is not a standard resource;
// - Contains the higher numbered Collection ID, which is likely
// to be the more recently created.
const AkResourceData prevRes = it.value();
const CollectionProperties properties[2] = { CollectionProperties(prevRes.collection),
CollectionProperties(thisRes.collection) };
int propToUse = (thisRes.collection.id() < prevRes.collection.id()) ? 1 : 0;
if (properties[1 - propToUse].standardTypes && !properties[propToUse].standardTypes)
propToUse = 1 - propToUse;
if (properties[1 - propToUse].enabledTypes && !properties[propToUse].enabledTypes)
propToUse = 1 - propToUse;
saveThis = (propToUse == 1);
const auto resourceToRemove = saveThis ? prevRes.resourceId : thisRes.resourceId;
qCWarning(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::collectionFetchResult: Removing duplicate resource" << resourceToRemove;
Akonadi::AgentManager* agentManager = Akonadi::AgentManager::self();
agentManager->removeInstance(agentManager->instance(resourceToRemove));
}
if (saveThis)
mCollectionPaths[collection.remoteId()] = thisRes;
}
}
mFetchesPending.remove(job);
if (mFetchesPending.isEmpty())
{
// De-duplication is complete. Migrate the remaining Akonadi resources.
doMigrateResources();
}
}
/******************************************************************************
* Migrate Akonadi KAlarm resources to file system resources.
*/
void AkonadiResourceMigrator::doMigrateResources()
{
qCDebug(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::doMigrateResources";
// First, migrate KAlarm calendar file Akonadi resources.
// This will allow any KAlarm directory resources to be merged into
// single file resources, if the user prefers that.
for (auto it = mCollectionPaths.constBegin(); it != mCollectionPaths.constEnd(); ++it)
{
const AkResourceData& resourceData = it.value();
if (!resourceData.dirType)
migrateCollection(resourceData.collection, false);
}
// Now migrate KAlarm directory Akonadi resources, which must be merged
// or converted into single file resources.
for (auto it = mCollectionPaths.constBegin(); it != mCollectionPaths.constEnd(); ++it)
{
const AkResourceData& resourceData = it.value();
if (resourceData.dirType)
migrateCollection(resourceData.collection, true);
}
// The alarm types of all collections have been found.
mCollectionPaths.clear();
terminate(true);
}
/******************************************************************************
* Migrate one Akonadi collection to a file system resource.
*/
void AkonadiResourceMigrator::migrateCollection(const Akonadi::Collection& collection, bool dirType)
{
// Fetch the collection's properties.
const CollectionProperties colProperties(collection);
if (!dirType)
{
// It's a single file resource.
qCDebug(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator: Migrate file resource" << collection.displayName() << ", alarm types:" << (int)colProperties.alarmTypes << ", enabled types:" << (int)colProperties.enabledTypes << ", standard types:" << (int)colProperties.standardTypes;
Q_EMIT fileResource(collection.resource(),
QUrl::fromUserInput(collection.remoteId(), QString(), QUrl::AssumeLocalFile),
colProperties.alarmTypes, collection.displayName(), colProperties.backgroundColour,
colProperties.enabledTypes, colProperties.standardTypes, colProperties.readOnly);
}
else
{
// Convert Akonadi directory resource to single file resources.
qCDebug(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator: Migrate directory resource" << collection.displayName() << ", alarm types:" << (int)colProperties.alarmTypes << ", enabled types:" << (int)colProperties.enabledTypes;
Q_EMIT dirResource(collection.resource(), collection.remoteId(),
colProperties.alarmTypes, collection.displayName(), colProperties.backgroundColour,
colProperties.enabledTypes, colProperties.standardTypes, colProperties.readOnly);
}
}
/******************************************************************************
* Delete an Akonadi resource after it has been migrated to a file system resource.
*/
void AkonadiResourceMigrator::deleteAkonadiResource(const QString& resourceName)
{
// Delete the Akonadi resource, to prevent it using CPU, on the
// assumption that Akonadi access won't be needed by any other
// application. Excess CPU usage is one of the major bugs which
// prompted replacing Akonadi resources with file resources.
Akonadi::AgentManager* agentManager = Akonadi::AgentManager::self();
const Akonadi::AgentInstance agent = agentManager->instance(resourceName);
agentManager->removeInstance(agent);
}
/******************************************************************************
* Called when Akonadi migration is complete or is known not to be possible.
*/
void AkonadiResourceMigrator::terminate(bool migrated)
{
qCDebug(AKONADIPLUGIN_LOG) << "AkonadiResourceMigrator::terminate" << migrated;
Q_EMIT migrationComplete(migrated);
// Ignore any further Akonadi server state changes, to prevent possible
// repeated migrations.
disconnect(Akonadi::ServerManager::self(), nullptr, this, nullptr);
if (mAkonadiStarted)
{
// The Akonadi server wasn't running before we started it, so stop it
// now that it's no longer needed.
Akonadi::ServerManager::stop();
}
deleteLater();
}
namespace
{
/******************************************************************************
* Fetch an Akonadi collection's properties.
*/
CollectionProperties::CollectionProperties(const Akonadi::Collection& collection)
{
readOnly = (collection.rights() & WritableRights) != WritableRights;
alarmTypes = CalEvent::types(collection.contentMimeTypes());
if (collection.hasAttribute<CollectionAttribute>())
{
const auto* attr = collection.attribute<CollectionAttribute>();
enabledTypes = attr->enabled() & alarmTypes;
standardTypes = attr->standard() & enabledTypes;
backgroundColour = attr->backgroundColor();
}
}
}
// vim: et sw=4:
/*
* akonadiresourcemigrator.h - migrates KAlarm Akonadi resources
* Program: kalarm
* SPDX-FileCopyrightText: 2020-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kalarmcalendar/kacalendar.h"
#include <Akonadi/ServerManager>
#include <Akonadi/Collection>
class KJob;
namespace Akonadi { class CollectionFetchJob; }
using namespace KAlarmCal;
/**
* Class to migrate Akonadi or KResources alarm calendars from previous
* versions of KAlarm, and to create default calendar resources if none exist.
*/
class AkonadiResourceMigrator : public QObject
{
Q_OBJECT
public:
~AkonadiResourceMigrator() override;
/** Return the unique instance, creating it if necessary.
* Note that the instance will be destroyed once migration has completed.
* @return Unique instance, or null if migration is not required or has
* already been done.
*/
static AkonadiResourceMigrator* instance();
/** Initiate Akonadi resource migration. */
void initiateMigration();
/** Delete a named Akonadi resource.
* This should be called after the resource has been migrated.
*/
void deleteAkonadiResource(const QString& resourceName);
Q_SIGNALS:
/** Emitted when Akonadi resource migration has completed.
* @param migrated true if Akonadi migration was performed.
*/
void migrationComplete(bool migrated);
/** Emitted when a file resource needs to be migrated. */
void fileResource(const QString& resourceName, const QUrl& location, KAlarmCal::CalEvent::Types alarmTypes,
const QString& displayName, const QColor& backgroundColour,
KAlarmCal::CalEvent::Types enabledTypes, KAlarmCal::CalEvent::Types standardTypes,
bool readOnly);