Commit d553d6cf authored by Claudio Cambra's avatar Claudio Cambra
Browse files

Simplify incidenceoccurrencemodel, rename things to match their function, add...


Simplify incidenceoccurrencemodel, rename things to match their function, add loading state indication

Signed-off-by: Claudio Cambra's avatarClaudio Cambra <claudio.cambra@gmail.com>
parent ffd277a9
Pipeline #248380 failed with stage
in 3 minutes and 16 seconds
......@@ -20,26 +20,27 @@ IncidenceOccurrenceModel::IncidenceOccurrenceModel(QObject *parent)
: QAbstractListModel(parent)
, m_coreCalendar(nullptr)
{
mRefreshTimer.setSingleShot(true);
QObject::connect(&mRefreshTimer, &QTimer::timeout, this, &IncidenceOccurrenceModel::updateFromSource);
m_resetThrottlingTimer.setSingleShot(true);
QObject::connect(&m_resetThrottlingTimer, &QTimer::timeout, this, &IncidenceOccurrenceModel::resetFromSource);
KSharedConfig::Ptr config = KSharedConfig::openConfig();
KConfigGroup rColorsConfig(config, "Resources Colors");
m_colorWatcher = KConfigWatcher::create(config);
// This is quite slow; would be nice to find a quicker way
QObject::connect(m_colorWatcher.data(), &KConfigWatcher::configChanged, this, &IncidenceOccurrenceModel::updateFromSource);
load();
connect(m_colorWatcher.data(), &KConfigWatcher::configChanged, this, &IncidenceOccurrenceModel::resetFromSource);
}
void IncidenceOccurrenceModel::setStart(const QDate &start)
{
if (start != mStart) {
mStart = start;
updateQuery();
Q_EMIT startChanged();
if(start == mStart) {
return;
}
mStart = start;
Q_EMIT startChanged();
mEnd = mStart.addDays(mLength);
}
QDate IncidenceOccurrenceModel::start() const
......@@ -53,8 +54,10 @@ void IncidenceOccurrenceModel::setLength(int length)
return;
}
mLength = length;
updateQuery();
Q_EMIT lengthChanged();
mEnd = mStart.addDays(mLength);
scheduleReset();
}
int IncidenceOccurrenceModel::length() const
......@@ -70,57 +73,72 @@ Filter *IncidenceOccurrenceModel::filter() const
void IncidenceOccurrenceModel::setFilter(Filter *filter)
{
mFilter = filter;
updateQuery();
Q_EMIT filterChanged();
scheduleReset();
}
void IncidenceOccurrenceModel::updateQuery()
bool IncidenceOccurrenceModel::loading() const
{
if (!m_coreCalendar) {
return m_loading;
}
void IncidenceOccurrenceModel::setLoading(const bool loading)
{
if(loading == m_loading) {
return;
}
if (!mLength || !mStart.isValid()) {
refreshView();
m_loading = loading;
Q_EMIT loadingChanged();
}
int IncidenceOccurrenceModel::resetThrottleInterval() const
{
return m_resetThrottleInterval;
}
void IncidenceOccurrenceModel::setResetThrottleInterval(const int resetThrottleInterval)
{
if(resetThrottleInterval == m_resetThrottleInterval) {
return;
}
mEnd = mStart.addDays(mLength);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::dataChanged, this, &IncidenceOccurrenceModel::slotSourceDataChanged);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::rowsInserted, this, &IncidenceOccurrenceModel::slotSourceRowsInserted);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::rowsRemoved, this, &IncidenceOccurrenceModel::refreshView);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::modelReset, this, &IncidenceOccurrenceModel::refreshView);
QObject::connect(m_coreCalendar.get(), &Akonadi::ETMCalendar::collectionsRemoved, this, &IncidenceOccurrenceModel::refreshView);
refreshView();
m_resetThrottleInterval = resetThrottleInterval;
Q_EMIT resetThrottleIntervalChanged();
}
void IncidenceOccurrenceModel::refreshView()
void IncidenceOccurrenceModel::scheduleReset()
{
if (!mRefreshTimer.isActive()) {
// Instant update, but then only refresh every 100ms max.
mRefreshTimer.start(100);
if (!m_resetThrottlingTimer.isActive()) {
// Instant update, but then only refresh every interval at most.
m_resetThrottlingTimer.start(m_resetThrottleInterval);
}
}
void IncidenceOccurrenceModel::updateFromSource()
void IncidenceOccurrenceModel::resetFromSource()
{
if (!m_coreCalendar || mRefreshTimer.isActive()) {
if (!m_coreCalendar) {
return;
} else if (m_coreCalendar->isLoading()) {
}
setLoading(true);
if (m_resetThrottlingTimer.isActive() || m_coreCalendar->isLoading()) {
// If calendar is still loading then just schedule a refresh later
refreshView();
// If refresh timer already active this won't restart it
scheduleReset();
return;
}
load();
loadColors();
beginResetModel();
m_incidences.clear();
m_occurrenceIndexHash.clear();
KCalendarCore::OccurrenceIterator occurrenceIterator{*m_coreCalendar, QDateTime{mStart, {0, 0, 0}}, QDateTime{mEnd, {12, 59, 59}}};
KCalendarCore::OccurrenceIterator occurrenceIterator(*m_coreCalendar, QDateTime(mStart, {0, 0, 0}), QDateTime(mEnd, {12, 59, 59}));
while (occurrenceIterator.hasNext()) {
occurrenceIterator.next();
......@@ -153,14 +171,18 @@ void IncidenceOccurrenceModel::updateFromSource()
}
endResetModel();
setLoading(false);
}
void IncidenceOccurrenceModel::slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight)
{
if (!m_coreCalendar || !upperLeft.isValid() || !bottomRight.isValid() || mRefreshTimer.isActive()) {
if (!m_coreCalendar || !upperLeft.isValid() || !bottomRight.isValid() || m_resetThrottlingTimer.isActive()) {
return;
}
setLoading(true);
const auto startRow = upperLeft.row();
const auto endRow = bottomRight.row();
......@@ -203,17 +225,21 @@ void IncidenceOccurrenceModel::slotSourceDataChanged(const QModelIndex &upperLef
Q_EMIT dataChanged(existingOccurrenceIndex, existingOccurrenceIndex);
}
}
setLoading(false);
}
void IncidenceOccurrenceModel::slotSourceRowsInserted(const QModelIndex &parent, const int first, const int last)
{
if (!m_coreCalendar || mRefreshTimer.isActive()) {
if (!m_coreCalendar || m_resetThrottlingTimer.isActive()) {
return;
} else if (m_coreCalendar->isLoading()) {
mRefreshTimer.start(100);
m_resetThrottlingTimer.start(m_resetThrottleInterval);
return;
}
setLoading(true);
for (int i = first; i <= last; ++i) {
const auto sourceModelIndex = m_coreCalendar->model()->index(i, 0, parent);
const auto incidenceItem = sourceModelIndex.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
......@@ -263,6 +289,8 @@ void IncidenceOccurrenceModel::slotSourceRowsInserted(const QModelIndex &parent,
m_occurrenceIndexHash.insert(occurrenceHashKey, persistentIndex);
}
}
setLoading(false);
}
int IncidenceOccurrenceModel::rowCount(const QModelIndex &parent) const
......@@ -397,8 +425,16 @@ void IncidenceOccurrenceModel::setCalendar(Akonadi::ETMCalendar::Ptr calendar)
return;
}
m_coreCalendar = calendar;
updateQuery();
connect(m_coreCalendar->model(), &QAbstractItemModel::dataChanged, this, &IncidenceOccurrenceModel::slotSourceDataChanged);
connect(m_coreCalendar->model(), &QAbstractItemModel::rowsInserted, this, &IncidenceOccurrenceModel::slotSourceRowsInserted);
connect(m_coreCalendar->model(), &QAbstractItemModel::rowsRemoved, this, &IncidenceOccurrenceModel::scheduleReset);
connect(m_coreCalendar->model(), &QAbstractItemModel::modelReset, this, &IncidenceOccurrenceModel::scheduleReset);
connect(m_coreCalendar.get(), &Akonadi::ETMCalendar::collectionsRemoved, this, &IncidenceOccurrenceModel::scheduleReset);
Q_EMIT calendarChanged();
scheduleReset();
}
Akonadi::ETMCalendar::Ptr IncidenceOccurrenceModel::calendar() const
......@@ -406,7 +442,7 @@ Akonadi::ETMCalendar::Ptr IncidenceOccurrenceModel::calendar() const
return m_coreCalendar;
}
void IncidenceOccurrenceModel::load()
void IncidenceOccurrenceModel::loadColors()
{
KSharedConfig::Ptr config = KSharedConfig::openConfig();
KConfigGroup rColorsConfig(config, "Resources Colors");
......
......@@ -43,6 +43,8 @@ class IncidenceOccurrenceModel : public QAbstractListModel
Q_PROPERTY(int length READ length WRITE setLength NOTIFY lengthChanged)
Q_PROPERTY(Filter *filter READ filter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(Akonadi::ETMCalendar::Ptr calendar READ calendar WRITE setCalendar NOTIFY calendarChanged)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(int resetThrottleInterval READ resetThrottleInterval WRITE setResetThrottleInterval NOTIFY resetThrottleIntervalChanged)
public:
enum Roles {
......@@ -81,6 +83,8 @@ public:
QDate start() const;
int length() const;
Filter *filter() const;
bool loading() const;
int resetThrottleInterval() const;
struct Occurrence {
QDateTime start;
......@@ -96,22 +100,26 @@ Q_SIGNALS:
void lengthChanged();
void filterChanged();
void calendarChanged();
void loadingChanged();
void resetThrottleIntervalChanged();
public Q_SLOTS:
void setStart(const QDate &start);
void setLength(int length);
void setFilter(Filter *filter);
void setCalendar(Akonadi::ETMCalendar::Ptr calendar);
void setResetThrottleInterval(const int resetThrottleInterval);
private Q_SLOTS:
void load();
void refreshView();
void updateQuery();
void updateFromSource();
void loadColors();
void scheduleReset();
void resetFromSource();
void slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight);
void slotSourceRowsInserted(const QModelIndex &parent, const int first, const int last);
void setLoading(const bool loading);
private:
static std::pair<QDateTime, QDateTime> incidenceOccurrenceStartEnd(const QDateTime &ocStart, const KCalendarCore::Incidence::Ptr &incidence);
static uint incidenceOccurrenceHash(const QDateTime &ocStart, const QDateTime &ocEnd, const QString &incidenceUid);
......@@ -126,10 +134,11 @@ private:
int mLength{0};
Akonadi::ETMCalendar::Ptr m_coreCalendar;
QTimer mRefreshTimer;
QTimer m_resetThrottlingTimer;
int m_resetThrottleInterval = 100;
// We need it to be ordered for the model
QVector<Occurrence> m_incidences;
bool m_loading = false;
QVector<Occurrence> m_incidences; // We need incidences to be in a preditable order for the model
QHash<uint, QPersistentModelIndex> m_occurrenceIndexHash;
QHash<QString, QColor> m_colors;
KConfigWatcher::Ptr m_colorWatcher;
......
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