Commit 1b3ce728 authored by Claudio Cambra's avatar Claudio Cambra
Browse files

More efficiently update multidayincidencemodel when datachanged emitted from source model



Signed-off-by: Claudio Cambra's avatarClaudio Cambra <claudio.cambra@gmail.com>
parent c7970346
......@@ -86,7 +86,7 @@ void IncidenceOccurrenceModel::updateQuery()
}
mEnd = mStart.addDays(mLength);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::dataChanged, this, &IncidenceOccurrenceModel::refreshView);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::dataChanged, this, &IncidenceOccurrenceModel::slotSourceDataChanged);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::rowsInserted, this, &IncidenceOccurrenceModel::refreshView);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::rowsRemoved, this, &IncidenceOccurrenceModel::refreshView);
QObject::connect(m_coreCalendar->model(), &QAbstractItemModel::modelReset, this, &IncidenceOccurrenceModel::refreshView);
......@@ -146,11 +146,6 @@ void IncidenceOccurrenceModel::updateFromSource()
}
}
if(start.date() > mEnd || end.date() < mStart) {
qDebug() << "Skipping incidence:" << incidence->summary() << mStart << start << mEnd << end;
continue;
}
const auto occurrenceHashKey = qHash(QString::number(start.toSecsSinceEpoch()) +
QString::number(end.toSecsSinceEpoch()) +
incidence->uid());
......@@ -164,12 +159,6 @@ void IncidenceOccurrenceModel::updateFromSource()
};
if (m_occurrenceIndexHash.contains(occurrenceHashKey)) {
const auto existingOccurrenceIndex = m_occurrenceIndexHash.value(occurrenceHashKey);
const auto existingOccurrenceRow = existingOccurrenceIndex.row();
m_incidences.replace(existingOccurrenceRow, occurrence);
Q_EMIT dataChanged(existingOccurrenceIndex, existingOccurrenceIndex);
deadKeysSet.remove(occurrenceHashKey);
} else {
const auto indexRow = m_incidences.count();
......@@ -196,6 +185,66 @@ void IncidenceOccurrenceModel::updateFromSource()
}
}
void IncidenceOccurrenceModel::slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight)
{
if (!m_coreCalendar || !upperLeft.isValid() || !bottomRight.isValid()) {
return;
}
const auto startRow = upperLeft.row();
const auto endRow = bottomRight.row();
for (int i = startRow; i <= endRow; ++i) {
const auto sourceModelIndex = m_coreCalendar->model()->index(i, 0);
const auto incidenceItem = sourceModelIndex.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
if(!incidenceItem.isValid() || !incidenceItem.hasPayload<KCalendarCore::Incidence::Ptr>()) {
continue;
}
const auto incidence = incidenceItem.payload<KCalendarCore::Incidence::Ptr>();
KCalendarCore::OccurrenceIterator occurrenceIterator{*m_coreCalendar, incidence, QDateTime{mStart, {0, 0, 0}}, QDateTime{mEnd, {12, 59, 59}}};
while (occurrenceIterator.hasNext()) {
occurrenceIterator.next();
auto start = occurrenceIterator.occurrenceStartDate();
const auto end = incidence->endDateForStart(start);
if (incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeTodo) {
KCalendarCore::Todo::Ptr todo = incidence.staticCast<KCalendarCore::Todo>();
if (!start.isValid()) { // Todos are very likely not to have a set start date
start = todo->dtDue();
}
}
const auto occurrenceHashKey = qHash(QString::number(start.toSecsSinceEpoch()) +
QString::number(end.toSecsSinceEpoch()) +
incidence->uid());
if(!m_occurrenceIndexHash.contains(occurrenceHashKey)) {
continue;
}
const Occurrence occurrence{
start,
end,
incidence,
getColor(incidence),
getCollectionId(incidence),
incidence->allDay(),
};
const auto existingOccurrenceIndex = m_occurrenceIndexHash.value(occurrenceHashKey);
const auto existingOccurrenceRow = existingOccurrenceIndex.row();
m_incidences.replace(existingOccurrenceRow, occurrence);
Q_EMIT dataChanged(existingOccurrenceIndex, existingOccurrenceIndex);
}
}
}
int IncidenceOccurrenceModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
......
......@@ -106,6 +106,9 @@ Q_SIGNALS:
void filterChanged();
void calendarChanged();
private Q_SLOTS:
void slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight);
private:
void refreshView();
void updateFromSource();
......
......@@ -10,14 +10,11 @@
#include <QBitArray>
MultiDayIncidenceModel::MultiDayIncidenceModel(QObject *parent)
: QAbstractItemModel(parent)
: QAbstractListModel(parent)
{
mRefreshTimer.setSingleShot(true);
mRefreshTimer.callOnTimeout(this, [this] {
beginResetModel();
endResetModel();
Q_EMIT incidenceCountChanged();
});
mRefreshTimer.setInterval(100);
mRefreshTimer.callOnTimeout(this, &MultiDayIncidenceModel::resetLayoutLines);
m_config = KalendarConfig::self();
QObject::connect(m_config, &KalendarConfig::showSubtodosInCalendarViewsChanged, this, [&]() {
......@@ -26,23 +23,6 @@ MultiDayIncidenceModel::MultiDayIncidenceModel(QObject *parent)
});
}
QModelIndex MultiDayIncidenceModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent)) {
return {};
}
if (!parent.isValid()) {
return createIndex(row, column);
}
return {};
}
QModelIndex MultiDayIncidenceModel::parent(const QModelIndex &) const
{
return {};
}
int MultiDayIncidenceModel::rowCount(const QModelIndex &parent) const
{
// Number of weeks
......@@ -52,11 +32,6 @@ int MultiDayIncidenceModel::rowCount(const QModelIndex &parent) const
return 0;
}
int MultiDayIncidenceModel::columnCount(const QModelIndex &) const
{
return 1;
}
static long long getDuration(const QDate &start, const QDate &end)
{
return qMax(start.daysTo(end) + 1, 1ll);
......@@ -244,20 +219,41 @@ QVariantList MultiDayIncidenceModel::layoutLines(const QDate &rowStart) const
return result;
}
QVariant MultiDayIncidenceModel::data(const QModelIndex &idx, int role) const
void MultiDayIncidenceModel::resetLayoutLines()
{
if (!hasIndex(idx.row(), idx.column())) {
return {};
beginResetModel();
m_laidOutLines.clear();
const auto numPeriods = rowCount({});
m_laidOutLines.reserve(numPeriods);
qDebug() << numPeriods;
for(int i = 0; i < numPeriods; ++i) {
const auto periodStart = mSourceModel->start().addDays(i * mPeriodLength);
const auto periodIncidenceLayout = layoutLines(periodStart);
m_laidOutLines.append(periodIncidenceLayout);
}
if (!mSourceModel) {
Q_EMIT incidenceCountChanged();
endResetModel();
}
QVariant MultiDayIncidenceModel::data(const QModelIndex &idx, int role) const
{
if (!hasIndex(idx.row(), idx.column()) || !mSourceModel || m_laidOutLines.empty()) {
return {};
}
const auto rowStart = mSourceModel->start().addDays(idx.row() * mPeriodLength);
switch (role) {
case PeriodStartDate:
{
const auto rowStart = mSourceModel->start().addDays(idx.row() * mPeriodLength);
return rowStart.startOfDay();
}
case Incidences:
return layoutLines(rowStart);
return m_laidOutLines.at(idx.row());
default:
Q_ASSERT(false);
return {};
......@@ -273,20 +269,61 @@ void MultiDayIncidenceModel::setModel(IncidenceOccurrenceModel *model)
{
beginResetModel();
m_laidOutLines.clear();
mSourceModel = model;
Q_EMIT modelChanged();
endResetModel();
auto resetModel = [this] {
if (!mRefreshTimer.isActive()) {
mRefreshTimer.start(100);
}
};
QObject::connect(model, &QAbstractItemModel::dataChanged, this, resetModel);
QObject::connect(model, &QAbstractItemModel::dataChanged, this, &MultiDayIncidenceModel::slotSourceDataChanged);
QObject::connect(model, &QAbstractItemModel::layoutChanged, this, resetModel);
QObject::connect(model, &QAbstractItemModel::modelReset, this, resetModel);
QObject::connect(model, &QAbstractItemModel::rowsInserted, this, resetModel);
QObject::connect(model, &QAbstractItemModel::rowsMoved, this, resetModel);
QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, resetModel);
endResetModel();
mRefreshTimer.start(100);
}
void MultiDayIncidenceModel::slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight)
{
if(!upperLeft.isValid() || !bottomRight.isValid()) {
return;
}
const auto startRow = upperLeft.row();
const auto endRow = bottomRight.row();
for (int i = startRow; i <= endRow; ++i) {
const auto sourceModelIndex = mSourceModel->index(i);
const auto occurrence = sourceModelIndex.data(IncidenceOccurrenceModel::IncidenceOccurrence).value<IncidenceOccurrenceModel::Occurrence>();
const auto sourceModelStartDate = mSourceModel->start();
const auto startDaysFromSourceStart = sourceModelStartDate.daysTo(occurrence.start.date());
const auto endDaysFromSourceStart = sourceModelStartDate.daysTo(occurrence.end.date());
const auto firstPeriodOccurrenceAppears = startDaysFromSourceStart / mPeriodLength;
const auto lastPeriodOccurrenceAppears = endDaysFromSourceStart / mPeriodLength;
qDebug() << occurrence.incidence->summary() << firstPeriodOccurrenceAppears << lastPeriodOccurrenceAppears;
if(firstPeriodOccurrenceAppears > m_laidOutLines.count() || lastPeriodOccurrenceAppears < 0) {
continue;
}
for (int i = firstPeriodOccurrenceAppears; i <= lastPeriodOccurrenceAppears; ++i) {
const auto periodStart = mSourceModel->start().addDays(i * mPeriodLength);
const auto idx = index(i, 0);
m_laidOutLines.replace(i, layoutLines(periodStart));
Q_EMIT dataChanged(idx, idx);
}
}
}
int MultiDayIncidenceModel::periodLength() const
......
......@@ -24,7 +24,7 @@ class Incidence;
* The "incidences" roles provides a list of lists, where each list represents a visual line,
* containing a number of events to display.
*/
class MultiDayIncidenceModel : public QAbstractItemModel
class MultiDayIncidenceModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int periodLength READ periodLength WRITE setPeriodLength NOTIFY periodLengthChanged)
......@@ -50,14 +50,8 @@ public:
explicit MultiDayIncidenceModel(QObject *parent = nullptr);
~MultiDayIncidenceModel() override = default;
QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
IncidenceOccurrenceModel *model();
......@@ -78,12 +72,18 @@ Q_SIGNALS:
protected:
void setIncidenceCount(int incidenceCount);
private Q_SLOTS:
void resetLayoutLines();
void slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight);
private:
QTimer mRefreshTimer;
QList<QModelIndex> sortedIncidencesFromSourceModel(const QDate &rowStart) const;
QVariantList layoutLines(const QDate &rowStart) const;
QTimer mRefreshTimer;
IncidenceOccurrenceModel *mSourceModel{nullptr};
int mPeriodLength{7};
QVector<QVariantList> m_laidOutLines;
int mPeriodLength = 7;
MultiDayIncidenceModel::Filters m_filters;
KalendarConfig *m_config = nullptr;
};
......
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