Fix Cache logic to support labels.

This commit is contained in:
Martin Rotter 2020-10-22 11:30:45 +02:00
parent 9b8ad9546b
commit 3cf7d6edea
9 changed files with 105 additions and 38 deletions

View File

@ -12,20 +12,32 @@
CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new QMutex(QMutex::NonRecursive)) {}
void CacheForServiceRoot::addMessageStatesToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign) {
void CacheForServiceRoot::addLabelsAssignmentsToCache(const QList<Message>& 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<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> CacheForServiceRoot::takeMessageCache() {
CacheSnapshot CacheForServiceRoot::takeMessageCache() {
QMutexLocker lck(m_cacheSaveMutex.data());
if (isEmpty()) {
return QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>>();
return CacheSnapshot();
}
// Make copy of changes.
QMap<RootItem::ReadStatus, QStringList> 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<RootItem::Importance, QList<Message>> cached_data_imp = m_cachedStatesImportant;
cached_data_imp.detach();
cached_ass_lbl.detach();
cached_deass_lbl.detach();
clearCache();
return QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>>(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 {

View File

@ -11,11 +11,18 @@
class QMutex;
struct CacheSnapshot {
QMap<QString, QStringList> m_cachedLabelAssignments;
QMap<QString, QStringList> m_cachedLabelDeassignments;
QMap<RootItem::ReadStatus, QStringList> m_cachedStatesRead;
QMap<RootItem::Importance, QList<Message>> m_cachedStatesImportant;
};
class CacheForServiceRoot {
public:
explicit CacheForServiceRoot();
void addMessageStatesToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign);
void addLabelsAssignmentsToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign);
void addMessageStatesToCache(const QList<Message>& 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<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> takeMessageCache();
CacheSnapshot takeMessageCache();
QScopedPointer<QMutex> m_cacheSaveMutex;

View File

@ -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) {

View File

@ -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<Mes
return true;
}
bool ServiceRoot::onBeforeLabelMessageAssignmentChanged(const QList<Label*> labels, const QList<Message>& messages, bool assign) {
auto cache = dynamic_cast<CacheForServiceRoot*>(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<Label*> labels, const QList<Message>& 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<RootItem*>(lbl);
}).toStdList();
getParentServiceRoot()->itemChanged(FROM_STD_LIST(QList<RootItem*>, list));
return true;
}
bool ServiceRoot::onBeforeMessagesRestoredFromBin(RootItem* selected_item, const QList<Message>& messages) {
Q_UNUSED(selected_item)
Q_UNUSED(messages)

View File

@ -123,6 +123,12 @@ class ServiceRoot : public RootItem {
// by the user from message list.
virtual bool onAfterMessagesDelete(RootItem* selected_item, const QList<Message>& messages);
// Called BEFORE some labels are assigned/deassigned from/to messages.
virtual bool onBeforeLabelMessageAssignmentChanged(const QList<Label*> labels, const QList<Message>& messages, bool assign);
// Called AFTER some labels are assigned/deassigned from/to messages.
virtual bool onAfterLabelMessageAssignmentChanged(const QList<Label*> labels, const QList<Message>& 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.

View File

@ -209,8 +209,8 @@ QString GmailServiceRoot::additionalTooltip() const {
}
void GmailServiceRoot::saveAllCachedData(bool async) {
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> msgCache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msgCache.first);
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
// Save the actual data read/unread.
while (i.hasNext()) {
@ -223,7 +223,7 @@ void GmailServiceRoot::saveAllCachedData(bool async) {
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msgCache.second);
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {

View File

@ -133,8 +133,8 @@ RootItem* InoreaderServiceRoot::obtainNewTreeForSyncIn() const {
}
void InoreaderServiceRoot::saveAllCachedData(bool async) {
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> msgCache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msgCache.first);
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
// Save the actual data read/unread.
while (i.hasNext()) {
@ -147,7 +147,7 @@ void InoreaderServiceRoot::saveAllCachedData(bool async) {
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msgCache.second);
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {

View File

@ -86,8 +86,8 @@ OwnCloudNetworkFactory* OwnCloudServiceRoot::network() const {
}
void OwnCloudServiceRoot::saveAllCachedData(bool async) {
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> msgCache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msgCache.first);
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
// Save the actual data read/unread.
while (i.hasNext()) {
@ -100,7 +100,7 @@ void OwnCloudServiceRoot::saveAllCachedData(bool async) {
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msgCache.second);
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {

View File

@ -117,8 +117,8 @@ bool TtRssServiceRoot::canBeDeleted() const {
}
void TtRssServiceRoot::saveAllCachedData(bool async) {
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> msgCache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msgCache.first);
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
// Save the actual data read/unread.
while (i.hasNext()) {
@ -136,7 +136,7 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msgCache.second);
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {