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

Improve generic encapsulation of AkonadiDataModel

parent 5a64eb37
......@@ -100,6 +100,7 @@ set(kalarm_bin_SRCS ${libkalarm_SRCS}
wakedlg.cpp
)
set(kalarm_bin_SRCS ${kalarm_bin_SRCS}
resources/calendarfunctions.cpp
resources/resourcetype.cpp
resources/resource.cpp
resources/resources.cpp
......
......@@ -61,8 +61,6 @@ DisplayCalendar* DisplayCalendar::mInstance = nullptr;
*/
void AlarmCalendar::initialise()
{
Preferences::setBackend(Preferences::Akonadi);
Preferences::self()->save();
KACalendar::setProductId(KALARM_NAME, KALARM_VERSION);
CalFormat::setApplication(QStringLiteral(KALARM_NAME), QString::fromLatin1(KACalendar::icalProductId()));
}
......
......@@ -32,6 +32,7 @@
#include "preferences.h"
#include "templatelistview.h"
#include "templatemenuaction.h"
#include "resources/calendarfunctions.h"
#include "resources/datamodel.h"
#include "resources/resources.h"
#include "resources/eventmodel.h"
......@@ -134,8 +135,6 @@ KAlarm::UpdateResult sendToKOrganizer(const KAEvent&);
KAlarm::UpdateResult deleteFromKOrganizer(const QString& eventID);
KAlarm::UpdateResult runKOrganizer();
QString uidKOrganizer(const QString& eventID);
bool updateCalendarFormat(const FileStorage::Ptr&);
bool importCalendarFile(const QUrl&, CalEvent::Types alarmTypes, QWidget* parent, QHash<CalEvent::Type, QVector<KAEvent>>&);
}
......@@ -802,7 +801,7 @@ bool importAlarms(Resource& resource, QWidget* parent)
continue;
}
qCDebug(KALARM_LOG) << "KAlarm::importAlarms:" << url.toDisplayString();
importCalendarFile(url, alarmTypes, parent, events);
importCalendarFile(url, alarmTypes, true, parent, events);
}
if (events.isEmpty())
return false;
......@@ -817,7 +816,7 @@ bool importAlarms(Resource& resource, QWidget* parent)
else
res = Resources::destination(it.key());
for (const KAEvent& event : it.value())
for (const KAEvent& event : qAsConst(it.value()))
{
if (!res.addEvent(event))
success = false;
......@@ -1795,115 +1794,6 @@ QString uidKOrganizer(const QString& id)
return result.insert(0, KORGANIZER_UID);
}
/******************************************************************************
* Find the version of KAlarm which wrote the calendar file, and do any
* necessary conversions to the current format.
*/
bool updateCalendarFormat(const FileStorage::Ptr& fileStorage)
{
QString versionString;
int version = KACalendar::updateVersion(fileStorage, versionString);
if (version == KACalendar::IncompatibleFormat)
return false; // calendar was created by another program, or an unknown version of KAlarm
return true;
}
/******************************************************************************
* Import alarms from a calendar file. The alarms are converted to the current
* KAlarm format and are given new unique event IDs.
* Parameters: parent: parent widget for error message boxes
* alarmList: imported alarms are added to this list
*/
bool importCalendarFile(const QUrl& url, CalEvent::Types alarmTypes, QWidget* parent, QHash<CalEvent::Type, QVector<KAEvent>>& alarmList)
{
if (!url.isValid())
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Invalid URL";
return false;
}
// If the URL is remote, download it into a temporary local file.
QString filename;
bool local = url.isLocalFile();
if (local)
{
filename = url.toLocalFile();
if (!QFile::exists(filename))
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile:" << url.toDisplayString() << "not found";
KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
return false;
}
}
else
{
auto getJob = KIO::storedGet(url);
KJobWidgets::setWindow(getJob, MainWindow::mainMainWindow());
if (!getJob->exec())
{
qCCritical(KALARM_LOG) << "KAlarm::importCalendarFile: Download failure";
KAMessageBox::error(parent, xi18nc("@info", "Cannot download calendar: <filename>%1</filename>", url.toDisplayString()));
return false;
}
QTemporaryFile tmpFile;
tmpFile.setAutoRemove(false);
tmpFile.write(getJob->data());
tmpFile.seek(0);
filename = tmpFile.fileName();
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: --- Downloaded to" << filename;
}
// Read the calendar and add its alarms to the current calendars
MemoryCalendar::Ptr cal(new MemoryCalendar(Preferences::timeSpecAsZone()));
FileStorage::Ptr calStorage(new FileStorage(cal, filename));
bool success = calStorage->load();
if (!local)
QFile::remove(filename);
if (!success)
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Error loading calendar '" << filename <<"'";
KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
return false;
}
const bool currentFormat = updateCalendarFormat(calStorage);
const Event::List events = cal->rawEvents();
for (Event::Ptr event : events)
{
if (event->alarms().isEmpty() || !KAEvent(event).isValid())
continue; // ignore events without alarms, or usable alarms
CalEvent::Type type = CalEvent::status(event);
if (type == CalEvent::TEMPLATE)
{
// If we know the event was not created by KAlarm, don't treat it as a template
if (!currentFormat)
type = CalEvent::ACTIVE;
}
if (!(type & alarmTypes))
continue;
Event::Ptr newev(new Event(*event));
// If there is a display alarm without display text, use the event
// summary text instead.
if (type == CalEvent::ACTIVE && !newev->summary().isEmpty())
{
const Alarm::List& alarms = newev->alarms();
for (Alarm::Ptr alarm : alarms)
{
if (alarm->type() == Alarm::Display && alarm->text().isEmpty())
alarm->setText(newev->summary());
}
newev->setSummary(QString()); // KAlarm only uses summary for template names
}
// Give the event a new ID and add it to the list.
newev->setUid(CalEvent::uid(CalFormat::createUniqueId(), type));
alarmList[type] += KAEvent(newev);
}
return true;
}
} // namespace
/******************************************************************************
......
......@@ -71,7 +71,7 @@
#include <iostream>
#include <climits>
static const int AKONADI_TIMEOUT = 30; // timeout (seconds) for Akonadi collections to be populated
static const int RESOURCES_TIMEOUT = 30; // timeout (seconds) for resources to be populated
/******************************************************************************
* Find the maximum number of seconds late which a late-cancel alarm is allowed
......@@ -1249,7 +1249,7 @@ bool KAlarmApp::wantShowInSystemTray() const
*/
void KAlarmApp::setResourcesTimeout()
{
QTimer::singleShot(AKONADI_TIMEOUT * 1000, this, &KAlarmApp::slotResourcesTimeout);
QTimer::singleShot(RESOURCES_TIMEOUT * 1000, this, &KAlarmApp::slotResourcesTimeout);
}
/******************************************************************************
......
......@@ -62,6 +62,7 @@
<choices name="Backend">
<choice name="Kresources"><label context="@option">KResources</label></choice>
<choice name="Akonadi"><label context="@option">Akonadi</label></choice>
<choice name="FileResources"><label context="@option">File Resources</label></choice>
</choices>
</entry>
<entry name="Base_TimeZone" key="TimeZone" type="String">
......
......@@ -52,7 +52,6 @@
#include <AkonadiCore/Item>
#include <AkonadiCore/ItemFetchJob>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiWidgets/ControlGui>
#include <KCalendarCore/MemoryCalendar>
#include <KCalUtils/ICalDrag>
using namespace KCalendarCore;
......@@ -155,7 +154,7 @@ MainWindow::MainWindow(bool restored)
setCentralWidget(mSplitter);
// Create the calendar resource selector widget
Akonadi::ControlGui::widgetNeedsAkonadi(this);
DataModel::widgetNeedsDatabase(this);
mResourceSelector = new ResourceSelector(mSplitter);
mSplitter->setStretchFactor(0, 0); // don't resize resource selector when window is resized
mSplitter->setStretchFactor(1, 1);
......
......@@ -95,6 +95,9 @@ public:
int headerDataEventRoleOffset() const override;
/** Return the data storage backend type used by this model. */
Preferences::Backend dataStorageBackend() const override { return Preferences::Akonadi; }
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);
......
/*
* calendarfunctions.cpp - miscellaneous calendar access functions
* Program: kalarm
* Copyright © 2020 David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "calendarfunctions.h"
#include "preferences.h"
#include "lib/messagebox.h"
#include "kalarm_debug.h"
#include <KCalendarCore/CalFormat>
#include <KCalendarCore/Event>
#include <KCalendarCore/MemoryCalendar>
using namespace KCalendarCore;
#include <KLocalizedString>
#include <KJobWidgets>
#include <KIO/StoredTransferJob>
#include <QTemporaryFile>
namespace KAlarm
{
/******************************************************************************
* Import alarms from a calendar file. The alarms are converted to the current
* KAlarm format and are given new unique event IDs.
* Parameters: parent: parent widget for error message boxes
* alarmList: imported alarms are appended to this list
*/
bool importCalendarFile(const QUrl& url, CalEvent::Types alarmTypes, bool newId, QWidget* parent, QHash<CalEvent::Type, QVector<KAEvent>>& alarmList)
{
if (!url.isValid())
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Invalid URL";
return false;
}
// If the URL is remote, download it into a temporary local file.
QString filename;
bool local = url.isLocalFile();
if (local)
{
filename = url.toLocalFile();
if (!QFile::exists(filename))
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile:" << url.toDisplayString() << "not found";
KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
return false;
}
}
else
{
auto getJob = KIO::storedGet(url);
KJobWidgets::setWindow(getJob, parent);
if (!getJob->exec())
{
qCCritical(KALARM_LOG) << "KAlarm::importCalendarFile: Download failure";
KAMessageBox::error(parent, xi18nc("@info", "Cannot download calendar: <filename>%1</filename>", url.toDisplayString()));
return false;
}
QTemporaryFile tmpFile;
tmpFile.setAutoRemove(false);
tmpFile.write(getJob->data());
tmpFile.seek(0);
filename = tmpFile.fileName();
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: --- Downloaded to" << filename;
}
// Read the calendar and add its alarms to the current calendars
MemoryCalendar::Ptr cal(new MemoryCalendar(Preferences::timeSpecAsZone()));
FileStorage::Ptr calStorage(new FileStorage(cal, filename));
bool success = calStorage->load();
if (!local)
QFile::remove(filename);
if (!success)
{
qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Error loading calendar '" << filename <<"'";
KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
return false;
}
QString versionString;
const bool currentFormat = (KACalendar::updateVersion(calStorage, versionString) != KACalendar::IncompatibleFormat);
const Event::List events = cal->rawEvents();
for (Event::Ptr event : events)
{
if (event->alarms().isEmpty() || !KAEvent(event).isValid())
continue; // ignore events without alarms, or usable alarms
CalEvent::Type type = CalEvent::status(event);
if (type == CalEvent::TEMPLATE)
{
// If we know the event was not created by KAlarm, don't treat it as a template
if (!currentFormat)
type = CalEvent::ACTIVE;
}
if (!(type & alarmTypes))
continue;
Event::Ptr newev(new Event(*event));
// If there is a display alarm without display text, use the event
// summary text instead.
if (type == CalEvent::ACTIVE && !newev->summary().isEmpty())
{
const Alarm::List& alarms = newev->alarms();
for (Alarm::Ptr alarm : alarms)
{
if (alarm->type() == Alarm::Display && alarm->text().isEmpty())
alarm->setText(newev->summary());
}
newev->setSummary(QString()); // KAlarm only uses summary for template names
}
// Give the event a new ID, or ensure that it is in the correct format.
const QString id = newId ? CalFormat::createUniqueId() : newev->uid();
newev->setUid(CalEvent::uid(id, type));
alarmList[type] += KAEvent(newev);
}
return true;
}
}
// vim: et sw=4:
/*
* calendarfunctions.h - miscellaneous calendar access functions
* Program: kalarm
* Copyright © 2020 David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CALENDARFUNCTIONS_H
#define CALENDARFUNCTIONS_H
#include <KAlarmCal/KAEvent>
#include <QHash>
#include <QVector>
using namespace KAlarmCal;
class QUrl;
class QWidget;
namespace KAlarm
{
/** Read events from a calendar file. The events are converted to the current
* KAlarm format and are optionally given new unique event IDs.
*
* @param url URL of calendar file to read
* @param alarmTypes alarm types to read from calendar file; other types are ignored
* @param newId whether to create new IDs for the events
* @param parent parent widget for error messages
* @param events imported alarms are appended to this list
* @return true if the calendar file was read successfully.
*/
bool importCalendarFile(const QUrl& url, CalEvent::Types alarmTypes, bool newId, QWidget* parent, QHash<CalEvent::Type, QVector<KAEvent>>& events);
} // namespace KAlarm
#endif // CALENDARFUNCTIONS_H
// vim: et sw=4:
......@@ -32,13 +32,20 @@ namespace DataModel
void initialise()
{
AkonadiDataModel::instance();
AkonadiDataModel* model = AkonadiDataModel::instance();
Preferences::setBackend(model->dataStorageBackend());
Preferences::self()->save();
}
void terminate()
{
}
void widgetNeedsDatabase(QWidget* widget)
{
Akonadi::ControlGui::widgetNeedsAkonadi(widget);
}
void reload()
{
AkonadiDataModel::instance()->reload();
......
......@@ -40,6 +40,11 @@ void initialise();
void terminate();
/** Disable the widget if the database engine is not available, and display an
* error overlay.
*/
void widgetNeedsDatabase(QWidget*);
/** Reload all resources' data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
......
......@@ -23,6 +23,8 @@
#include "resourcetype.h"
#include "preferences.h"
#include <KAlarmCal/KACalendar>
#include <QSize>
......@@ -78,6 +80,9 @@ public:
virtual ~ResourceDataModelBase();
public:
/** Return the data storage backend type used by this model. */
virtual Preferences::Backend dataStorageBackend() const = 0;
static QSize iconSize() { return mIconSize; }
/** Return a bulleted list of alarm types for inclusion in an i18n message. */
......
Markdown is supported
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