Navigation Menu

Skip to content

Commit

Permalink
[nemo-qml-plugin-calendar] Prevent flicker of attendees. Contributes …
Browse files Browse the repository at this point in the history
…to JB#32993

The CalendarWorker observes storageModified() signals sent from mkcal.
In mkcal side, when storageModified() is emitted, loaded ranges are
invalidated and must be re-loaded.  Thus, when CalendarWorker observes
the storageModified() signal, it tells the CalendarManager that it
needs to rebuild its required ranges (from connected AgendaModel
and currently active EventQuery instances).  The CalendarManager
then asks the CalendarWorker to load instances within that range
into the calendar from storage.

If an EventQuery is refreshed as part of this process, it previously
always emitted attendeesChanged() even if the data in the backend
remained the same.  This commit ensures that we load the data from
the backend, and compare it to the currently cached data, and only
emit attendeesChanged() if they are indeed different.

Finally, it guards against a race condition case where if multiple
storageModified() signals are received in sequence, the some attempts
to load the attendees may fail due to the storage having invalidated
its loaded ranges.  In this case, the results we receive back will
be invalid, and should be ignored (and in this case, the data for
the event will be reloaded again, as triggered by storageModified()).
  • Loading branch information
Chris Adams committed Mar 27, 2020
1 parent 9c36ae2 commit 1ba0729
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 18 deletions.
14 changes: 11 additions & 3 deletions src/calendardata.h
Expand Up @@ -87,11 +87,19 @@ struct Notebook {
typedef QPair<QDate,QDate> Range;

struct Attendee {
bool isOrganizer;
bool isOrganizer = false;
QString name;
QString email;
KCalCore::Attendee::Role participationRole;
KCalCore::Attendee::PartStat status;
KCalCore::Attendee::Role participationRole = KCalCore::Attendee::OptParticipant;
KCalCore::Attendee::PartStat status = KCalCore::Attendee::None;

bool operator==(const Attendee &other) const {
return isOrganizer == other.isOrganizer
&& name == other.name
&& email == other.email
&& participationRole == other.participationRole
&& status == other.status;
}
};

struct EmailContact {
Expand Down
25 changes: 16 additions & 9 deletions src/calendareventquery.cpp
Expand Up @@ -140,8 +140,11 @@ QObject *CalendarEventQuery::occurrence() const
QList<QObject*> CalendarEventQuery::attendees()
{
if (!mAttendeesCached) {
mAttendees = CalendarManager::instance()->getEventAttendees(mUid, mRecurrenceId);
mAttendeesCached = true;
bool resultValid = false;
mAttendees = CalendarManager::instance()->getEventAttendees(mUid, mRecurrenceId, &resultValid);
if (resultValid) {
mAttendeesCached = true;
}
}

return CalendarUtils::convertAttendeeList(mAttendees);
Expand Down Expand Up @@ -187,9 +190,8 @@ void CalendarEventQuery::doRefresh(CalendarData::Event event)
mOccurrence = 0;

if (mEvent.isValid()) {
CalendarEventOccurrence *occurrence = CalendarManager::instance()->getNextOccurrence(mUid,
mRecurrenceId,
mStartTime);
CalendarEventOccurrence *occurrence = CalendarManager::instance()->getNextOccurrence(
mUid, mRecurrenceId, mStartTime);
if (occurrence) {
mOccurrence = occurrence;
mOccurrence->setParent(this);
Expand All @@ -201,10 +203,15 @@ void CalendarEventQuery::doRefresh(CalendarData::Event event)
if (signalEventChanged)
emit eventChanged();

// always emit also attendee change signal
mAttendees.clear();
mAttendeesCached = false;
emit attendeesChanged();
// check if attendees have changed.
bool resultValid = false;
QList<CalendarData::Attendee> attendees = CalendarManager::instance()->getEventAttendees(
mUid, mRecurrenceId, &resultValid);
if (resultValid && mAttendees != attendees) {
mAttendees = attendees;
mAttendeesCached = true;
emit attendeesChanged();
}
}

KDateTime CalendarEventQuery::recurrenceId()
Expand Down
25 changes: 20 additions & 5 deletions src/calendarmanager.cpp
Expand Up @@ -702,13 +702,28 @@ CalendarEventOccurrence* CalendarManager::getNextOccurrence(const QString &uid,
return new CalendarEventOccurrence(eo.eventUid, eo.recurrenceId, eo.startTime, eo.endTime);
}

QList<CalendarData::Attendee> CalendarManager::getEventAttendees(const QString &uid, const KDateTime &recurrenceId)
QList<CalendarData::Attendee> CalendarManager::getEventAttendees(const QString &uid, const KDateTime &recurrenceId, bool *resultValid)
{
QList<CalendarData::Attendee> attendees;
QMetaObject::invokeMethod(mCalendarWorker, "getEventAttendees", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QList<CalendarData::Attendee>, attendees),
Q_ARG(QString, uid),
Q_ARG(KDateTime, recurrenceId));

// Not foolproof, since thread interleaving means we might
// receive a storageModified() signal on the worker thread
// while we're dispatching this call here.
// But, this will at least ensure that if we _know_ that
// the storage is not in loaded state, that we don't
// attempt to read the invalid data.
// The other alternative would be to cache all attendee
// info in the event struct immediately within
// CalendarWorker::createEventStruct(), however it was
// decided that it would be better to avoid the memory usage.
*resultValid = !(mLoadPending || mResetPending);
if (*resultValid) {
QMetaObject::invokeMethod(mCalendarWorker, "getEventAttendees", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QList<CalendarData::Attendee>, attendees),
Q_ARG(QString, uid),
Q_ARG(KDateTime, recurrenceId));
}

return attendees;
}

Expand Down
2 changes: 1 addition & 1 deletion src/calendarmanager.h
Expand Up @@ -111,7 +111,7 @@ class CalendarManager : public QObject
CalendarEventOccurrence* getNextOccurrence(const QString &uid, const KDateTime &recurrenceId,
const QDateTime &start);
// return attendees for given event, synchronous call
QList<CalendarData::Attendee> getEventAttendees(const QString &uid, const KDateTime &recurrenceId);
QList<CalendarData::Attendee> getEventAttendees(const QString &uid, const KDateTime &recurrenceId, bool *resultValid);

private slots:
void storageModifiedSlot(const QString &info);
Expand Down

0 comments on commit 1ba0729

Please sign in to comment.