Commit 71926dff authored by David Jarvie's avatar David Jarvie
Browse files

Refactor DataModel to call virtual ResourceDataModelBase methods

parent f588c704
......@@ -20,9 +20,14 @@
#include "akonadidatamodel.h"
#include "preferences.h"
#include "resources/akonadicalendarupdater.h"
#include "resources/akonadiresourcecreator.h"
#include "resources/akonadiresourcemigrator.h"
#include "resources/eventmodel.h"
#include "resources/resourcemodel.h"
#include "resources/resources.h"
#include "preferences.h"
#include "lib/synchtimer.h"
#include "kalarm_debug.h"
......@@ -42,6 +47,7 @@
#include <AkonadiCore/Item>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiWidgets/AgentTypeDialog>
#include <AkonadiWidgets/ControlGui>
#include <KLocalizedString>
#include <KColorUtils>
......@@ -63,8 +69,8 @@ static_assert((int)ResourceDataModelBase::UserRole>=(int)Akonadi::EntityTreeMode
= Class: AkonadiDataModel
=============================================================================*/
AkonadiDataModel* AkonadiDataModel::mInstance = nullptr;
int AkonadiDataModel::mTimeHourPos = -2;
bool AkonadiDataModel::mInstanceIsOurs = false;
int AkonadiDataModel::mTimeHourPos = -2;
/******************************************************************************
* Construct and return the singleton.
......@@ -72,8 +78,11 @@ int AkonadiDataModel::mTimeHourPos = -2;
AkonadiDataModel* AkonadiDataModel::instance()
{
if (!mInstance)
{
mInstance = new AkonadiDataModel(new ChangeRecorder(qApp), qApp);
return mInstance;
mInstanceIsOurs = true;
}
return mInstanceIsOurs ? (AkonadiDataModel*)mInstance : nullptr;
}
/******************************************************************************
......@@ -129,7 +138,10 @@ AkonadiDataModel::AkonadiDataModel(ChangeRecorder* monitor, QObject* parent)
AkonadiDataModel::~AkonadiDataModel()
{
if (mInstance == this)
{
mInstance = nullptr;
mInstanceIsOurs = false;
}
}
/******************************************************************************
......@@ -398,6 +410,20 @@ void AkonadiDataModel::slotUpdateWorkingHours()
signalDataChanged(&checkItem_workTimeOnly, TimeColumn, TimeToColumn, QModelIndex());
}
/******************************************************************************
* Reload all collections from Akonadi storage. The backend data is not reloaded.
*/
void AkonadiDataModel::reload()
{
qCDebug(KALARM_LOG) << "AkonadiDataModel::reload";
const Collection::List collections = mMonitor->collectionsMonitored();
for (const Collection& collection : collections)
{
mMonitor->setCollectionMonitored(collection, false);
mMonitor->setCollectionMonitored(collection, true);
}
}
/******************************************************************************
* Reload a collection from Akonadi storage. The backend data is not reloaded.
*/
......@@ -413,17 +439,70 @@ bool AkonadiDataModel::reload(Resource& resource)
}
/******************************************************************************
* Reload all collections from Akonadi storage. The backend data is not reloaded.
* Disable the widget if the database engine is not available, and display an
* error overlay.
*/
void AkonadiDataModel::reload()
void AkonadiDataModel::widgetNeedsDatabase(QWidget* widget)
{
qCDebug(KALARM_LOG) << "AkonadiDataModel::reload";
const Collection::List collections = mMonitor->collectionsMonitored();
for (const Collection& collection : collections)
{
mMonitor->setCollectionMonitored(collection, false);
mMonitor->setCollectionMonitored(collection, true);
}
Akonadi::ControlGui::widgetNeedsAkonadi(widget);
}
/******************************************************************************
* Check for, and remove, any duplicate Akonadi resources, i.e. those which use
* the same calendar file/directory.
*/
void AkonadiDataModel::removeDuplicateResources()
{
AkonadiResource::removeDuplicateResources();
}
/******************************************************************************
* Create an AkonadiResourceCreator instance.
*/
ResourceCreator* AkonadiDataModel::createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent)
{
return new AkonadiResourceCreator(defaultType, parent);
}
/******************************************************************************
* Update a resource's backend calendar file to the current KAlarm format.
*/
void AkonadiDataModel::updateCalendarToCurrentFormat(Resource& resource, bool ignoreKeepFormat, QObject* parent)
{
AkonadiCalendarUpdater::updateToCurrentFormat(resource, ignoreKeepFormat, parent);
}
/******************************************************************************
* Create model instances which are dependent on the resource data model type.
*/
ResourceListModel* AkonadiDataModel::createResourceListModel(QObject* parent)
{
return ResourceListModel::create<AkonadiDataModel>(parent);
}
ResourceFilterCheckListModel* AkonadiDataModel::createResourceFilterCheckListModel(QObject* parent)
{
return ResourceFilterCheckListModel::create<AkonadiDataModel>(parent);
}
AlarmListModel* AkonadiDataModel::createAlarmListModel(QObject* parent)
{
return AlarmListModel::create<AkonadiDataModel>(parent);
}
AlarmListModel* AkonadiDataModel::allAlarmListModel()
{
return AlarmListModel::all<AkonadiDataModel>();
}
TemplateListModel* AkonadiDataModel::createTemplateListModel(QObject* parent)
{
return TemplateListModel::create<AkonadiDataModel>(parent);
}
TemplateListModel* AkonadiDataModel::allTemplateListModel()
{
return TemplateListModel::all<AkonadiDataModel>();
}
/******************************************************************************
......
......@@ -69,12 +69,6 @@ public:
Akonadi::Collection* collection(Akonadi::Collection::Id id) const;
Akonadi::Collection* collection(const Resource&) const;
/** Reload a collection's data from Akonadi storage (not from the backend). */
bool reload(Resource&);
/** Reload all collections' data from Akonadi storage (not from the backend). */
void reload();
KAEvent event(const QString& eventId) const;
KAEvent event(const QModelIndex&) const;
using QObject::event; // prevent warning about hidden virtual method
......@@ -95,9 +89,6 @@ 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);
......@@ -107,6 +98,45 @@ Q_SIGNALS:
void serverStopped();
protected:
/** 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;
......@@ -168,8 +198,8 @@ private:
QList<KAEvent> events(ResourceId) const;
void getChildEvents(const QModelIndex& parent, QList<KAEvent>&) const;
static AkonadiDataModel* mInstance;
static int mTimeHourPos; // position of hour within time string, or -1 if leading zeroes included
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
......
/*
* datamodel.cpp - calendar data model dependent functions
* datamodel.cpp - model independent access to calendar functions
* Program: kalarm
* Copyright © 2019-2020 David Jarvie <djarvie@kde.org>
* 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
......@@ -20,94 +20,97 @@
#include "datamodel.h"
//#define USE_AKONADI
#ifdef USE_AKONADI
#include "akonadidatamodel.h"
#include "akonadiresource.h"
#include "akonadiresourcecreator.h"
#include "akonadicalendarupdater.h"
#include "eventmodel.h"
#include "resourcemodel.h"
#define DATA_MODEL AkonadiDataModel
#else
#include "fileresourcedatamodel.h"
#define DATA_MODEL FileResourceDataModel
#endif
#include <AkonadiWidgets/ControlGui>
namespace DataModel
void DataModel::initialise()
{
void initialise()
{
AkonadiDataModel* model = AkonadiDataModel::instance();
Preferences::setBackend(model->dataStorageBackend());
DATA_MODEL::instance();
// Record in kalarmrc, for information only, which backend is in use.
Preferences::setBackend(ResourceDataModelBase::mInstance->dataStorageBackend());
Preferences::self()->save();
}
void terminate()
void DataModel::terminate()
{
if (ResourceDataModelBase::mInstance)
ResourceDataModelBase::mInstance->terminate();
}
void widgetNeedsDatabase(QWidget* widget)
void DataModel::reload()
{
Akonadi::ControlGui::widgetNeedsAkonadi(widget);
if (ResourceDataModelBase::mInstance)
ResourceDataModelBase::mInstance->reload();
}
void reload()
bool DataModel::reload(Resource& resource)
{
AkonadiDataModel::instance()->reload();
return ResourceDataModelBase::mInstance && ResourceDataModelBase::mInstance->reload(resource);
}
bool reload(Resource& resource)
bool DataModel::isMigrationComplete()
{
return AkonadiDataModel::instance()->reload(resource);
return ResourceDataModelBase::mInstance && ResourceDataModelBase::mInstance->isMigrationComplete();
}
bool isMigrationComplete()
void DataModel::removeDuplicateResources()
{
return AkonadiDataModel::instance()->isMigrationComplete();
if (ResourceDataModelBase::mInstance)
ResourceDataModelBase::mInstance->removeDuplicateResources();
}
void removeDuplicateResources()
void DataModel::widgetNeedsDatabase(QWidget* widget)
{
AkonadiResource::removeDuplicateResources();
if (ResourceDataModelBase::mInstance)
ResourceDataModelBase::mInstance->widgetNeedsDatabase(widget);
}
ResourceListModel* createResourceListModel(QObject* parent)
ResourceCreator* DataModel::createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent)
{
return ResourceListModel::create<AkonadiDataModel>(parent);
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->createResourceCreator(defaultType, parent) : nullptr;
}
ResourceFilterCheckListModel* createResourceFilterCheckListModel(QObject* parent)
void DataModel::updateCalendarToCurrentFormat(Resource& resource, bool ignoreKeepFormat, QObject* parent)
{
return ResourceFilterCheckListModel::create<AkonadiDataModel>(parent);
if (ResourceDataModelBase::mInstance)
ResourceDataModelBase::mInstance->updateCalendarToCurrentFormat(resource, ignoreKeepFormat, parent);
}
AlarmListModel* createAlarmListModel(QObject* parent)
ResourceListModel* DataModel::createResourceListModel(QObject* parent)
{
return AlarmListModel::create<AkonadiDataModel>(parent);
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->createResourceListModel(parent) : nullptr;
}
AlarmListModel* allAlarmListModel()
ResourceFilterCheckListModel* DataModel::createResourceFilterCheckListModel(QObject* parent)
{
return AlarmListModel::all<AkonadiDataModel>();
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->createResourceFilterCheckListModel(parent) : nullptr;
}
TemplateListModel* createTemplateListModel(QObject* parent)
AlarmListModel* DataModel::createAlarmListModel(QObject* parent)
{
return TemplateListModel::create<AkonadiDataModel>(parent);
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->createAlarmListModel(parent) : nullptr;
}
TemplateListModel* allTemplateListModel()
AlarmListModel* DataModel::allAlarmListModel()
{
return TemplateListModel::all<AkonadiDataModel>();
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->allAlarmListModel() : nullptr;
}
ResourceCreator* createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent)
TemplateListModel* DataModel::createTemplateListModel(QObject* parent)
{
return new AkonadiResourceCreator(defaultType, parent);
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->createTemplateListModel(parent) : nullptr;
}
void updateCalendarToCurrentFormat(Resource& resource, bool ignoreKeepFormat, QObject* parent)
TemplateListModel* DataModel::allTemplateListModel()
{
AkonadiCalendarUpdater::updateToCurrentFormat(resource, ignoreKeepFormat, parent);
return ResourceDataModelBase::mInstance ? ResourceDataModelBase::mInstance->allTemplateListModel() : nullptr;
}
} // namespace DataModel
// vim: et sw=4:
/*
* datamodel.h - calendar data model dependent functions
* datamodel.h - model independent access to calendar functions
* Program: kalarm
* Copyright © 2019-2020 David Jarvie <djarvie@kde.org>
*
......@@ -29,50 +29,75 @@ class ResourceFilterCheckListModel;
class AlarmListModel;
class TemplateListModel;
class ResourceCreator;
class QObject;
class QWidget;
/** Class to create objects dependent on data model. */
namespace DataModel
{
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.
*/
void reload();
/** Reload a resource's data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
bool reload(Resource&);
bool isMigrationComplete();
/** Check for, and remove, any duplicate Akonadi resources, i.e. those which
* use the same calendar file/directory.
*/
void removeDuplicateResources();
ResourceListModel* createResourceListModel(QObject* parent);
ResourceFilterCheckListModel* createResourceFilterCheckListModel(QObject* parent);
AlarmListModel* createAlarmListModel(QObject* parent);
AlarmListModel* allAlarmListModel();
TemplateListModel* createTemplateListModel(QObject* parent);
TemplateListModel* allTemplateListModel();
ResourceCreator* createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent);
void updateCalendarToCurrentFormat(Resource&, bool ignoreKeepFormat, QObject* parent);
} // namespace DataModel
/*=============================================================================
= Class: DataModel
= Static methods providing model independent access to the resource data model.
=============================================================================*/
class DataModel
{
public:
/** Initialise the data model. */
static void initialise();
/** Terminate access to the data model, and tidy up. */
static void terminate();
/** Reload all resources' data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
static void reload();
/** Reload a resource's data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
static bool reload(Resource&);
/** Return whether calendar migration/creation at initialisation has completed. */
static bool isMigrationComplete();
/** Check for, and remove, any duplicate Akonadi resources, i.e. those which
* use the same calendar file/directory.
*/
static void removeDuplicateResources();
/** Disable the widget if the database engine is not available, and display an
* error overlay.
*/
static void widgetNeedsDatabase(QWidget*);
/** Create a ResourceCreator instance for the model. */
static ResourceCreator* createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent);
/** Update a resource's backend calendar file to the current KAlarm format. */
static void updateCalendarToCurrentFormat(Resource&, bool ignoreKeepFormat, QObject* parent);
static ResourceListModel* createResourceListModel(QObject* parent);
static ResourceFilterCheckListModel* createResourceFilterCheckListModel(QObject* parent);
static AlarmListModel* createAlarmListModel(QObject* parent);
static AlarmListModel* allAlarmListModel();
static TemplateListModel* createTemplateListModel(QObject* parent);
static TemplateListModel* allTemplateListModel();
#if 0
static QSize iconSize() { return mIconSize; }
/** Return a bulleted list of alarm types for inclusion in an i18n message. */
static QString typeListForDisplay(CalEvent::Types);
/** Get the tooltip for a resource. The resource's enabled status is
* evaluated for specified alarm types. */
QString tooltip(const Resource&, CalEvent::Types) const;
/** Return the read-only status tooltip for a resource.
* A null string is returned if the resource is fully writable. */
static QString readOnlyTooltip(const Resource&);
/** Return offset to add to headerData() role, for item models. */
virtual int headerDataEventRoleOffset() const { return 0; }
#endif
};
#endif // DATAMODEL_H
......
......@@ -49,6 +49,8 @@ QString timeToAlarmText(const DateTime& dateTime);
= Class: ResourceDataModelBase
=============================================================================*/
ResourceDataModelBase* ResourceDataModelBase::mInstance = nullptr;
QPixmap* ResourceDataModelBase::mTextIcon = nullptr;
QPixmap* ResourceDataModelBase::mFileIcon = nullptr;
QPixmap* ResourceDataModelBase::mCommandIcon = nullptr;
......
......@@ -30,6 +30,11 @@
#include <QSize>
class Resource;
class ResourceListModel;
class ResourceFilterCheckListModel;
class AlarmListModel;
class TemplateListModel;
class ResourceCreator;
class QModelIndex;
class QPixmap;
......@@ -79,11 +84,7 @@ 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; }
static QSize iconSize() { return mIconSize; }
/** Return a bulleted list of alarm types for inclusion in an i18n message. */
static QString typeListForDisplay(CalEvent::Types);
......@@ -99,12 +100,48 @@ public:
/** Return offset to add to headerData() role, for item models. */
virtual int headerDataEventRoleOffset() const { return 0; }
/** Return whether calendar migration/creation at initialisation has completed. */
bool isMigrationComplete() const;
protected:
ResourceDataModelBase();
/** Terminate access to the data model, and tidy up. */
virtual void terminate() = 0;
/** Reload all resources' data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
virtual void reload() = 0;
/** Reload a resource's data from storage.
* @note In the case of Akonadi, this does not reload from the backend storage.
*/
virtual bool reload(Resource&) = 0;
/** Check for, and remove, any duplicate resources, i.e. those which use
* the same calendar file/directory.
*/
virtual void removeDuplicateResources() = 0;
/** Disable the widget if the database engine is not available, and display
* an error overlay.
*/
virtual void widgetNeedsDatabase(QWidget*) = 0;
/** Create a ResourceCreator instance for the model. */
virtual ResourceCreator* createResourceCreator(KAlarmCal::CalEvent::Type defaultType, QWidget* parent) = 0;
/** Update a resource's backend calendar file to the current KAlarm format. */
virtual void updateCalendarToCurrentFormat(Resource&, bool ignoreKeepFormat, QObject* parent) = 0;
virtual ResourceListModel* createResourceListModel(QObject* parent) = 0;
virtual ResourceFilterCheckListModel* createResourceFilterCheckListModel(QObject* parent) = 0;
virtual AlarmListModel* createAlarmListModel(QObject* parent) = 0;
virtual AlarmListModel* allAlarmListModel() = 0;
virtual TemplateListModel* createTemplateListModel(QObject* parent) = 0;
virtual TemplateListModel* allTemplateListModel() = 0;
/** Return the data storage backend type used by this model. */
virtual Preferences::Backend dataStorageBackend() const = 0;
static QVariant headerData(int section, Qt::Orientation, int role, bool eventHeaders, bool& handled);
/** Return whether resourceData() and/or eventData() handle a role. */
......@@ -124,6 +161,9 @@ protected:
/** Called when a resource notifies a message to display to the user. */
void handleResourceMessage(ResourceType::MessageType, const QString& message, const QString& details);
/** Return whether calendar migration/creation at initialisation has completed. */
bool isMigrationComplete() const;
/** Return whether calendar migration is currently in progress. */
bool isMigrating() const;
......@@ -138,6 +178,8 @@ protected:
static QString whatsThisText(int column);
static QPixmap* eventIcon(const KAEvent&);
static ResourceDataModelBase* mInstance;
private:
static QPixmap* mTextIcon;
static QPixmap* mFileIcon;
......@@ -147,6 +189,8 @@ private: