diff --git a/src/librssguard/core/feeddownloader.cpp b/src/librssguard/core/feeddownloader.cpp index c9cadc6d3..95778dbb6 100644 --- a/src/librssguard/core/feeddownloader.cpp +++ b/src/librssguard/core/feeddownloader.cpp @@ -9,6 +9,7 @@ #include "miscellaneous/application.h" #include "services/abstract/cacheforserviceroot.h" #include "services/abstract/feed.h" +#include "services/abstract/labelsnode.h" #include #include @@ -115,7 +116,10 @@ void FeedDownloader::updateOneFeed(Feed* feed) { MessageFilter::initializeFilteringEngine(filter_engine); // Create JavaScript communication wrapper for the message. - MessageObject msg_obj(&database, feed->customId(), feed->getParentServiceRoot()->accountId()); + MessageObject msg_obj(&database, + feed->customId(), + feed->getParentServiceRoot()->accountId(), + feed->getParentServiceRoot()->labelsNode()->labels()); // Register the wrapper. auto js_object = filter_engine.newQObject(&msg_obj); @@ -196,6 +200,30 @@ void FeedDownloader::updateOneFeed(Feed* feed) { important_msgs << *msg_orig; } + // Process changed labels. + for (Label* lbl : msg_backup.m_assignedLabels) { + if (!msg_orig->m_assignedLabels.contains(lbl)) { + // Label is not there anymore, it was deassigned. + lbl->deassignFromMessage(*msg_orig); + + qDebugNN << "It was detected that label" << QUOTE_W_SPACE(lbl->customId()) + << "was DEASSIGNED from message" << QUOTE_W_SPACE(msg_orig->m_customId) + << "by message filter(s)."; + } + } + + for (Label* lbl : msg_orig->m_assignedLabels) { + if (!msg_backup.m_assignedLabels.contains(lbl)) { + // Label is in new message, but is not in old message, it + // was newly assigned. + lbl->assignToMessage(*msg_orig); + + qDebugNN << "It was detected that label" << QUOTE_W_SPACE(lbl->customId()) + << "was ASSIGNED to message" << QUOTE_W_SPACE(msg_orig->m_customId) + << "by message filter(s)."; + } + } + if (remove_msg) { msgs.removeAt(i--); } diff --git a/src/librssguard/core/message.cpp b/src/librssguard/core/message.cpp index 606eb2408..6291d2971 100644 --- a/src/librssguard/core/message.cpp +++ b/src/librssguard/core/message.cpp @@ -2,6 +2,7 @@ #include "core/message.h" +#include "3rd-party/boolinq/boolinq.h" #include "miscellaneous/textfactory.h" #include "services/abstract/label.h" @@ -158,8 +159,11 @@ uint qHash(const Message& key) { return (uint(key.m_accountId) * 10000) + uint(key.m_id); } -MessageObject::MessageObject(QSqlDatabase* db, const QString& feed_custom_id, int account_id, QObject* parent) - : QObject(parent), m_db(db), m_feedCustomId(feed_custom_id), m_accountId(account_id), m_message(nullptr) {} +MessageObject::MessageObject(QSqlDatabase* db, const QString& feed_custom_id, + int account_id, QList available_labels, + QObject* parent) + : QObject(parent), m_db(db), m_feedCustomId(feed_custom_id), m_accountId(account_id), m_message(nullptr), + m_availableLabels(available_labels) {} void MessageObject::setMessage(Message* message) { m_message = message; @@ -244,6 +248,37 @@ bool MessageObject::isDuplicateWithAttribute(int attribute_check) const { return false; } +bool MessageObject::assignLabel(QString label_custom_id) const { + Label* lbl = boolinq::from(m_availableLabels).firstOrDefault([label_custom_id](Label* lbl) { + return lbl->customId() == label_custom_id; + }); + + if (lbl != nullptr) { + if (!m_message->m_assignedLabels.contains(lbl)) { + m_message->m_assignedLabels.append(lbl); + } + + return true; + } + else { + return false; + } +} + +bool MessageObject::deassignLabel(QString label_custom_id) const { + Label* lbl = boolinq::from(m_message->m_assignedLabels).firstOrDefault([label_custom_id](Label* lbl) { + return lbl->customId() == label_custom_id; + }); + + if (lbl != nullptr) { + m_message->m_assignedLabels.removeAll(lbl); + return true; + } + else { + return false; + } +} + QString MessageObject::title() const { return m_message->m_title; } @@ -311,3 +346,7 @@ int MessageObject::accountId() const { QList MessageObject::assignedLabels() const { return m_message->m_assignedLabels; } + +QList MessageObject::availableLabels() const { + return m_availableLabels; +} diff --git a/src/librssguard/core/message.h b/src/librssguard/core/message.h index 81ac8841a..5d88e743e 100644 --- a/src/librssguard/core/message.h +++ b/src/librssguard/core/message.h @@ -121,6 +121,7 @@ class MessageObject : public QObject { Q_OBJECT Q_PROPERTY(QList assignedLabels READ assignedLabels) + Q_PROPERTY(QList availableLabels READ availableLabels) Q_PROPERTY(QString feedCustomId READ feedCustomId) Q_PROPERTY(int accountId READ accountId) Q_PROPERTY(QString title READ title WRITE setTitle) @@ -132,7 +133,9 @@ class MessageObject : public QObject { Q_PROPERTY(bool isImportant READ isImportant WRITE setIsImportant) public: - explicit MessageObject(QSqlDatabase* db, const QString& feed_custom_id, int account_id, QObject* parent = nullptr); + explicit MessageObject(QSqlDatabase* db, const QString& feed_custom_id, + int account_id, QList available_labels, + QObject* parent = nullptr); void setMessage(Message* message); @@ -141,7 +144,17 @@ class MessageObject : public QObject { // value casted to int. Q_INVOKABLE bool isDuplicateWithAttribute(int attribute_check) const; + // Adds given label to list of assigned labels to this message. + // Returns true if label was assigned now or if the message already has it assigned. + Q_INVOKABLE bool assignLabel(QString label_custom_id) const; + + // Removes given label from list of assigned labels of this message. + // Returns true if label was now removed or if it is not assigned to the message at all. + Q_INVOKABLE bool deassignLabel(QString label_custom_id) const; + + // Returns list of assigned and available messages. QList assignedLabels() const; + QList availableLabels() const; // Generic Message's properties bindings. QString feedCustomId() const; @@ -173,6 +186,7 @@ class MessageObject : public QObject { QString m_feedCustomId; int m_accountId; Message* m_message; + QList m_availableLabels; }; #endif // MESSAGE_H diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp index 9d86803b4..ce66b21e4 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp @@ -153,7 +153,7 @@ void FormMessageFiltersManager::testFilter() { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); // Create JavaScript communication wrapper for the message. - MessageObject msg_obj(&database, QString::number(NO_PARENT_CATEGORY), NO_PARENT_CATEGORY); + MessageObject msg_obj(&database, QString::number(NO_PARENT_CATEGORY), NO_PARENT_CATEGORY, {}); // Register the wrapper. auto js_object = filter_engine.newQObject(&msg_obj); diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 33f460846..9d2ee73b8 100755 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -116,7 +116,7 @@ QString s_customLogFile = QString(); void Application::performLogging(QtMsgType type, const QMessageLogContext& context, const QString& msg) { #ifndef QT_NO_DEBUG_OUTPUT QString console_message = qFormatLogMessage(type, context, msg); - std::wcout << console_message.toStdWString() << std::endl; + std::cout << console_message.toStdString() << std::endl; if (!s_customLogFile.isEmpty()) { QFile log_file(s_customLogFile); @@ -581,7 +581,8 @@ void Application::determineFirstRuns() { void Application::parseCmdArguments() { QCommandLineOption log_file(QStringList() << CLI_LOG_SHORT << CLI_LOG_LONG, - "Write application debug log to file.", "log-file"); + "Write application debug log to file. Note that logging to file may slow application down.", + "log-file"); QCommandLineOption custom_data_folder(QStringList() << CLI_DAT_SHORT << CLI_DAT_LONG, "Use custom folder for user data and disable single instance application mode.", "user-data-folder"); diff --git a/src/librssguard/services/abstract/label.cpp b/src/librssguard/services/abstract/label.cpp index cbd9259cb..576f4478c 100755 --- a/src/librssguard/services/abstract/label.cpp +++ b/src/librssguard/services/abstract/label.cpp @@ -110,7 +110,10 @@ QIcon Label::generateIcon(const QColor& color) { } void Label::assignToMessage(const Message& msg) { - QSqlDatabase database = qApp->database()->connection(metaObject()->className()); + bool is_main_thread = QThread::currentThread() == qApp->thread(); + QSqlDatabase database = is_main_thread ? + qApp->database()->connection(metaObject()->className()) : + qApp->database()->connection(QSL("feed_upd")); if (getParentServiceRoot()->onBeforeLabelMessageAssignmentChanged({ this }, { msg }, true)) { DatabaseQueries::assignLabelToMessage(database, this, msg); @@ -120,7 +123,10 @@ void Label::assignToMessage(const Message& msg) { } void Label::deassignFromMessage(const Message& msg) { - QSqlDatabase database = qApp->database()->connection(metaObject()->className()); + bool is_main_thread = QThread::currentThread() == qApp->thread(); + QSqlDatabase database = is_main_thread ? + qApp->database()->connection(metaObject()->className()) : + qApp->database()->connection(QSL("feed_upd")); if (getParentServiceRoot()->onBeforeLabelMessageAssignmentChanged({ this }, { msg }, false)) { DatabaseQueries::deassignLabelFromMessage(database, this, msg); diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h index fa079a320..c999f5395 100644 --- a/src/librssguard/services/abstract/rootitem.h +++ b/src/librssguard/services/abstract/rootitem.h @@ -23,6 +23,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { // Added for message filtering with labels. Q_PROPERTY(QString title READ title) + Q_PROPERTY(QString customId READ customId) public: enum class ReadStatus {