Commit 16b5e7d8 authored by Volker Krause's avatar Volker Krause
Browse files

Add Akonadi KCalendarCore platform calendar plugin

parent 2fc69ebc
......@@ -86,6 +86,7 @@ endif()
add_subdirectory(src)
add_subdirectory(serializers)
add_subdirectory(reminder-daemon)
add_subdirectory(calendar-plugin)
if (BUILD_TESTING)
add_subdirectory(autotests)
endif ()
......
# SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
# SPDX-License-Identifier: BSD-2-Clause
add_library(akonadicalendarplugin)
target_sources(akonadicalendarplugin PRIVATE
akonadicalendarplugin.cpp
singlecollectioncalendar.cpp
)
target_link_libraries(akonadicalendarplugin PRIVATE
KF5::CalendarCore
KF5::AkonadiCalendar
)
install(TARGETS akonadicalendarplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf${QT_MAJOR_VERSION}/org.kde.kcalendarcore.calendars/)
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "akonadicalendarplugin.h"
#include "singlecollectioncalendar.h"
#include <Akonadi/CollectionFetchJob>
#include <Akonadi/CollectionFetchScope>
#include <Akonadi/Monitor>
#include <KCalendarCore/Event>
#include <KCalendarCore/Journal>
#include <KCalendarCore/Todo>
#include <QDebug>
static bool filterCollection(const Akonadi::Collection &col)
{
return !col.isVirtual();
}
AkonadiCalendarPlugin::AkonadiCalendarPlugin(QObject *parent, const QVariantList &args)
: KCalendarCore::CalendarPlugin(parent, args)
{
auto job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive, this);
job->fetchScope().setContentMimeTypes(KCalendarCore::Incidence::mimeTypes());
connect(job, &Akonadi::CollectionFetchJob::finished, this, [this, job]() {
const auto results = job->collections();
for (const auto &col : results) {
if (!filterCollection(col)) {
continue;
}
KCalendarCore::Calendar::Ptr cal(new SingleCollectionCalendar(col));
m_calendars.push_back(cal);
}
});
auto monitor = new Akonadi::Monitor(this);
monitor->setCollectionFetchScope(job->fetchScope());
connect(monitor, &Akonadi::Monitor::collectionAdded, this, [this](const Akonadi::Collection &c) {
if (!filterCollection(c)) {
return;
}
m_calendars.push_back(KCalendarCore::Calendar::Ptr(new SingleCollectionCalendar(c)));
Q_EMIT calendarsChanged();
});
connect(monitor, &Akonadi::Monitor::collectionRemoved, this, [this](const Akonadi::Collection &c) {
m_calendars.erase(std::remove_if(m_calendars.begin(),
m_calendars.end(),
[c](const KCalendarCore::Calendar::Ptr &cal) {
return cal.staticCast<SingleCollectionCalendar>()->collection().id() == c.id();
}),
m_calendars.end());
Q_EMIT calendarsChanged();
});
connect(monitor, qOverload<const Akonadi::Collection &>(&Akonadi::Monitor::collectionChanged), this, [this](const Akonadi::Collection &col) {
for (const auto &c : m_calendars) {
const auto cal = c.staticCast<SingleCollectionCalendar>();
if (cal->collection().id() == col.id()) {
cal->setCollection(col);
Q_EMIT calendarsChanged();
return;
}
}
});
}
AkonadiCalendarPlugin::~AkonadiCalendarPlugin() = default;
QVector<KCalendarCore::Calendar::Ptr> AkonadiCalendarPlugin::calendars() const
{
return m_calendars;
}
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <KCalendarCore/CalendarPlugin>
/** Akonadi platform calendar plugin for KCalendarCore. */
class AkonadiCalendarPlugin : public KCalendarCore::CalendarPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.kcalendarcore.CalendarPlugin")
public:
explicit AkonadiCalendarPlugin(QObject *parent = nullptr, const QVariantList &args = {});
~AkonadiCalendarPlugin() override;
QVector<KCalendarCore::Calendar::Ptr> calendars() const override;
private:
QVector<KCalendarCore::Calendar::Ptr> m_calendars;
};
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "singlecollectioncalendar.h"
#include "../src/calendarbase_p.h"
#include <Akonadi/CalendarUtils>
#include <Akonadi/ItemFetchJob>
#include <Akonadi/ItemFetchScope>
#include <Akonadi/Monitor>
#include <kcalendarcore_version.h>
SingleCollectionCalendar::SingleCollectionCalendar(const Akonadi::Collection &col, QObject *parent)
: Akonadi::CalendarBase(parent)
{
setCollection(col);
incidenceChanger()->setDefaultCollection(col);
incidenceChanger()->setGroupwareCommunication(false);
incidenceChanger()->setDestinationPolicy(Akonadi::IncidenceChanger::DestinationPolicyNeverAsk);
#if KCALENDARCORE_VERSION >= QT_VERSION_CHECK(5, 96, 0)
setIsLoading(true);
#endif
// here and below for monitoring: ensure items have a parent collection
// before calling internalInsert to prevent an extra collection fetch job
auto job = new Akonadi::ItemFetchJob(col, this);
job->fetchScope().fetchFullPayload();
connect(job, &Akonadi::ItemFetchJob::finished, this, [this, job]() {
Q_D(Akonadi::CalendarBase);
const auto items = job->items();
for (auto item : items) {
item.setParentCollection(m_collection);
d->internalInsert(item);
}
#if KCALENDARCORE_VERSION >= QT_VERSION_CHECK(5, 96, 0)
setIsLoading(false);
#endif
});
auto monitor = new Akonadi::Monitor(this);
monitor->setCollectionMonitored(m_collection, true);
monitor->setItemFetchScope(job->fetchScope());
connect(monitor, &Akonadi::Monitor::itemAdded, this, [this](Akonadi::Item item) {
Q_D(Akonadi::CalendarBase);
item.setParentCollection(m_collection);
d->internalInsert(item);
});
connect(monitor, &Akonadi::Monitor::itemChanged, this, [this](Akonadi::Item item) {
Q_D(Akonadi::CalendarBase);
item.setParentCollection(m_collection);
d->internalInsert(item);
});
connect(monitor, &Akonadi::Monitor::itemRemoved, this, [this](const Akonadi::Item &item) {
Q_D(Akonadi::CalendarBase);
d->internalRemove(item);
});
}
SingleCollectionCalendar::~SingleCollectionCalendar() = default;
Akonadi::Collection SingleCollectionCalendar::collection() const
{
return m_collection;
}
void SingleCollectionCalendar::setCollection(const Akonadi::Collection &c)
{
Q_ASSERT(c.id() == m_collection.id() || !m_collection.isValid());
m_collection = c;
setName(Akonadi::CalendarUtils::displayName(nullptr, m_collection));
setAccessMode((m_collection.rights() & (Akonadi::Collection::CanCreateItem | Akonadi::Collection::CanChangeItem)) ? KCalendarCore::ReadWrite
: KCalendarCore::ReadOnly);
}
bool SingleCollectionCalendar::addEvent(const KCalendarCore::Event::Ptr &event)
{
if (m_collection.contentMimeTypes().contains(event->mimeType()) || m_collection.contentMimeTypes().contains(QLatin1String("text/calendar"))) {
return CalendarBase::addEvent(event);
}
return false;
}
bool SingleCollectionCalendar::addTodo(const KCalendarCore::Todo::Ptr &todo)
{
if (m_collection.contentMimeTypes().contains(todo->mimeType()) || m_collection.contentMimeTypes().contains(QLatin1String("text/calendar"))) {
return CalendarBase::addTodo(todo);
}
return false;
}
bool SingleCollectionCalendar::addJournal(const KCalendarCore::Journal::Ptr &journal)
{
if (m_collection.contentMimeTypes().contains(journal->mimeType()) || m_collection.contentMimeTypes().contains(QLatin1String("text/calendar"))) {
return CalendarBase::addJournal(journal);
}
return false;
}
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <Akonadi/CalendarBase>
/** Calendar representing a single Akonadi::Collection. */
class SingleCollectionCalendar : public Akonadi::CalendarBase
{
public:
explicit SingleCollectionCalendar(const Akonadi::Collection &col, QObject *parent = nullptr);
~SingleCollectionCalendar() override;
Akonadi::Collection collection() const;
void setCollection(const Akonadi::Collection &c);
bool addEvent(const KCalendarCore::Event::Ptr &event) override;
bool addTodo(const KCalendarCore::Todo::Ptr &todo) override;
bool addJournal(const KCalendarCore::Journal::Ptr &journal) override;
private:
Akonadi::Collection m_collection;
};
......@@ -21,8 +21,8 @@ public:
explicit CalendarBasePrivate(CalendarBase *qq);
~CalendarBasePrivate() override;
void internalInsert(const Akonadi::Item &item);
void internalRemove(const Akonadi::Item &item);
AKONADI_CALENDAR_EXPORT void internalInsert(const Akonadi::Item &item);
AKONADI_CALENDAR_EXPORT void internalRemove(const Akonadi::Item &item);
void deleteAllIncidencesOfType(const QString &mimeType);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment