From 3cf7d6edeab7eb834f584e809ac406b513b293b8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 22 Oct 2020 11:30:45 +0200 Subject: [PATCH] Fix Cache logic to support labels. --- .../services/abstract/cacheforserviceroot.cpp | 59 +++++++++++++------ .../services/abstract/cacheforserviceroot.h | 11 +++- src/librssguard/services/abstract/label.cpp | 14 +++-- .../services/abstract/serviceroot.cpp | 29 +++++++++ .../services/abstract/serviceroot.h | 6 ++ .../services/gmail/gmailserviceroot.cpp | 6 +- .../inoreader/inoreaderserviceroot.cpp | 6 +- .../services/owncloud/owncloudserviceroot.cpp | 6 +- .../services/tt-rss/ttrssserviceroot.cpp | 6 +- 9 files changed, 105 insertions(+), 38 deletions(-) diff --git a/src/librssguard/services/abstract/cacheforserviceroot.cpp b/src/librssguard/services/abstract/cacheforserviceroot.cpp index 4790edaa2..eed3cbd70 100644 --- a/src/librssguard/services/abstract/cacheforserviceroot.cpp +++ b/src/librssguard/services/abstract/cacheforserviceroot.cpp @@ -12,20 +12,32 @@ CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new QMutex(QMutex::NonRecursive)) {} -void CacheForServiceRoot::addMessageStatesToCache(const QList& ids_of_messages, Label* lbl, bool assign) { +void CacheForServiceRoot::addLabelsAssignmentsToCache(const QList& ids_of_messages, Label* lbl, bool assign) { auto custom_ids = lbl->getParentServiceRoot()->customIDsOfMessages(ids_of_messages); if (assign) { - m_cachedLabelAssignments[lbl->customId()].append(custom_ids); - m_cachedLabelAssignments[lbl->customId()].removeDuplicates(); - - // Remove the same messages from "deassign" list. - auto deassign = m_cachedLabelDeassignments[lbl->customId()]; - auto list = boolinq::from(deassign.begin(), deassign.end()).where([custom_ids](const QString& id) { - return !custom_ids.contains(id); - }).toStdList(); - - m_cachedLabelDeassignments[lbl->customId()] = FROM_STD_LIST(QStringList, list); + for (const QString& custom_id : custom_ids) { + if (m_cachedLabelDeassignments[lbl->customId()].contains(custom_id)) { + // We want to assign this ID but it was marked for deassignment, remove from deassignment. + m_cachedLabelDeassignments[lbl->customId()].removeAll(custom_id); + } + else { + m_cachedLabelAssignments[lbl->customId()].append(custom_id); + m_cachedLabelAssignments[lbl->customId()].removeDuplicates(); + } + } + } + else { + for (const QString& custom_id : custom_ids) { + if (m_cachedLabelAssignments[lbl->customId()].contains(custom_id)) { + // We want to deassign this ID but it was marked for assignment, remove from assignment. + m_cachedLabelAssignments[lbl->customId()].removeAll(custom_id); + } + else { + m_cachedLabelDeassignments[lbl->customId()].append(custom_id); + m_cachedLabelDeassignments[lbl->customId()].removeDuplicates(); + } + } } } @@ -108,6 +120,8 @@ void CacheForServiceRoot::saveCacheToFile(int acc_id) { void CacheForServiceRoot::clearCache() { m_cachedStatesRead.clear(); m_cachedStatesImportant.clear(); + m_cachedLabelAssignments.clear(); + m_cachedLabelDeassignments.clear(); } void CacheForServiceRoot::loadCacheFromFile(int acc_id) { @@ -132,25 +146,34 @@ void CacheForServiceRoot::loadCacheFromFile(int acc_id) { } } -QPair, QMap>> CacheForServiceRoot::takeMessageCache() { +CacheSnapshot CacheForServiceRoot::takeMessageCache() { QMutexLocker lck(m_cacheSaveMutex.data()); if (isEmpty()) { - return QPair, QMap>>(); + return CacheSnapshot(); } // Make copy of changes. - QMap cached_data_read = m_cachedStatesRead; + auto cached_data_read = m_cachedStatesRead; + auto cached_data_imp = m_cachedStatesImportant; + auto cached_ass_lbl = m_cachedLabelAssignments; + auto cached_deass_lbl = m_cachedLabelDeassignments; cached_data_read.detach(); - - QMap> cached_data_imp = m_cachedStatesImportant; - cached_data_imp.detach(); + cached_ass_lbl.detach(); + cached_deass_lbl.detach(); clearCache(); - return QPair, QMap>>(cached_data_read, cached_data_imp); + CacheSnapshot c; + + c.m_cachedLabelAssignments = cached_ass_lbl; + c.m_cachedLabelDeassignments = cached_deass_lbl; + c.m_cachedStatesImportant = cached_data_imp; + c.m_cachedStatesRead = cached_data_read; + + return c; } bool CacheForServiceRoot::isEmpty() const { diff --git a/src/librssguard/services/abstract/cacheforserviceroot.h b/src/librssguard/services/abstract/cacheforserviceroot.h index d260da7ef..f460ba294 100644 --- a/src/librssguard/services/abstract/cacheforserviceroot.h +++ b/src/librssguard/services/abstract/cacheforserviceroot.h @@ -11,11 +11,18 @@ class QMutex; +struct CacheSnapshot { + QMap m_cachedLabelAssignments; + QMap m_cachedLabelDeassignments; + QMap m_cachedStatesRead; + QMap> m_cachedStatesImportant; +}; + class CacheForServiceRoot { public: explicit CacheForServiceRoot(); - void addMessageStatesToCache(const QList& ids_of_messages, Label* lbl, bool assign); + void addLabelsAssignmentsToCache(const QList& ids_of_messages, Label* lbl, bool assign); void addMessageStatesToCache(const QList& ids_of_messages, RootItem::Importance importance); void addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read); @@ -27,7 +34,7 @@ class CacheForServiceRoot { virtual void saveAllCachedData(bool async = true) = 0; protected: - QPair, QMap>> takeMessageCache(); + CacheSnapshot takeMessageCache(); QScopedPointer m_cacheSaveMutex; diff --git a/src/librssguard/services/abstract/label.cpp b/src/librssguard/services/abstract/label.cpp index 1c453c76e..bc60ef0fd 100755 --- a/src/librssguard/services/abstract/label.cpp +++ b/src/librssguard/services/abstract/label.cpp @@ -104,19 +104,21 @@ QIcon Label::generateIcon(const QColor& color) { void Label::assignToMessage(const Message& msg) { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); - DatabaseQueries::assignLabelToMessage(database, this, msg); + if (getParentServiceRoot()->onBeforeLabelMessageAssignmentChanged({this}, {msg}, true)) { + DatabaseQueries::assignLabelToMessage(database, this, msg); - updateCounts(true); - getParentServiceRoot()->itemChanged({ this }); + getParentServiceRoot()->onAfterLabelMessageAssignmentChanged({this}, {msg}, true); + } } void Label::deassignFromMessage(const Message& msg) { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); - DatabaseQueries::deassignLabelFromMessage(database, this, msg); + if (getParentServiceRoot()->onBeforeLabelMessageAssignmentChanged({this}, {msg}, false)) { + DatabaseQueries::deassignLabelFromMessage(database, this, msg); - updateCounts(true); - getParentServiceRoot()->itemChanged({ this }); + getParentServiceRoot()->onAfterLabelMessageAssignmentChanged({this}, {msg}, false); + } } void Label::setCountOfAllMessages(int totalCount) { diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index ccf6a354b..9202338c5 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -2,6 +2,7 @@ #include "services/abstract/serviceroot.h" +#include "3rd-party/boolinq/boolinq.h" #include "core/feedsmodel.h" #include "core/messagesmodel.h" #include "miscellaneous/application.h" @@ -616,6 +617,34 @@ bool ServiceRoot::onAfterMessagesDelete(RootItem* selected_item, const QList labels, const QList& messages, bool assign) { + auto cache = dynamic_cast(this); + + if (cache != nullptr) { + boolinq::from(labels).for_each([cache, messages, assign](Label* lbl) { + cache->addLabelsAssignmentsToCache(messages, lbl, assign); + }); + } + + return true; +} + +bool ServiceRoot::onAfterLabelMessageAssignmentChanged(const QList labels, const QList& messages, bool assign) { + Q_UNUSED(messages) + Q_UNUSED(assign) + + boolinq::from(labels).for_each([](Label* lbl) { + lbl->updateCounts(true); + }); + + auto list = boolinq::from(labels).select([](Label* lbl) { + return static_cast(lbl); + }).toStdList(); + + getParentServiceRoot()->itemChanged(FROM_STD_LIST(QList, list)); + return true; +} + bool ServiceRoot::onBeforeMessagesRestoredFromBin(RootItem* selected_item, const QList& messages) { Q_UNUSED(selected_item) Q_UNUSED(messages) diff --git a/src/librssguard/services/abstract/serviceroot.h b/src/librssguard/services/abstract/serviceroot.h index cd8d6d985..00effd7fa 100644 --- a/src/librssguard/services/abstract/serviceroot.h +++ b/src/librssguard/services/abstract/serviceroot.h @@ -123,6 +123,12 @@ class ServiceRoot : public RootItem { // by the user from message list. virtual bool onAfterMessagesDelete(RootItem* selected_item, const QList& messages); + // Called BEFORE some labels are assigned/deassigned from/to messages. + virtual bool onBeforeLabelMessageAssignmentChanged(const QList labels, const QList& messages, bool assign); + + // Called AFTER some labels are assigned/deassigned from/to messages. + virtual bool onAfterLabelMessageAssignmentChanged(const QList labels, const QList& messages, bool assign); + // Called BEFORE the list of messages is about to be restored from recycle bin // by the user from message list. // Selected item is naturally recycle bin. diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 10713826c..f0f2dbda6 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -209,8 +209,8 @@ QString GmailServiceRoot::additionalTooltip() const { } void GmailServiceRoot::saveAllCachedData(bool async) { - QPair, QMap>> msgCache = takeMessageCache(); - QMapIterator i(msgCache.first); + auto msg_cache = takeMessageCache(); + QMapIterator i(msg_cache.m_cachedStatesRead); // Save the actual data read/unread. while (i.hasNext()) { @@ -223,7 +223,7 @@ void GmailServiceRoot::saveAllCachedData(bool async) { } } - QMapIterator> j(msgCache.second); + QMapIterator> j(msg_cache.m_cachedStatesImportant); // Save the actual data important/not important. while (j.hasNext()) { diff --git a/src/librssguard/services/inoreader/inoreaderserviceroot.cpp b/src/librssguard/services/inoreader/inoreaderserviceroot.cpp index b1ae91945..096e59fe8 100644 --- a/src/librssguard/services/inoreader/inoreaderserviceroot.cpp +++ b/src/librssguard/services/inoreader/inoreaderserviceroot.cpp @@ -133,8 +133,8 @@ RootItem* InoreaderServiceRoot::obtainNewTreeForSyncIn() const { } void InoreaderServiceRoot::saveAllCachedData(bool async) { - QPair, QMap>> msgCache = takeMessageCache(); - QMapIterator i(msgCache.first); + auto msg_cache = takeMessageCache(); + QMapIterator i(msg_cache.m_cachedStatesRead); // Save the actual data read/unread. while (i.hasNext()) { @@ -147,7 +147,7 @@ void InoreaderServiceRoot::saveAllCachedData(bool async) { } } - QMapIterator> j(msgCache.second); + QMapIterator> j(msg_cache.m_cachedStatesImportant); // Save the actual data important/not important. while (j.hasNext()) { diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.cpp b/src/librssguard/services/owncloud/owncloudserviceroot.cpp index 8ed555d2a..0059df94f 100644 --- a/src/librssguard/services/owncloud/owncloudserviceroot.cpp +++ b/src/librssguard/services/owncloud/owncloudserviceroot.cpp @@ -86,8 +86,8 @@ OwnCloudNetworkFactory* OwnCloudServiceRoot::network() const { } void OwnCloudServiceRoot::saveAllCachedData(bool async) { - QPair, QMap>> msgCache = takeMessageCache(); - QMapIterator i(msgCache.first); + auto msg_cache = takeMessageCache(); + QMapIterator i(msg_cache.m_cachedStatesRead); // Save the actual data read/unread. while (i.hasNext()) { @@ -100,7 +100,7 @@ void OwnCloudServiceRoot::saveAllCachedData(bool async) { } } - QMapIterator> j(msgCache.second); + QMapIterator> j(msg_cache.m_cachedStatesImportant); // Save the actual data important/not important. while (j.hasNext()) { diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp index b92bdec20..4f8557f30 100644 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp +++ b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp @@ -117,8 +117,8 @@ bool TtRssServiceRoot::canBeDeleted() const { } void TtRssServiceRoot::saveAllCachedData(bool async) { - QPair, QMap>> msgCache = takeMessageCache(); - QMapIterator i(msgCache.first); + auto msg_cache = takeMessageCache(); + QMapIterator i(msg_cache.m_cachedStatesRead); // Save the actual data read/unread. while (i.hasNext()) { @@ -136,7 +136,7 @@ void TtRssServiceRoot::saveAllCachedData(bool async) { } } - QMapIterator> j(msgCache.second); + QMapIterator> j(msg_cache.m_cachedStatesImportant); // Save the actual data important/not important. while (j.hasNext()) {