Commit e7d6c6b3 authored by David Jarvie's avatar David Jarvie
Browse files

Remove Akonadi resource option

parent 11cc00b1
Pipeline #44328 passed with stage
in 17 minutes and 56 seconds
......@@ -59,8 +59,6 @@ find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED DBus Gui Network Widgets
option(FILE_RESOURCES "Use file system resources instead of Akonadi resources." TRUE)
# Find KF5 packages
find_package(KF5CalendarCore ${KF5_MIN_VERSION} CONFIG REQUIRED)
......@@ -114,7 +112,6 @@ find_package(Xsltproc)
set_package_properties(Xsltproc PROPERTIES DESCRIPTION "XSLT processor from libxslt" TYPE REQUIRED PURPOSE "Required to generate D-Bus interfaces for all Akonadi resources.")
configure_file(src/config-kalarm.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kalarm.h)
include_directories(${kalarm_SOURCE_DIR} ${kalarm_BINARY_DIR})
......@@ -61,12 +61,7 @@ set(resources_SRCS
......@@ -2,6 +2,3 @@
/* Define to 1 if you have the Xlib */
#cmakedefine01 KDEPIM_HAVE_X11
/* Define to 1 to use file system resources instead of Akonadi resources */
#cmakedefine01 FILE_RESOURCES
......@@ -10,11 +10,7 @@
#define KALARM_H
#include "config-kalarm.h"
* akonadicalendarupdater.cpp - updates a calendar to current KAlarm format
* Program: kalarm
* SPDX-FileCopyrightText: 2011-2020 David Jarvie <>
* SPDX-License-Identifier: GPL-2.0-or-later
#include "akonadicalendarupdater.h"
#include "kalarmsettings.h"
#include "kalarmdirsettings.h"
#include "resources/akonadidatamodel.h"
#include "resources/akonadiresource.h"
#include "resources/resources.h"
#include "lib/messagebox.h"
#include "kalarm_debug.h"
#include <KAlarmCal/CollectionAttribute>
#include <KAlarmCal/CompatibilityAttribute>
#include <KAlarmCal/Version>
#include <AkonadiCore/AgentManager>
#include <KLocalizedString>
#include <QTimer>
using namespace Akonadi;
using namespace KAlarmCal;
AkonadiCalendarUpdater::AkonadiCalendarUpdater(const Collection& collection, bool dirResource,
bool ignoreKeepFormat, bool newCollection,
QObject* parent, QWidget* promptParent)
: CalendarUpdater(, ignoreKeepFormat, parent, promptParent)
, mCollection(collection)
, mDirResource(dirResource)
, mNewCollection(newCollection)
* If an existing Akonadi resource calendar can be converted to the current
* KAlarm format, prompt the user whether to convert it, and if yes, tell the
* Akonadi resource to update the backend storage to the current format.
* The CollectionAttribute's KeepFormat property will be updated if the user
* chooses not to update the calendar.
* Note: the collection should be up to date: use AkonadiDataModel::refresh()
* before calling this function.
void AkonadiCalendarUpdater::updateToCurrentFormat(const Resource& resource, bool ignoreKeepFormat, QObject* parent)
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::updateToCurrentFormat:" <<;
if (containsResource(
return; // prevent multiple simultaneous user prompts
const AgentInstance agent = AgentManager::self()->instance(resource.configName());
const QString id = agent.type().identifier();
bool dirResource;
if (id == AkonadiResource::KALARM_RESOURCE)
dirResource = false;
else if (id == AkonadiResource::KALARM_DIR_RESOURCE)
dirResource = true;
qCCritical(KALARM_LOG) << "AkonadiCalendarUpdater::updateToCurrentFormat: Invalid agent type" << id;
const Collection& collection = AkonadiResource::collection(resource);
auto* updater = new AkonadiCalendarUpdater(collection, dirResource, ignoreKeepFormat, false, parent, qobject_cast<QWidget*>(parent));
QTimer::singleShot(0, updater, &AkonadiCalendarUpdater::update);
* If the calendar is not in the current KAlarm format, prompt the user whether
* to convert to the current format, and then perform the conversion.
bool AkonadiCalendarUpdater::update()
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::update:" << << (mDirResource ? "directory" : "file");
bool result = true;
if (isDuplicate())
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::update: Not updating (concurrent update in progress)";
else if (mCollection.hasAttribute<CompatibilityAttribute>()) // must know format to update
const CompatibilityAttribute* compatAttr = mCollection.attribute<CompatibilityAttribute>();
const KACalendar::Compat compatibility = compatAttr->compatibility();
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::update: current format:" << compatibility;
if ((compatibility & ~KACalendar::Converted)
// The calendar isn't in the current KAlarm format
&& !(compatibility & ~(KACalendar::Convertible | KACalendar::Converted)))
// The calendar format is convertible to the current KAlarm format
if (!mIgnoreKeepFormat
&& mCollection.hasAttribute<CollectionAttribute>()
&& mCollection.attribute<CollectionAttribute>()->keepFormat())
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::update: Not updating format (previous user choice)";
// The user hasn't previously said not to convert it
const QString versionString = KAlarmCal::getVersionString(compatAttr->version());
const QString msg = conversionPrompt(, versionString, false);
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::update: Version" << versionString;
if (KAMessageBox::warningYesNo(mPromptParent, msg) != KMessageBox::Yes)
result = false; // the user chose not to update the calendar
// Tell the resource to update the backend storage format
QString errmsg;
if (!mNewCollection)
// Refetch the collection's details because anything could
// have happened since the prompt was first displayed.
if (!AkonadiDataModel::instance()->refresh(mCollection))
errmsg = i18nc("@info", "Invalid collection");
if (errmsg.isEmpty())
const AgentInstance agent = AgentManager::self()->instance(mCollection.resource());
if (mDirResource)
updateStorageFormat<OrgKdeAkonadiKAlarmDirSettingsInterface>(agent, errmsg, mParent);
updateStorageFormat<OrgKdeAkonadiKAlarmSettingsInterface>(agent, errmsg, mParent);
if (!errmsg.isEmpty())
Resources::notifyResourceMessage(, ResourceType::MessageType::Error,
xi18nc("@info", "Failed to update format of calendar <resource>%1</resource>",,
if (!mNewCollection)
// Record the user's choice of whether to update the calendar
Resource resource = AkonadiDataModel::instance()->resource(;
return result;
* Tell an Akonadi resource to update the backend storage format to the current
* KAlarm format.
* Reply = true if success; if false, 'errorMessage' contains the error message.
template <class Interface> bool AkonadiCalendarUpdater::updateStorageFormat(const AgentInstance& agent, QString& errorMessage, QObject* parent)
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::updateStorageFormat";
auto* iface = AkonadiResource::getAgentInterface<Interface>(agent, errorMessage, parent);
if (!iface)
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::updateStorageFormat:" << errorMessage;
return false;
delete iface;
qCDebug(KALARM_LOG) << "AkonadiCalendarUpdater::updateStorageFormat: true";
return true;
// vim: et sw=4:
* akonadicalendarupdater.h - updates a calendar to current KAlarm format
* Program: kalarm
* SPDX-FileCopyrightText: 2011-2020 David Jarvie <>
* SPDX-License-Identifier: GPL-2.0-or-later
#include "calendarupdater.h"
#include <AkonadiCore/Collection>
namespace Akonadi { class AgentInstance; }
// Updates the backend calendar format of a single alarm calendar
class AkonadiCalendarUpdater : public CalendarUpdater
AkonadiCalendarUpdater(const Akonadi::Collection& collection, bool dirResource,
bool ignoreKeepFormat, bool newCollection, QObject* parent, QWidget* promptParent = nullptr);
/** If an existing resource calendar can be converted to the current KAlarm
* format, prompt the user whether to convert it, and if yes, tell the resource
* to update the backend storage to the current format.
* The resource's KeepFormat property will be updated if the user chooses not to
* update the calendar.
* This method should call update() on a single shot timer to prompt the
* user and convert the calendar.
* @param parent Parent object. If possible, this should be a QWidget.
static void updateToCurrentFormat(const Resource&, bool ignoreKeepFormat, QObject* parent);
public Q_SLOTS:
/** If the calendar is not in the current KAlarm format, prompt the user
* whether to convert to the current format, and then perform the conversion.
* This method calls deleteLater() on completion.
* @return false if the calendar is not in current format and the user
* chose not to update it; true otherwise.
bool update() override;
template <class Interface> static bool updateStorageFormat(const Akonadi::AgentInstance&, QString& errorMessage, QObject* parent);
Akonadi::Collection mCollection;
const bool mDirResource;
const bool mNewCollection;
// vim: et sw=4:
This diff is collapsed.
* akonadidatamodel.h - KAlarm calendar file access using Akonadi
* Program: kalarm
* SPDX-FileCopyrightText: 2010-2020 David Jarvie <>
* SPDX-License-Identifier: GPL-2.0-or-later
#include "resources/resourcedatamodelbase.h"
#include "resources/akonadiresource.h"
#include <KAlarmCal/KAEvent>
#include <AkonadiCore/EntityTreeModel>
#include <AkonadiCore/ServerManager>
#include <QColor>
#include <QHash>
#include <QQueue>
namespace Akonadi
class ChangeRecorder;
class KJob;
using namespace KAlarmCal;
class AkonadiDataModel : public Akonadi::EntityTreeModel, public ResourceDataModelBase
enum Change { Enabled, ReadOnly, AlarmTypes };
static AkonadiDataModel* instance();
~AkonadiDataModel() override;
static Akonadi::ChangeRecorder* monitor();
/** Refresh the specified collection instance with up to date data. */
bool refresh(Akonadi::Collection&) const;
/** Refresh the specified item instance with up to date data. */
bool refresh(Akonadi::Item&) const;
Resource resource(Akonadi::Collection::Id) const;
Resource resource(const QModelIndex&) const;
QModelIndex resourceIndex(const Resource&) const;
QModelIndex resourceIndex(Akonadi::Collection::Id) const;
Akonadi::Collection* collection(Akonadi::Collection::Id id) const;
Akonadi::Collection* collection(const Resource&) const;
KAEvent event(const QString& eventId) const;
KAEvent event(const QModelIndex&) const;
using QObject::event; // prevent warning about hidden virtual method
/** Return an event's model index, based on its ID. */
QModelIndex eventIndex(const KAEvent&) const;
QModelIndex eventIndex(const QString& eventId) const;
/** Return the up-to-date Item, given its ID.
* If not found, an invalid Item is returned.
Akonadi::Item itemById(Akonadi::Item::Id) const;
/** Return the Item for a given event. */
Akonadi::Item itemForEvent(const QString& eventId) const;
QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
int headerDataEventRoleOffset() const override;
private Q_SLOTS:
/** Called when a resource notifies a message to display to the user. */
void slotResourceMessage(ResourceType::MessageType, const QString& message, const QString& details);
/** Signal emitted when the Akonadi server has stopped. */
void serverStopped();
/** Terminate access to the data model, and tidy up. Not necessary for Akonadi. */
void terminate() override {}
/** Reload all resources' data from storage.
* @note This reloads data from Akonadi storage, not from the backend storage.
void reload() override;
/** Reload a resource's data from storage.
* @note This reloads data from Akonadi storage, not from the backend storage.
bool reload(Resource&) override;
/** Check for, and remove, any duplicate resources, i.e. those which use
* the same calendar file/directory.
void removeDuplicateResources() override;
/** Disable the widget if the database engine is not available, and display
* an error overlay.
void widgetNeedsDatabase(QWidget*) override;
/** Create an AkonadiResourceCreator instance. */
ResourceCreator* createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent) override;
/** Update a resource's backend calendar file to the current KAlarm format. */
void updateCalendarToCurrentFormat(Resource&, bool ignoreKeepFormat, QObject* parent) override;
ResourceListModel* createResourceListModel(QObject* parent) override;
ResourceFilterCheckListModel* createResourceFilterCheckListModel(QObject* parent) override;
AlarmListModel* createAlarmListModel(QObject* parent) override;
AlarmListModel* allAlarmListModel() override;
TemplateListModel* createTemplateListModel(QObject* parent) override;
TemplateListModel* allTemplateListModel() override;
/** Return the data storage backend type used by this model. */
Preferences::Backend dataStorageBackend() const override { return Preferences::Akonadi; }
QVariant entityHeaderData(int section, Qt::Orientation, int role, HeaderGroup) const override;
int entityColumnCount(HeaderGroup) const override;
private Q_SLOTS:
void checkResources(Akonadi::ServerManager::State);
void slotMigrationCompleted();
void collectionFetchResult(KJob*);
void slotCollectionChanged(const Akonadi::Collection& c, const QSet<QByteArray>& attrNames);
void slotCollectionRemoved(const Akonadi::Collection&);
void slotCollectionBeingCreated(const QString& path, Akonadi::Collection::Id, bool finished);
void slotCollectionTreeFetched();
void slotCollectionPopulated(Akonadi::Collection::Id);
void slotUpdateTimeTo();
void slotUpdateArchivedColour(const QColor&);
void slotUpdateDisabledColour(const QColor&);
void slotUpdateHolidays();
void slotUpdateWorkingHours();
void slotRowsInserted(const QModelIndex& parent, int start, int end);
void slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
void slotMonitoredItemChanged(const Akonadi::Item&, const QSet<QByteArray>&);
void slotEmitEventUpdated();
struct CalData // data per collection
CalData() : enabled(false) { }
CalData(bool e, const QColor& c) : colour(c), enabled(e) { }
QColor colour; // user selected color for the calendar
bool enabled; // whether the collection is enabled
struct CollJobData // collection data for jobs in progress
CollJobData() : id(-1) {}
CollJobData(Akonadi::Collection::Id i, const QString& d) : id(i), displayName(d) {}
Akonadi::Collection::Id id;
QString displayName;
struct CollTypeData // data for configuration dialog for collection creation job
CollTypeData() : parent(nullptr), alarmType(CalEvent::EMPTY) {}
CollTypeData(CalEvent::Type t, QWidget* p) : parent(p), alarmType(t) {}
QWidget* parent;
CalEvent::Type alarmType;
AkonadiDataModel(Akonadi::ChangeRecorder*, QObject* parent);
void initResourceMigrator();
Resource& updateResource(const Akonadi::Collection&) const;
/** Return the alarm for the specified Akonadi Item.
* The item's parentCollection() is set.
* @param res Set the resource for the item's parent collection.
* @return the event, or invalid event if no such event exists.
KAEvent event(Akonadi::Item&, const QModelIndex&, Resource& res) const;
QModelIndex itemIndex(const Akonadi::Item&) const;
void signalDataChanged(bool (*checkFunc)(const Akonadi::Item&), int startColumn, int endColumn, const QModelIndex& parent);
void setCollectionChanged(Resource&, const Akonadi::Collection&, bool checkCompat);
QList<KAEvent> events(ResourceId) const;
void getChildEvents(const QModelIndex& parent, QList<KAEvent>&) const;
static bool mInstanceIsOurs; // mInstance is an AkonadiDataModel instance
static int mTimeHourPos; // position of hour within time string, or -1 if leading zeroes included
Akonadi::ChangeRecorder* mMonitor;
QHash<KJob*, CollJobData> mPendingCollectionJobs; // pending collection creation/deletion jobs, with collection ID & name
QHash<KJob*, CollTypeData> mPendingColCreateJobs; // default alarm type for pending collection creation jobs
QList<QString> mCollectionsBeingCreated; // path names of new collections being created by migrator
QList<Akonadi::Collection::Id> mCollectionIdsBeingCreated; // ids of new collections being created by migrator
struct EventIds
Akonadi::Collection::Id collectionId {-1};
Akonadi::Item::Id itemId {-1};
explicit EventIds(Akonadi::Collection::Id c = -1, Akonadi::Item::Id i = -1) : collectionId(c), itemId(i) {}
QHash<QString, EventIds> mEventIds; // collection and item ID for each event ID
mutable QHash<Akonadi::Collection::Id, Resource> mResources;
QQueue<KAEvent> mPendingEventChanges; // changed events with changedEvent() signal pending
// vim: et sw=4:
This diff is collapsed.
* akonadiresource.h - class for an Akonadi alarm calendar resource
* Program: kalarm
* SPDX-FileCopyrightText: 2019-2020 David Jarvie <>
* SPDX-License-Identifier: GPL-2.0-or-later
#include "resource.h"
#include "kalarm_debug.h"
#include <KAlarmCal/CollectionAttribute>
#include <AkonadiCore/AgentInstance>
#include <AkonadiCore/Collection>
#include <AkonadiCore/Item>
#include <AkonadiCore/ServerManager>
#include <QObject>
#include <QDBusConnection>
class KJob;
class DuplicateResourceObject;
using namespace KAlarmCal;
/** Class for an alarm calendar resource accessed through Akonadi.
* Public access to this class is normally via the Resource class.
class AkonadiResource : public ResourceType
/** Construct a new AkonadiResource.
* The supplied collection must be up to date.
static Resource create(const Akonadi::Collection&);
/** Constructor.
* The supplied collection must be up to date.
explicit AkonadiResource(const Akonadi::Collection&);
~AkonadiResource() override;
static Resource nullResource();
/** Return whether the resource has a valid configuration. */
bool isValid() const override;
/** Return the resource's collection. */
Akonadi::Collection collection() const;
/** Return the type of storage used by the resource. */
StorageType storageType() const override;
/** Return the type of the resource (file, remote file, etc.)
* for display purposes.
* @param description true for description (e.g. "Remote file"),
* false for brief label (e.g. "URL").
QString storageTypeString(bool description) const override;
/** Return the location(s) of the resource (URL, file path, etc.) */
QUrl location() const override;
/** Return the location of the resource (URL, file path, etc.)
* for display purposes. */
QString displayLocation() const override;
/** Return the resource's display name. */
QString displayName() const override;
/** Return the resource's configuration identifier, which for this class is
* the Akonadi resource identifier. This is not the name normally
* displayed to the user.
QString configName() const override;
/** Return which types of alarms the resource can contain. */
CalEvent::Types alarmTypes() const override;
/** Return which alarm types (active, archived or template) the
* resource is enabled for. */
CalEvent::Types enabledTypes() const override;
/** Set the enabled/disabled state of the resource and its alarms,
* for a specified alarm type (active, archived or template). The
* enabled/disabled state for other alarm types is not affected.
* The alarms of that type in a disabled resource are ignored, and
* not displayed in the alarm list. The standard status for that type
* for a disabled resource is automatically cleared.
* @param type alarm type
* @param enabled true to set enabled, false to set disabled.
void setEnabled(CalEvent::Type type, bool enabled) override;
/** Set which alarm types (active, archived or template) the resource
* is enabled for.
* @param types alarm types
void setEnabled(CalEvent::Types types) override;
/** Return whether the resource is configured as read-only or is
* read-only on disc.
bool readOnly() const override;
/** Return whether the resource is both enabled and fully writable for a