// For license of this file, see /LICENSE.md. #include "services/abstract/cacheforserviceroot.h" #include "3rd-party/boolinq/boolinq.h" #include "miscellaneous/application.h" #include "miscellaneous/mutex.h" #include "services/abstract/label.h" #include #include CacheForServiceRoot::CacheForServiceRoot() : m_uniqueId(NO_PARENT_CATEGORY), m_cacheSaveMutex(new QMutex()) {} CacheForServiceRoot::~CacheForServiceRoot() {} void CacheForServiceRoot::addLabelsAssignmentsToCache(const QStringList& ids_of_messages, const QString& lbl_custom_id, bool assign) { if (assign) { for (const QString& custom_id : ids_of_messages) { if (m_cachedLabelDeassignments[lbl_custom_id].contains(custom_id)) { // We want to assign this ID but it was marked for deassignment, remove from deassignment. m_cachedLabelDeassignments[lbl_custom_id].removeAll(custom_id); } else { m_cachedLabelAssignments[lbl_custom_id].append(custom_id); m_cachedLabelAssignments[lbl_custom_id].removeDuplicates(); } } } else { for (const QString& custom_id : ids_of_messages) { if (m_cachedLabelAssignments[lbl_custom_id].contains(custom_id)) { // We want to deassign this ID but it was marked for assignment, remove from assignment. m_cachedLabelAssignments[lbl_custom_id].removeAll(custom_id); } else { m_cachedLabelDeassignments[lbl_custom_id].append(custom_id); m_cachedLabelDeassignments[lbl_custom_id].removeDuplicates(); } } } saveCacheToFile(); } void CacheForServiceRoot::addLabelsAssignmentsToCache(const QList& ids_of_messages, Label* lbl, bool assign) { auto custom_ids = lbl->getParentServiceRoot()->customIDsOfMessages(ids_of_messages); addLabelsAssignmentsToCache(custom_ids, lbl->customId(), assign); } void CacheForServiceRoot::addMessageStatesToCache(const QList& ids_of_messages, RootItem::Importance importance) { QMutexLocker lck(m_cacheSaveMutex.data()); QList& list_act = m_cachedStatesImportant[importance]; QList& list_other = m_cachedStatesImportant[importance == RootItem::Importance::Important ? RootItem::Importance::NotImportant : RootItem::Importance::Important]; // Store changes, they will be sent to server later. list_act.append(ids_of_messages); #if QT_VERSION >= 0x050E00 // Qt >= 5.14.0 QSet set_act(list_act.begin(), list_act.end()); QSet set_other(list_other.begin(), list_other.end()); #else QSet set_act = list_act.toSet(); QSet set_other = list_other.toSet(); #endif // Now, we want to remove all IDS from list_other, which are contained in list. set_other -= set_act; list_act.clear(); list_act.append(set_act.values()); list_other.clear(); list_other.append(set_other.values()); saveCacheToFile(); } void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read) { QMutexLocker lck(m_cacheSaveMutex.data()); QStringList& list_act = m_cachedStatesRead[read]; QStringList& list_other = m_cachedStatesRead[read == RootItem::ReadStatus::Read ? RootItem::ReadStatus::Unread : RootItem::ReadStatus::Read]; // Store changes, they will be sent to server later. list_act.append(ids_of_messages); #if QT_VERSION >= 0x050E00 // Qt >= 5.14.0 QSet set_act(list_act.begin(), list_act.end()); QSet set_other(list_other.begin(), list_other.end()); #else QSet set_act = list_act.toSet(); QSet set_other = list_other.toSet(); #endif // Now, we want to remove all IDS from list_other, which are contained in list. set_other -= set_act; list_act.clear(); list_act.append(set_act.values()); list_other.clear(); list_other.append(set_other.values()); saveCacheToFile(); } void CacheForServiceRoot::saveCacheToFile() { // Save to file. const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(m_uniqueId) + "-cached-msgs.dat"; if (isEmpty()) { QFile::remove(file_cache); } else { QFile file(file_cache); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QDataStream stream(&file); stream << m_cachedStatesImportant << m_cachedStatesRead << m_cachedLabelAssignments << m_cachedLabelDeassignments; file.flush(); file.close(); } } } void CacheForServiceRoot::clearCache() { m_cachedStatesRead.clear(); m_cachedStatesImportant.clear(); m_cachedLabelAssignments.clear(); m_cachedLabelDeassignments.clear(); } void CacheForServiceRoot::loadCacheFromFile() { QMutexLocker lck(m_cacheSaveMutex.data()); clearCache(); // Load from file. const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(m_uniqueId) + "-cached-msgs.dat"; QFile file(file_cache); if (file.exists()) { if (file.open(QIODevice::OpenModeFlag::ReadOnly)) { QDataStream stream(&file); stream >> m_cachedStatesImportant >> m_cachedStatesRead >> m_cachedLabelAssignments >> m_cachedLabelDeassignments; file.close(); } } } void CacheForServiceRoot::setUniqueId(int unique_id) { m_uniqueId = unique_id; } CacheSnapshot CacheForServiceRoot::takeMessageCache() { QMutexLocker lck(m_cacheSaveMutex.data()); if (isEmpty()) { return CacheSnapshot(); } // Make copy of changes. 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(); cached_data_imp.detach(); cached_ass_lbl.detach(); cached_deass_lbl.detach(); clearCache(); saveCacheToFile(); 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 { return m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty() && m_cachedLabelAssignments.isEmpty() && m_cachedLabelDeassignments.isEmpty(); }