From 40402f6c7a2b96989ae1f5df709a2eafdcf28249 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 27 Jul 2020 08:36:37 +0200 Subject: [PATCH 1/6] lang sync --- localization/rssguard_pt.ts | 30 ++++++++++++++++-------------- localization/rssguard_sv.ts | 30 ++++++++++++++++-------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/localization/rssguard_pt.ts b/localization/rssguard_pt.ts index 5ae13cd3b..cf6635d20 100644 --- a/localization/rssguard_pt.ts +++ b/localization/rssguard_pt.ts @@ -448,7 +448,7 @@ Clique para abrir a pasta de destino. E-mail address - + Endereço de e-mail @@ -737,7 +737,7 @@ ou esta função ainda não foi implementada. GNU GPL License (applies to RSS Guard and mimesis source code) - + Licença GNU GPL (aplica-se ao código fonte do RSS Guard e mimesis) @@ -771,19 +771,19 @@ ou esta função ainda não foi implementada. Subject - + Assunto Title of your message - + Título da sua mensagem E-mail NOT sent - + E-mail NÃO enviado Your e-mail message wasn't sent. - + Sua mensagem de e-mail não foi enviada. @@ -1047,7 +1047,7 @@ ou esta função ainda não foi implementada. Specified redirect URL must start with "http://localhost" and must be configured in your OAuth "application". - + A URL de redirecionamento especificada deve começar com "http://localhost" e deve ser configurada no "aplicativo" OAuth. @@ -1146,13 +1146,15 @@ ou esta função ainda não foi implementada. Get my own Application ID - + Obter minha própria ID de Aplicativo Specified redirect URL must start with "http://localhost" and must be configured in your OAuth "application". It is highly recommended to create your own "Application ID". - + A URL de redirecionamento especificada deve começar com "http://localhost" e deve ser configurada no "aplicativo" OAuth. + +É altamente recomendado criar seu próprio "ID de Aplicativo". @@ -2309,7 +2311,7 @@ It is highly recommended to create your own "Application ID". Cannot save new filter, error: ''. - + Não foi possível salvar o novo filtro, erro: ". @@ -2880,15 +2882,15 @@ Você pode instalá-lo agora. you aren't logged in - + você não está logado not logged-in - + não logado comm error when asking for recipients - + erro comm ao perguntar por destinatários @@ -3523,7 +3525,7 @@ versão, clicando nesta notificação popup. Cannot insert message filter, because current database cannot return last inserted row ID. - + Não é possível inserir o filtro de mensagens, porque o banco de dados atual não pode retornar o último ID da linha inserida. diff --git a/localization/rssguard_sv.ts b/localization/rssguard_sv.ts index 2d8fd3f12..946302ea9 100644 --- a/localization/rssguard_sv.ts +++ b/localization/rssguard_sv.ts @@ -448,7 +448,7 @@ Klicka här för att öppna målmappen. E-mail address - + E-postadress @@ -737,7 +737,7 @@ att funktionen inte är implementerad än. GNU GPL License (applies to RSS Guard and mimesis source code) - + GNU GPL Licens (gäller RSS Guard och mimesis källkod) @@ -771,19 +771,19 @@ att funktionen inte är implementerad än. Subject - + Ämne Title of your message - + Meddelandetitel E-mail NOT sent - + E-postmeddelande INTE skickat Your e-mail message wasn't sent. - + Ditt e-postmeddelande skickades inte. @@ -1047,7 +1047,7 @@ att funktionen inte är implementerad än. Specified redirect URL must start with "http://localhost" and must be configured in your OAuth "application". - + Angiven omdirigerings-URL måste börja med "http://localhost" och måste konfigureras i ditt "OAuth-program". @@ -1146,13 +1146,15 @@ att funktionen inte är implementerad än. Get my own Application ID - + Skapa mitt eget applikations-ID Specified redirect URL must start with "http://localhost" and must be configured in your OAuth "application". It is highly recommended to create your own "Application ID". - + Angiven omdirigerings-URL måste börja med "http://localhost" och måste konfigureras i ditt "OAuth-program". + +Det rekommenderas starkt att du skapar ditt eget applikations-ID. @@ -2309,7 +2311,7 @@ It is highly recommended to create your own "Application ID". Cannot save new filter, error: ''. - + Kan inte spara nytt filter, fel: ". @@ -2879,15 +2881,15 @@ Du kan installera det nu. you aren't logged in - + Du är inte inloggad not logged-in - + Inte inloggad comm error when asking for recipients - + comm-fel när mottagare efterfrågas @@ -3522,7 +3524,7 @@ genom att klicka på denna popup-avisering. Cannot insert message filter, because current database cannot return last inserted row ID. - + Kan inte infoga meddelandefilter eftersom den aktuella databasen inte kan returnera senast infogat rad-ID. From 0b2e1df83d5893abff695f787325971e82c3cb3b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 27 Jul 2020 10:54:09 +0200 Subject: [PATCH 2/6] small refactoring --- .../services/abstract/serviceroot.cpp | 17 ++++++++- .../services/abstract/serviceroot.h | 10 ++++-- .../services/gmail/gmailserviceroot.cpp | 6 ++++ .../services/gmail/gmailserviceroot.h | 3 +- .../services/gmail/gui/formaddeditemail.cpp | 11 +++++- .../services/gmail/gui/formaddeditemail.h | 1 + .../inoreader/inoreaderserviceroot.cpp | 15 +++----- .../services/inoreader/inoreaderserviceroot.h | 3 +- .../services/owncloud/owncloudserviceroot.cpp | 16 +++------ .../services/owncloud/owncloudserviceroot.h | 6 +--- .../services/standard/standardfeed.cpp | 25 +++++++------ .../services/standard/standardserviceroot.cpp | 36 +++++++++++-------- .../services/standard/standardserviceroot.h | 11 +++--- .../services/tt-rss/ttrssserviceroot.cpp | 16 +++------ .../services/tt-rss/ttrssserviceroot.h | 7 ++-- 15 files changed, 100 insertions(+), 83 deletions(-) diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index 802558281..b2938252c 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -72,8 +72,23 @@ QList ServiceRoot::contextMenu() { return serviceMenu(); } +QList ServiceRoot::contextMenuForMessages(const QList& messages) { + Q_UNUSED(messages) + return {}; +} + QList ServiceRoot::serviceMenu() { - return QList(); + if (m_serviceMenu.isEmpty() && isSyncable()) { + m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this); + connect(m_actionSyncIn, &QAction::triggered, this, &ServiceRoot::syncIn); + m_serviceMenu.append(m_actionSyncIn); + } + + return m_serviceMenu; +} + +bool ServiceRoot::isSyncable() const { + return false; } void ServiceRoot::start(bool freshly_activated) { diff --git a/src/librssguard/services/abstract/serviceroot.h b/src/librssguard/services/abstract/serviceroot.h index 796b81c62..3cf8d5f83 100644 --- a/src/librssguard/services/abstract/serviceroot.h +++ b/src/librssguard/services/abstract/serviceroot.h @@ -54,13 +54,17 @@ class ServiceRoot : public RootItem { virtual QList addItemMenu(); // Returns actions to display as context menu. - QList contextMenu(); + virtual QList contextMenu(); + virtual QList contextMenuForMessages(const QList& messages); // Returns list of specific actions to be shown in main window menu // bar in sections "Services -> 'this service'". // NOTE: Caller does NOT take ownership of created menu! virtual QList serviceMenu(); + // If plugin uses online synchronization, then returns true. + virtual bool isSyncable() const; + // Start/stop services. // Start method is called when feed model gets initialized OR after user adds new service. // Account should synchronously initialize its children (load them from DB is recommended @@ -204,10 +208,12 @@ class ServiceRoot : public RootItem { virtual QMap storeCustomFeedsData(); virtual void restoreCustomFeedsData(const QMap& data, const QHash& feeds); - private: + protected: RecycleBin* m_recycleBin; ImportantNode* m_importantNode; int m_accountId; + QAction* m_actionSyncIn; + QList m_serviceMenu; }; #endif // SERVICEROOT_H diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 321bc94d0..4a8785704 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -130,6 +130,8 @@ bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { QList GmailServiceRoot::serviceMenu() { if (m_serviceMenu.isEmpty()) { + ServiceRoot::serviceMenu(); + QAction* act_new_email = new QAction(qApp->icons()->fromTheme(QSL("mail-message-new")), tr("Write new e-mail message"), this); connect(act_new_email, &QAction::triggered, this, &GmailServiceRoot::writeNewEmail); @@ -139,6 +141,10 @@ QList GmailServiceRoot::serviceMenu() { return m_serviceMenu; } +bool GmailServiceRoot::isSyncable() const { + return true; +} + bool GmailServiceRoot::canBeEdited() const { return true; } diff --git a/src/librssguard/services/gmail/gmailserviceroot.h b/src/librssguard/services/gmail/gmailserviceroot.h index 9fa8c3325..035d618ea 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.h +++ b/src/librssguard/services/gmail/gmailserviceroot.h @@ -23,6 +23,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { GmailNetworkFactory* network() const; QList serviceMenu(); + bool isSyncable() const; bool canBeEdited() const; bool editViaGui(); bool canBeDeleted() const; @@ -48,9 +49,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { void loadFromDatabase(); private: - QList m_serviceMenu; GmailNetworkFactory* m_network; - }; inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) { diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index 580f0f42d..f9a60b02e 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -12,7 +12,8 @@ #include "services/gmail/gui/emailrecipientcontrol.h" #include "services/gmail/network/gmailnetworkfactory.h" -FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) : QDialog(parent), m_root(root) { +FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) + : QDialog(parent), m_root(root), m_originalMessage(nullptr) { m_ui.setupUi(this); GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("mail-message-new"))); @@ -39,6 +40,14 @@ void FormAddEditEmail::execForAdd() { exec(); } +void FormAddEditEmail::execForReply(Message* original_message) { + m_originalMessage = original_message; + + addRecipientRow(m_originalMessage->m_author); + m_ui.m_txtSubject->setText(QSL("Re:%1").arg(m_originalMessage->m_title)); + exec(); +} + void FormAddEditEmail::removeRecipientRow() { auto* sndr = static_cast(sender()); diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.h b/src/librssguard/services/gmail/gui/formaddeditemail.h index 854353aea..0ce4f4b82 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.h +++ b/src/librssguard/services/gmail/gui/formaddeditemail.h @@ -23,6 +23,7 @@ class FormAddEditEmail : public QDialog { public slots: void execForAdd(); + void execForReply(Message* original_message); private slots: void removeRecipientRow(); diff --git a/src/librssguard/services/inoreader/inoreaderserviceroot.cpp b/src/librssguard/services/inoreader/inoreaderserviceroot.cpp index 95f2baba1..7931487ea 100644 --- a/src/librssguard/services/inoreader/inoreaderserviceroot.cpp +++ b/src/librssguard/services/inoreader/inoreaderserviceroot.cpp @@ -82,6 +82,10 @@ void InoreaderServiceRoot::saveAccountDataToDatabase() { } } +bool InoreaderServiceRoot::isSyncable() const { + return true; +} + bool InoreaderServiceRoot::canBeEdited() const { return true; } @@ -119,17 +123,6 @@ void InoreaderServiceRoot::stop() { saveCacheToFile(accountId()); } -QList InoreaderServiceRoot::serviceMenu() { - if (m_serviceMenu.isEmpty()) { - QAction* act_sync_in = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this); - - connect(act_sync_in, &QAction::triggered, this, &InoreaderServiceRoot::syncIn); - m_serviceMenu.append(act_sync_in); - } - - return m_serviceMenu; -} - QString InoreaderServiceRoot::code() const { return InoreaderEntryPoint().code(); } diff --git a/src/librssguard/services/inoreader/inoreaderserviceroot.h b/src/librssguard/services/inoreader/inoreaderserviceroot.h index bfea16a25..d580ff070 100644 --- a/src/librssguard/services/inoreader/inoreaderserviceroot.h +++ b/src/librssguard/services/inoreader/inoreaderserviceroot.h @@ -20,6 +20,7 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot { void setNetwork(InoreaderNetworkFactory* network); InoreaderNetworkFactory* network() const; + bool isSyncable() const; bool canBeEdited() const; bool editViaGui(); bool canBeDeleted() const; @@ -43,10 +44,8 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot { private: void loadFromDatabase(); - QList serviceMenu(); private: - QList m_serviceMenu; InoreaderNetworkFactory* m_network; }; diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.cpp b/src/librssguard/services/owncloud/owncloudserviceroot.cpp index 80f0900d4..80b1850fc 100644 --- a/src/librssguard/services/owncloud/owncloudserviceroot.cpp +++ b/src/librssguard/services/owncloud/owncloudserviceroot.cpp @@ -17,7 +17,7 @@ #include "services/owncloud/owncloudserviceentrypoint.h" OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_actionSyncIn(nullptr), m_network(new OwnCloudNetworkFactory()) { + : ServiceRoot(parent), m_network(new OwnCloudNetworkFactory()) { setIcon(OwnCloudServiceEntryPoint().icon()); } @@ -25,6 +25,10 @@ OwnCloudServiceRoot::~OwnCloudServiceRoot() { delete m_network; } +bool OwnCloudServiceRoot::isSyncable() const { + return true; +} + bool OwnCloudServiceRoot::canBeEdited() const { return true; } @@ -59,16 +63,6 @@ bool OwnCloudServiceRoot::supportsCategoryAdding() const { return false; } -QList OwnCloudServiceRoot::serviceMenu() { - if (m_serviceMenu.isEmpty()) { - m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this); - connect(m_actionSyncIn, &QAction::triggered, this, &OwnCloudServiceRoot::syncIn); - m_serviceMenu.append(m_actionSyncIn); - } - - return m_serviceMenu; -} - void OwnCloudServiceRoot::start(bool freshly_activated) { Q_UNUSED(freshly_activated) loadFromDatabase(); diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.h b/src/librssguard/services/owncloud/owncloudserviceroot.h index 3f583ac86..f1c4c1733 100644 --- a/src/librssguard/services/owncloud/owncloudserviceroot.h +++ b/src/librssguard/services/owncloud/owncloudserviceroot.h @@ -18,13 +18,13 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot { explicit OwnCloudServiceRoot(RootItem* parent = nullptr); virtual ~OwnCloudServiceRoot(); + bool isSyncable() const; bool canBeEdited() const; bool canBeDeleted() const; bool editViaGui(); bool deleteViaGui(); bool supportsFeedAdding() const; bool supportsCategoryAdding() const; - QList serviceMenu(); void start(bool freshly_activated); void stop(); @@ -42,12 +42,8 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot { private: RootItem* obtainNewTreeForSyncIn() const; - void loadFromDatabase(); - QAction* m_actionSyncIn; - - QList m_serviceMenu; OwnCloudNetworkFactory* m_network; }; diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index 7fcafa9b3..c07ff2c19 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -77,6 +77,7 @@ StandardServiceRoot* StandardFeed::serviceRoot() const { bool StandardFeed::editViaGui() { QScopedPointer form_pointer(new FormStandardFeedDetails(serviceRoot(), qApp->mainFormWidget())); + form_pointer.data()->addEditFeed(this, nullptr); return false; } @@ -111,7 +112,7 @@ QString StandardFeed::typeToString(StandardFeed::Type type) { void StandardFeed::fetchMetadataForItself() { QPair metadata = guessFeed(url(), username(), password()); - if (metadata.first != nullptr && metadata.second == QNetworkReply::NoError) { + if (metadata.first != nullptr && metadata.second == QNetworkReply::NetworkError::NoError) { // Some properties are not updated when new metadata are fetched. metadata.first->setParent(parent()); metadata.first->setUrl(url()); @@ -138,10 +139,11 @@ QPair StandardFeed::guessFeed(const const QString& username, const QString& password) { QPair result; + result.first = nullptr; QByteArray feed_contents; - QList> headers; + headers << NetworkFactory::generateBasicAuthHeader(username, password); NetworkResult network_result = NetworkFactory::performNetworkOperation(url, @@ -208,8 +210,8 @@ QPair StandardFeed::guessFeed(const QDomElement root_element = xml_document.documentElement(); QString root_tag_name = root_element.tagName(); - QList icon_possible_locations; + icon_possible_locations.append(url); if (root_tag_name == QL1S("rdf:RDF")) { @@ -308,8 +310,8 @@ bool StandardFeed::addItself(RootItem* parent) { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); bool ok; int new_id = DatabaseQueries::addStandardFeed(database, parent->id(), parent->getParentServiceRoot()->accountId(), title(), - description(), creationDate(), icon(), encoding(), url(), passwordProtected(), - username(), password(), autoUpdateType(), autoUpdateInitialInterval(), type(), &ok); + description(), creationDate(), icon(), encoding(), url(), passwordProtected(), + username(), password(), autoUpdateType(), autoUpdateInitialInterval(), type(), &ok); if (!ok) { // Query failed. @@ -329,12 +331,13 @@ bool StandardFeed::editItself(StandardFeed* new_feed_data) { RootItem* new_parent = new_feed_data->parent(); if (!DatabaseQueries::editStandardFeed(database, new_parent->id(), original_feed->id(), new_feed_data->title(), - new_feed_data->description(), new_feed_data->icon(), - new_feed_data->encoding(), new_feed_data->url(), new_feed_data->passwordProtected(), - new_feed_data->username(), new_feed_data->password(), - new_feed_data->autoUpdateType(), new_feed_data->autoUpdateInitialInterval(), - new_feed_data->type())) { + new_feed_data->description(), new_feed_data->icon(), + new_feed_data->encoding(), new_feed_data->url(), new_feed_data->passwordProtected(), + new_feed_data->username(), new_feed_data->password(), + new_feed_data->autoUpdateType(), new_feed_data->autoUpdateInitialInterval(), + new_feed_data->type())) { // Persistent storage update failed, no way to continue now. + qWarning("Self-editing of standard feed failed."); return false; } @@ -399,8 +402,8 @@ void StandardFeed::setEncoding(const QString& encoding) { QList StandardFeed::obtainNewMessages(bool* error_during_obtaining) { QByteArray feed_contents; int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QList> headers; + headers << NetworkFactory::generateBasicAuthHeader(username(), password()); m_networkError = NetworkFactory::performNetworkOperation(url(), diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp index 6fcb45a4c..0b19ae0bd 100644 --- a/src/librssguard/services/standard/standardserviceroot.cpp +++ b/src/librssguard/services/standard/standardserviceroot.cpp @@ -27,15 +27,13 @@ #include StandardServiceRoot::StandardServiceRoot(RootItem* parent) - : ServiceRoot(parent), - m_actionExportFeeds(nullptr), m_actionImportFeeds(nullptr), m_actionFeedFetchMetadata(nullptr) { + : ServiceRoot(parent) { setTitle(qApp->system()->loggedInUser() + QSL(" (RSS/RDF/ATOM)")); setIcon(StandardServiceEntryPoint().icon()); setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds.")); } StandardServiceRoot::~StandardServiceRoot() { - qDeleteAll(m_serviceMenu); qDeleteAll(m_feedContextMenu); } @@ -176,13 +174,19 @@ void StandardServiceRoot::checkArgumentForFeedAdding(const QString& argument) { QList StandardServiceRoot::getContextMenuForFeed(StandardFeed* feed) { if (m_feedContextMenu.isEmpty()) { // Initialize. - m_actionFeedFetchMetadata = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("Fetch metadata"), nullptr); - m_feedContextMenu.append(m_actionFeedFetchMetadata); + auto* action_metadata = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), + tr("Fetch metadata"), + this); + + m_feedContextMenu.append(action_metadata); + + connect(action_metadata, &QAction::triggered, this, [this]() { + m_feedForMetadata->fetchMetadataForItself(); + }); } - // Make connections. - disconnect(m_actionFeedFetchMetadata, &QAction::triggered, nullptr, nullptr); - connect(m_actionFeedFetchMetadata, &QAction::triggered, feed, &StandardFeed::fetchMetadataForItself); + m_feedForMetadata = feed; + return m_feedContextMenu; } @@ -306,12 +310,16 @@ void StandardServiceRoot::exportFeeds() { QList StandardServiceRoot::serviceMenu() { if (m_serviceMenu.isEmpty()) { - m_actionExportFeeds = new QAction(qApp->icons()->fromTheme("document-export"), tr("Export feeds"), this); - m_actionImportFeeds = new QAction(qApp->icons()->fromTheme("document-import"), tr("Import feeds"), this); - connect(m_actionExportFeeds, &QAction::triggered, this, &StandardServiceRoot::exportFeeds); - connect(m_actionImportFeeds, &QAction::triggered, this, &StandardServiceRoot::importFeeds); - m_serviceMenu.append(m_actionExportFeeds); - m_serviceMenu.append(m_actionImportFeeds); + ServiceRoot::serviceMenu(); + + auto* action_export_feeds = new QAction(qApp->icons()->fromTheme("document-export"), tr("Export feeds"), this); + auto* action_import_feeds = new QAction(qApp->icons()->fromTheme("document-import"), tr("Import feeds"), this); + + connect(action_export_feeds, &QAction::triggered, this, &StandardServiceRoot::exportFeeds); + connect(action_import_feeds, &QAction::triggered, this, &StandardServiceRoot::importFeeds); + + m_serviceMenu.append(action_export_feeds); + m_serviceMenu.append(action_import_feeds); } return m_serviceMenu; diff --git a/src/librssguard/services/standard/standardserviceroot.h b/src/librssguard/services/standard/standardserviceroot.h index bc97f5b34..38b66a399 100644 --- a/src/librssguard/services/standard/standardserviceroot.h +++ b/src/librssguard/services/standard/standardserviceroot.h @@ -5,11 +5,12 @@ #include "services/abstract/serviceroot.h" +#include "services/standard/standardfeed.h" + #include #include class StandardCategory; -class StandardFeed; class FeedsImportExportModel; class QMenu; @@ -58,12 +59,8 @@ class StandardServiceRoot : public ServiceRoot { QString processFeedUrl(const QString& feed_url); void checkArgumentsForFeedAdding(); - QAction* m_actionExportFeeds; - QAction* m_actionImportFeeds; - - QList m_serviceMenu; - QList m_feedContextMenu; - QAction* m_actionFeedFetchMetadata; + QPointer m_feedForMetadata = {}; + QList m_feedContextMenu = {}; }; #endif // STANDARDSERVICEROOT_H diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp index cd3ece626..12d57a16d 100644 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp +++ b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp @@ -23,7 +23,7 @@ #include TtRssServiceRoot::TtRssServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_actionSyncIn(nullptr), m_network(new TtRssNetworkFactory()) { + : ServiceRoot(parent), m_network(new TtRssNetworkFactory()) { setIcon(TtRssServiceEntryPoint().icon()); } @@ -52,6 +52,10 @@ QString TtRssServiceRoot::code() const { return TtRssServiceEntryPoint().code(); } +bool TtRssServiceRoot::isSyncable() const { + return true; +} + bool TtRssServiceRoot::editViaGui() { QScopedPointer form_pointer(new FormEditTtRssAccount(qApp->mainFormWidget())); @@ -148,16 +152,6 @@ void TtRssServiceRoot::saveAllCachedData(bool async) { } } -QList TtRssServiceRoot::serviceMenu() { - if (m_serviceMenu.isEmpty()) { - m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this); - connect(m_actionSyncIn, &QAction::triggered, this, &TtRssServiceRoot::syncIn); - m_serviceMenu.append(m_actionSyncIn); - } - - return m_serviceMenu; -} - QString TtRssServiceRoot::additionalTooltip() const { return tr("Username: %1\nServer: %2\n" "Last error: %3\nLast login on: %4").arg(m_network->username(), diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.h b/src/librssguard/services/tt-rss/ttrssserviceroot.h index 4d401530d..fb862d7f2 100644 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.h +++ b/src/librssguard/services/tt-rss/ttrssserviceroot.h @@ -22,13 +22,14 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot { void start(bool freshly_activated); void stop(); QString code() const; + + bool isSyncable() const; bool canBeEdited() const; bool canBeDeleted() const; bool editViaGui(); bool deleteViaGui(); bool supportsFeedAdding() const; bool supportsCategoryAdding() const; - QList serviceMenu(); QString additionalTooltip() const; @@ -46,12 +47,8 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot { private: RootItem* obtainNewTreeForSyncIn() const; - void loadFromDatabase(); - QAction* m_actionSyncIn; - - QList m_serviceMenu; TtRssNetworkFactory* m_network; }; From a3d142034fed5ddf6004c5fb2297eb82471314c7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 29 Jul 2020 07:51:48 +0200 Subject: [PATCH 3/6] debug next status --- resources/icons.qrc | 1 + resources/rssguard.qrc | 1 + resources/text/COPYING_MIT | 19 + src/librssguard/3rd-party/boolinq/boolinq.h | 882 ++++++++++++++++++ src/librssguard/core/messagesmodel.cpp | 10 + src/librssguard/core/messagesmodel.h | 2 + src/librssguard/gui/dialogs/formabout.cpp | 7 + src/librssguard/gui/dialogs/formabout.ui | 68 +- src/librssguard/gui/dialogs/formmain.cpp | 2 +- src/librssguard/gui/feedsview.cpp | 12 +- src/librssguard/gui/messagesview.cpp | 31 +- src/librssguard/gui/messagesview.h | 18 +- .../services/abstract/recyclebin.cpp | 2 +- .../services/abstract/recyclebin.h | 2 +- .../services/abstract/rootitem.cpp | 2 +- src/librssguard/services/abstract/rootitem.h | 2 +- .../services/abstract/serviceroot.cpp | 4 +- .../services/abstract/serviceroot.h | 8 +- .../services/gmail/gmailserviceroot.cpp | 23 +- .../services/gmail/gmailserviceroot.h | 6 + .../services/gmail/gui/formaddeditemail.cpp | 13 +- .../gmail/network/gmailnetworkfactory.cpp | 50 +- .../gmail/network/gmailnetworkfactory.h | 3 +- .../owncloud/gui/formeditowncloudaccount.cpp | 2 +- .../network/owncloudnetworkfactory.cpp | 2 + .../services/standard/standardfeed.cpp | 2 +- .../services/standard/standardfeed.h | 2 +- 27 files changed, 1130 insertions(+), 46 deletions(-) create mode 100755 resources/text/COPYING_MIT create mode 100755 src/librssguard/3rd-party/boolinq/boolinq.h diff --git a/resources/icons.qrc b/resources/icons.qrc index 2c39d2853..3320fda80 100644 --- a/resources/icons.qrc +++ b/resources/icons.qrc @@ -37,6 +37,7 @@ ./graphics/Faenza/actions/64/mail-mark-read.png ./graphics/Faenza/actions/64/mail-mark-unread.png ./graphics/Faenza/actions/64/mail-message-new.png + ./graphics/Faenza/actions/64/mail-reply-sender.png ./graphics/Faenza/actions/64/mail-send.png ./graphics/Faenza/actions/64/mail-sent.png ./graphics/Faenza/actions/64/media-playback-start.png diff --git a/resources/rssguard.qrc b/resources/rssguard.qrc index feb8bc999..6367a2995 100755 --- a/resources/rssguard.qrc +++ b/resources/rssguard.qrc @@ -2,6 +2,7 @@ text/CHANGELOG text/COPYING_BSD + text/COPYING_MIT text/COPYING_GNU_GPL text/COPYING_GNU_GPL_HTML diff --git a/resources/text/COPYING_MIT b/resources/text/COPYING_MIT new file mode 100755 index 000000000..58363dadb --- /dev/null +++ b/resources/text/COPYING_MIT @@ -0,0 +1,19 @@ +Copyright (C) 2019 by Anton Bukov (k06aaa@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/librssguard/3rd-party/boolinq/boolinq.h b/src/librssguard/3rd-party/boolinq/boolinq.h new file mode 100755 index 000000000..0d52c1167 --- /dev/null +++ b/src/librssguard/3rd-party/boolinq/boolinq.h @@ -0,0 +1,882 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// + +namespace boolinq { + + struct LinqEndException {}; + + enum BytesDirection { + BytesFirstToLast, + BytesLastToFirst, + }; + + enum BitsDirection { + BitsHighToLow, + BitsLowToHigh, + }; + + template + class Linq { + std::function nextFunc; + S storage; + + public: + typedef T value_type; + + Linq() : nextFunc(), storage() + { + } + + Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage) + { + } + + T next() + { + return nextFunc(storage); + } + + void for_each_i(std::function apply) const + { + Linq linq = *this; + try { + for (int i = 0; ; i++) { + apply(linq.next(), i); + } + } + catch (LinqEndException &) {} + } + + void for_each(std::function apply) const + { + return for_each_i([apply](T value, int index) { return apply(value); }); + } + + Linq, int>, T> where_i(std::function filter) const + { + return Linq, int>, T>( + std::make_tuple(*this, 0), + [filter](std::tuple, int> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + + while (true) { + T ret = linq.next(); + if (filter(ret, index++)) { + return ret; + } + } + } + ); + } + + Linq, int>, T> where(std::function filter) const + { + return where_i([filter](T value, int index) { return filter(value); }); + } + + Linq, int>, T> take(int count) const + { + return where_i([count](T /*value*/, int i) { + if (i == count) { + throw LinqEndException(); + } + return true; + }); + } + + Linq, int>, T> takeWhile_i(std::function predicate) const + { + return where_i([predicate](T value, int i) { + if (!predicate(value, i)) { + throw LinqEndException(); + } + return true; + }); + } + + Linq, int>, T> takeWhile(std::function predicate) const + { + return takeWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); + } + + Linq, int>, T> skip(int count) const + { + return where_i([count](T value, int i) { return i >= count; }); + } + + Linq, int, bool>, T> skipWhile_i(std::function predicate) const + { + return Linq, int, bool>, T>( + std::make_tuple(*this, 0, false), + [predicate](std::tuple, int, bool> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (flag) { + return linq.next(); + } + while (true) { + T ret = linq.next(); + if (!predicate(ret, index++)) { + flag = true; + return ret; + } + } + } + ); + } + + Linq, int, bool>, T> skipWhile(std::function predicate) const + { + return skipWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); + } + + template + Linq, std::vector, int>, T> append(Types ... newValues) const + { + return Linq, std::vector, int>, T>( + std::make_tuple(*this, std::vector{ newValues... }, -1), + [](std::tuple, std::vector, int> &tuple) { + Linq &linq = std::get<0>(tuple); + std::vector &values = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + if (index == -1) { + try { + return linq.next(); + } + catch (LinqEndException &) { + index = 0; + } + } + + if (index < values.size()) { + return values[index++]; + } + + throw LinqEndException(); + } + ); + } + + template + Linq, std::vector, int>, T> prepend(Types ... newValues) const + { + return Linq, std::vector, int>, T>( + std::make_tuple(*this, std::vector{ newValues... }, 0), + [](std::tuple, std::vector, int> &tuple) { + Linq &linq = std::get<0>(tuple); + std::vector &values = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + if (index < values.size()) { + return values[index++]; + } + return linq.next(); + } + ); + } + + template::type> + Linq, int>, _TRet> select_i(F apply) const + { + return Linq, int>, _TRet>( + std::make_tuple(*this, 0), + [apply](std::tuple, int> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + + return apply(linq.next(), index++); + } + ); + } + + template::type> + Linq, int>, _TRet> select(F apply) const + { + return select_i([apply](T value, int /*index*/) { return apply(value); }); + } + + template + Linq, int>, TRet> cast() const + { + return select_i([](T value, int /*i*/) { return TRet(value); }); + } + + template + Linq, Linq, bool>, T> concat(const Linq & rhs) const + { + return Linq, Linq, bool>, T>( + std::make_tuple(*this, rhs, false), + [](std::tuple, Linq, bool> &tuple){ + Linq &first = std::get<0>(tuple); + Linq &second = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + try { + return first.next(); + } + catch (LinqEndException &) {} + } + return second.next(); + } + ); + } + + template< + typename F, + typename _TRet = typename std::result_of::type, + typename _TRetVal = typename _TRet::value_type + > + Linq, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const + { + return Linq, _TRet, int, bool>, _TRetVal>( + std::make_tuple(*this, _TRet(), 0, true), + [apply](std::tuple, _TRet, int, bool> &tuple) { + Linq &linq = std::get<0>(tuple); + _TRet ¤t = std::get<1>(tuple); + int &index = std::get<2>(tuple); + bool &finished = std::get<3>(tuple); + + while (true) { + if (finished) { + current = apply(linq.next(), index++); + finished = false; + } + try { + return current.next(); + } + catch (LinqEndException &) { + finished = true; + } + } + } + ); + } + + template< + typename F, + typename _TRet = typename std::result_of::type, + typename _TRetVal = typename _TRet::value_type + > + Linq, _TRet, int, bool>, _TRetVal> selectMany(F apply) const + { + return selectMany_i([apply](T value, int index) { return apply(value); }); + } + + template< + typename F, + typename _TKey = typename std::result_of::type, + typename _TValue = Linq, int>, T> // where(predicate) + > + Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> > groupBy(F apply) const + { + return Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> >( + std::make_tuple(*this, *this, std::unordered_set<_TKey>()), + [apply](std::tuple, Linq, std::unordered_set<_TKey> > &tuple){ + Linq &linq = std::get<0>(tuple); + Linq &linqCopy = std::get<1>(tuple); + std::unordered_set<_TKey> &set = std::get<2>(tuple); + + _TKey key = apply(linq.next()); + if (set.insert(key).second) { + return std::make_pair(key, linqCopy.where([apply, key](T v){ + return apply(v) == key; + })); + } + throw LinqEndException(); + } + ); + } + + template::type> + Linq, std::unordered_set<_TRet> >, T> distinct(F transform) const + { + return Linq, std::unordered_set<_TRet> >, T>( + std::make_tuple(*this, std::unordered_set<_TRet>()), + [transform](std::tuple, std::unordered_set<_TRet> > &tuple) { + Linq &linq = std::get<0>(tuple); + std::unordered_set<_TRet> &set = std::get<1>(tuple); + + while (true) { + T value = linq.next(); + if (set.insert(transform(value)).second) { + return value; + } + } + } + ); + } + + Linq, std::unordered_set >, T> distinct() const + { + return distinct([](T value) { return value; }); + } + + template::const_iterator> + Linq, _TIter, bool>, T> orderBy(F transform) const + { + std::vector items = toStdVector(); + std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) { + return transform(a) < transform(b); + }); + + return Linq, _TIter, bool>, T>( + std::make_tuple(items, _TIter(), false), + [](std::tuple, _TIter, bool> &tuple) { + std::vector &vec = std::get<0>(tuple); + _TIter &it = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + flag = true; + it = vec.cbegin(); + } + if (it == vec.cend()) { + throw LinqEndException(); + } + return *(it++); + } + ); + } + + Linq, typename std::vector::const_iterator, bool>, T> orderBy() const + { + return orderBy([](T value) { return value; }); + } + + template::const_reverse_iterator> + Linq, _TIter, bool>, T> reverse() const + { + return Linq, _TIter, bool>, T>( + std::make_tuple(toStdList(), _TIter(), false), + [](std::tuple, _TIter, bool> &tuple) { + std::list &list = std::get<0>(tuple); + _TIter &it = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + flag = true; + it = list.crbegin(); + } + if (it == list.crend()) { + throw LinqEndException(); + } + return *(it++); + } + ); + } + + // Aggregators + + template + TRet aggregate(TRet start, std::function accumulate) const + { + Linq linq = *this; + try { + while (true) { + start = accumulate(start, linq.next()); + } + } + catch (LinqEndException &) {} + return start; + } + + template::type> + _TRet sum(F transform) const + { + return aggregate<_TRet>(_TRet(), [transform](_TRet accumulator, T value) { + return accumulator + transform(value); + }); + } + + template + TRet sum() const + { + return sum([](T value) { return TRet(value); }); + } + + template::type> + _TRet avg(F transform) const + { + int count = 0; + _TRet res = sum([transform, &count](T value) { + count++; + return transform(value); + }); + return res / count; + } + + template + TRet avg() const + { + return avg([](T value) { return TRet(value); }); + } + + int count() const + { + int index = 0; + for_each([&index](T /*a*/) { index++; }); + return index; + } + + int count(std::function predicate) const + { + return where(predicate).count(); + } + + int count(const T &item) const + { + return count([item](T value) { return item == value; }); + } + + // Bool aggregators + + bool any(std::function predicate) const + { + Linq linq = *this; + try { + while (true) { + if (predicate(linq.next())) + return true; + } + } + catch (LinqEndException &) {} + return false; + } + + bool any() const + { + return any([](T value) { return static_cast(value); }); + } + + bool all(std::function predicate) const + { + return !any([predicate](T value) { return !predicate(value); }); + } + + bool all() const + { + return all([](T value) { return static_cast(value); }); + } + + bool contains(const T &item) const + { + return any([&item](T value) { return value == item; }); + } + + // Election aggregators + + T elect(std::function accumulate) const + { + T result; + for_each_i([accumulate, &result](T value, int i) { + if (i == 0) { + result = value; + } else { + result = accumulate(result, value); + } + }); + return result; + } + + template + T max(F transform) const + { + return elect([transform](const T &a, const T &b) { + return (transform(a) < transform(b)) ? b : a; + }); + } + + T max() const + { + return max([](T value) { return value; }); + } + + template + T min(F transform) const + { + return elect([transform](const T &a, const T &b) { + return (transform(a) < transform(b)) ? a : b; + }); + } + + T min() const + { + return min([](T value) { return value; }); + } + + // Single object returners + + T elementAt(int index) const + { + return skip(index).next(); + } + + T first(std::function predicate) const + { + return where(predicate).next(); + } + + T first() const + { + return Linq(*this).next(); + } + + T firstOrDefault(std::function predicate, T const& defaultValue = T()) const + { + try { + return where(predicate).next(); + } + catch (LinqEndException &) {} + return defaultValue; + } + + T firstOrDefault(T const& defaultValue = T()) const + { + try { + return Linq(*this).next(); + } + catch (LinqEndException &) {} + return defaultValue; + } + + T last(std::function predicate) const + { + T res; + int index = -1; + where(predicate).for_each_i([&res, &index](T value, int i) { + res = value; + index = i; + }); + + if (index == -1) { + throw LinqEndException(); + } + return res; + } + + T last() const + { + return last([](T /*value*/) { return true; }); + } + + T lastOrDefault(std::function predicate, T const& defaultValue = T()) const + { + T res = defaultValue; + where(predicate).for_each([&res](T value) { + res = value; + }); + return res; + } + + T lastOrDefault(T const& defaultValue = T()) const + { + return lastOrDefault([](T /*value*/) { return true; }, defaultValue); + } + + // Export to containers + + std::vector toStdVector() const + { + std::vector items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::list toStdList() const + { + std::list items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::deque toStdDeque() const + { + std::deque items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::set toStdSet() const + { + std::set items; + for_each([&items](T value) { + items.insert(value); + }); + return items; + } + + std::unordered_set toStdUnorderedSet() const + { + std::unordered_set items; + for_each([&items](T value) { + items.insert(value); + }); + return items; + } + + // Bits and bytes + + Linq, BytesDirection, T, int>, int> bytes(BytesDirection direction = BytesFirstToLast) const + { + return Linq, BytesDirection, T, int>, int>( + std::make_tuple(*this, direction, T(), sizeof(T)), + [](std::tuple, BytesDirection, T, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + T &value = std::get<2>(tuple); + int &index = std::get<3>(tuple); + + if (index == sizeof(T)) { + value = linq.next(); + index = 0; + } + + unsigned char *ptr = reinterpret_cast(&value); + + int byteIndex = index; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(T) - 1 - byteIndex; + } + + index++; + return ptr[byteIndex]; + } + ); + } + + template + Linq, BytesDirection, int>, TRet> unbytes(BytesDirection direction = BytesFirstToLast) const + { + return Linq, BytesDirection, int>, TRet>( + std::make_tuple(*this, direction, 0), + [](std::tuple, BytesDirection, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + TRet value; + unsigned char *ptr = reinterpret_cast(&value); + + for (int i = 0; i < sizeof(TRet); i++) { + int byteIndex = i; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(TRet) - 1 - byteIndex; + } + + ptr[byteIndex] = linq.next(); + } + + return value; + } + ); + } + + Linq, BytesDirection, BitsDirection, T, int>, int> bits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const + { + return Linq, BytesDirection, BitsDirection, T, int>, int>( + std::make_tuple(*this, bytesDir, bitsDir, T(), sizeof(T) * CHAR_BIT), + [](std::tuple, BytesDirection, BitsDirection, T, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + BitsDirection &bitsDirection = std::get<2>(tuple); + T &value = std::get<3>(tuple); + int &index = std::get<4>(tuple); + + if (index == sizeof(T) * CHAR_BIT) { + value = linq.next(); + index = 0; + } + + unsigned char *ptr = reinterpret_cast(&value); + + int byteIndex = index / CHAR_BIT; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(T) - 1 - byteIndex; + } + + int bitIndex = index % CHAR_BIT; + if (bitsDirection == BitsHighToLow) { + bitIndex = CHAR_BIT - 1 - bitIndex; + } + + index++; + return (ptr[byteIndex] >> bitIndex) & 1; + } + ); + } + + template + Linq, BytesDirection, BitsDirection, int>, TRet> unbits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const + { + return Linq, BytesDirection, BitsDirection, int>, TRet>( + std::make_tuple(*this, bytesDir, bitsDir, 0), + [](std::tuple, BytesDirection, BitsDirection, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + BitsDirection &bitsDirection = std::get<2>(tuple); + int &index = std::get<3>(tuple); + + TRet value = TRet(); + unsigned char *ptr = reinterpret_cast(&value); + + for (int i = 0; i < sizeof(TRet) * CHAR_BIT; i++) { + int byteIndex = i / CHAR_BIT; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(TRet) - 1 - byteIndex; + } + + int bitIndex = i % CHAR_BIT; + if (bitsDirection == BitsHighToLow) { + bitIndex = CHAR_BIT - 1 - bitIndex; + } + + ptr[byteIndex] &= ~(1 << bitIndex); + ptr[byteIndex] |= bool(linq.next()) << bitIndex; + } + + return value; + } + ); + } + }; + + template + std::ostream &operator<<(std::ostream &stream, Linq linq) + { + try { + while (true) { + stream << linq.next() << ' '; + } + } + catch (LinqEndException &) {} + return stream; + } + + //////////////////////////////////////////////////////////////// + // Linq Creators + //////////////////////////////////////////////////////////////// + + template + Linq, typename std::iterator_traits::value_type> from(const T & begin, const T & end) + { + return Linq, typename std::iterator_traits::value_type>( + std::make_pair(begin, end), + [](std::pair &pair) { + if (pair.first == pair.second) { + throw LinqEndException(); + } + return *(pair.first++); + } + ); + } + + template + Linq, typename std::iterator_traits::value_type> from(const T & it, int n) + { + return from(it, it + n); + } + + template + Linq, T> from(T (&array)[N]) + { + return from((const T *)(&array), (const T *)(&array) + N); + } + + template class TV, typename TT> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::list, std::vector, std::dequeue + template class TV, typename TT, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::set + template class TV, typename TT, typename TS, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::map + template class TV, typename TK, typename TT, typename TS, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::array + template class TV, typename TT, size_t TL> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + template + Linq, T> repeat(const T & value, int count) { + return Linq, T>( + std::make_pair(value, count), + [](std::pair &pair) { + if (pair.second > 0) { + pair.second--; + return pair.first; + } + throw LinqEndException(); + } + ); + } + + template + Linq, T> range(const T & start, const T & end, const T & step) { + return Linq, T>( + std::make_tuple(start, end, step), + [](std::tuple &tuple) { + T &start = std::get<0>(tuple); + T &end = std::get<1>(tuple); + T &step = std::get<2>(tuple); + + T value = start; + if (value < end) { + start += step; + return value; + } + throw LinqEndException(); + } + ); + } +} \ No newline at end of file diff --git a/src/librssguard/core/messagesmodel.cpp b/src/librssguard/core/messagesmodel.cpp index 7c75b9948..1607146c6 100644 --- a/src/librssguard/core/messagesmodel.cpp +++ b/src/librssguard/core/messagesmodel.cpp @@ -214,6 +214,16 @@ Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; } +QList MessagesModel::messagesAt(QList row_indices) const { + QList msgs; + + for (int idx : row_indices) { + msgs << messageAt(idx); + } + + return msgs; +} + QVariant MessagesModel::data(int row, int column, int role) const { return data(index(row, column), role); } diff --git a/src/librssguard/core/messagesmodel.h b/src/librssguard/core/messagesmodel.h index 176d19667..b7ef9149d 100644 --- a/src/librssguard/core/messagesmodel.h +++ b/src/librssguard/core/messagesmodel.h @@ -44,6 +44,8 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer { Qt::ItemFlags flags(const QModelIndex& index) const; // Returns message at given index. + + QList messagesAt(QList row_indices) const; Message messageAt(int row_index) const; int messageId(int row_index) const; RootItem::Importance messageImportance(int row_index) const; diff --git a/src/librssguard/gui/dialogs/formabout.cpp b/src/librssguard/gui/dialogs/formabout.cpp index cb7fb9695..632f27573 100644 --- a/src/librssguard/gui/dialogs/formabout.cpp +++ b/src/librssguard/gui/dialogs/formabout.cpp @@ -68,6 +68,13 @@ void FormAbout::loadLicenseAndInformation() { m_ui.m_txtLicenseBsd->setText(tr("License not found.")); } + try { + m_ui.m_txtLicenseMit->setText(IOFactory::readFile(APP_INFO_PATH + QL1S("/COPYING_MIT"))); + } + catch (...) { + m_ui.m_txtLicenseMit->setText(tr("License not found.")); + } + // Set other informative texts. m_ui.m_lblDesc->setText(tr("%8
" "Version: %1 (built on %2/%3)
" "Revision: %4
" "Build date: %5
" "Qt: %6 (compiled against %7)
").arg( diff --git a/src/librssguard/gui/dialogs/formabout.ui b/src/librssguard/gui/dialogs/formabout.ui index 84959f6dd..dba81fca3 100644 --- a/src/librssguard/gui/dialogs/formabout.ui +++ b/src/librssguard/gui/dialogs/formabout.ui @@ -160,7 +160,7 @@ p, li { white-space: pre-wrap; } 0 0 685 - 184 + 157 @@ -235,8 +235,8 @@ p, li { white-space: pre-wrap; } 0 0 - 98 - 69 + 685 + 157 @@ -288,6 +288,68 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + true + + + + + + + + MIT License (applies to boolinq source code) + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + DejaVu Sans Mono + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + QTextEdit::AutoNone + + + false + + + QTextEdit::WidgetWidth + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index ebd6ae5bc..1f30788b5 100755 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -312,7 +312,7 @@ void FormMain::updateRecycleBinMenu() { no_action->setEnabled(false); root_menu->addAction(no_action); } - else if ((context_menu = bin->contextMenu()).isEmpty()) { + else if ((context_menu = bin->contextMenuFeedsList()).isEmpty()) { QAction* no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), tr("No actions possible"), m_ui->m_menuRecycleBin); diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp index 9fcbc0f82..343ee9511 100755 --- a/src/librssguard/gui/feedsview.cpp +++ b/src/librssguard/gui/feedsview.cpp @@ -430,7 +430,7 @@ QMenu* FeedsView::initializeContextMenuBin(RootItem* clicked_item) { m_contextMenuBin->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuBin->addActions(QList() << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << @@ -453,7 +453,7 @@ QMenu* FeedsView::initializeContextMenuService(RootItem* clicked_item) { m_contextMenuService->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuService->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -511,7 +511,7 @@ QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) { m_contextMenuCategories->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -538,7 +538,7 @@ QMenu* FeedsView::initializeContextMenuFeeds(RootItem* clicked_item) { m_contextMenuFeeds->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -565,7 +565,7 @@ QMenu* FeedsView::initializeContextMenuImportant(RootItem* clicked_item) { m_contextMenuImportant->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuImportant->addActions(QList() << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << @@ -598,7 +598,7 @@ QMenu* FeedsView::initializeContextMenuOtherItem(RootItem* clicked_item) { m_contextMenuOtherItems->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); if (!specific_actions.isEmpty()) { m_contextMenuOtherItems->addSeparator(); diff --git a/src/librssguard/gui/messagesview.cpp b/src/librssguard/gui/messagesview.cpp index 99febc4e0..ff789aaec 100644 --- a/src/librssguard/gui/messagesview.cpp +++ b/src/librssguard/gui/messagesview.cpp @@ -2,6 +2,7 @@ #include "gui/messagesview.h" +#include "3rd-party/boolinq/boolinq.h" #include "core/messagesmodel.h" #include "core/messagesproxymodel.h" #include "gui/dialogs/formmain.h" @@ -13,6 +14,7 @@ #include "miscellaneous/settings.h" #include "network-web/networkfactory.h" #include "network-web/webfactory.h" +#include "services/abstract/serviceroot.h" #include #include @@ -213,11 +215,32 @@ void MessagesView::initializeContextMenu() { m_contextMenu->addMenu(menu); m_contextMenu->addActions( - QList() << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << - qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); + QList() + << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail + << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally + << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally + << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead + << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread + << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages + << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); - if (m_sourceModel->loadedItem() != nullptr && m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { - m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); + if (m_sourceModel->loadedItem() != nullptr) { + if (m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { + m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); + } + + QModelIndexList selected_indexes = selectionModel()->selectedRows(); + const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); + auto rows = boolinq::from(mapped_indexes).select([](const QModelIndex& idx) { + return idx.row(); + }).toStdList(); + auto messages = m_sourceModel->messagesAt(QList::fromStdList(rows)); + auto extra_context_menu = m_sourceModel->loadedItem()->getParentServiceRoot()->contextMenuMessagesList(messages); + + if (!extra_context_menu.isEmpty()) { + m_contextMenu->addSeparator(); + m_contextMenu->addActions(extra_context_menu); + } } } diff --git a/src/librssguard/gui/messagesview.h b/src/librssguard/gui/messagesview.h index 5f948ee22..487019da1 100644 --- a/src/librssguard/gui/messagesview.h +++ b/src/librssguard/gui/messagesview.h @@ -19,14 +19,8 @@ class MessagesView : public QTreeView { explicit MessagesView(QWidget* parent = nullptr); virtual ~MessagesView(); - // Model accessors. - inline MessagesProxyModel* model() const { - return m_proxyModel; - } - - inline MessagesModel* sourceModel() const { - return m_sourceModel; - } + MessagesProxyModel* model() const; + MessagesModel* sourceModel() const; void reloadFontSettings(); @@ -110,4 +104,12 @@ class MessagesView : public QTreeView { bool m_columnsAdjusted; }; +inline MessagesProxyModel* MessagesView::model() const { + return m_proxyModel; +} + +inline MessagesModel* MessagesView::sourceModel() const { + return m_sourceModel; +} + #endif // MESSAGESVIEW_H diff --git a/src/librssguard/services/abstract/recyclebin.cpp b/src/librssguard/services/abstract/recyclebin.cpp index 525ef2529..5268d2f7e 100644 --- a/src/librssguard/services/abstract/recyclebin.cpp +++ b/src/librssguard/services/abstract/recyclebin.cpp @@ -46,7 +46,7 @@ void RecycleBin::updateCounts(bool update_total_count) { } } -QList RecycleBin::contextMenu() { +QList RecycleBin::contextMenuFeedsList() { if (m_contextMenu.isEmpty()) { QAction* restore_action = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Restore recycle bin"), diff --git a/src/librssguard/services/abstract/recyclebin.h b/src/librssguard/services/abstract/recyclebin.h index 78c1014fb..b1b42b8f8 100644 --- a/src/librssguard/services/abstract/recyclebin.h +++ b/src/librssguard/services/abstract/recyclebin.h @@ -14,7 +14,7 @@ class RecycleBin : public RootItem { QString additionalTooltip() const; - QList contextMenu(); + QList contextMenuFeedsList(); QList undeletedMessages() const; bool markAsReadUnread(ReadStatus status); diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp index c2c29450f..b6ad95294 100644 --- a/src/librssguard/services/abstract/rootitem.cpp +++ b/src/librssguard/services/abstract/rootitem.cpp @@ -44,7 +44,7 @@ QString RootItem::additionalTooltip() const { return QString(); } -QList RootItem::contextMenu() { +QList RootItem::contextMenuFeedsList() { return QList(); } diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h index b8e7bc64a..1020c097c 100644 --- a/src/librssguard/services/abstract/rootitem.h +++ b/src/librssguard/services/abstract/rootitem.h @@ -63,7 +63,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { // Returns list of specific actions which can be done with the item. // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. - virtual QList contextMenu(); + virtual QList contextMenuFeedsList(); // Can properties of this item be edited? virtual bool canBeEdited() const; diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index b2938252c..61c52919e 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -68,11 +68,11 @@ bool ServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { return false; } -QList ServiceRoot::contextMenu() { +QList ServiceRoot::contextMenuFeedsList() { return serviceMenu(); } -QList ServiceRoot::contextMenuForMessages(const QList& messages) { +QList ServiceRoot::contextMenuMessagesList(const QList& messages) { Q_UNUSED(messages) return {}; } diff --git a/src/librssguard/services/abstract/serviceroot.h b/src/librssguard/services/abstract/serviceroot.h index 3cf8d5f83..37328ce4c 100644 --- a/src/librssguard/services/abstract/serviceroot.h +++ b/src/librssguard/services/abstract/serviceroot.h @@ -53,9 +53,11 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList addItemMenu(); - // Returns actions to display as context menu. - virtual QList contextMenu(); - virtual QList contextMenuForMessages(const QList& messages); + // NOTE: Caller does NOT take ownership of created menu! + virtual QList contextMenuFeedsList(); + + // NOTE: Caller does NOT take ownership of created menu! + virtual QList contextMenuMessagesList(const QList& messages); // Returns list of specific actions to be shown in main window menu // bar in sections "Services -> 'this service'". diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 4a8785704..64eebcbd1 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -18,7 +18,8 @@ #include -GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent) : ServiceRoot(parent), m_network(network) { +GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent) + : ServiceRoot(parent), m_network(network), m_actionReply(nullptr) { if (network == nullptr) { m_network = new GmailNetworkFactory(this); } @@ -36,6 +37,10 @@ void GmailServiceRoot::updateTitle() { setTitle(m_network->username() + QSL(" (Gmail)")); } +void GmailServiceRoot::replyToEmail() { + FormAddEditEmail(this, qApp->mainFormWidget()).execForReply(&m_replyToMessage); +} + RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const { auto* root = new RootItem(); GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root); @@ -128,6 +133,22 @@ bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { } } +QList GmailServiceRoot::contextMenuMessagesList(const QList& messages) { + if (messages.size() == 1) { + if (m_actionReply == nullptr) { + m_actionReply = new QAction(qApp->icons()->fromTheme(QSL("mail-reply-sender")), tr("Reply"), this); + + m_replyToMessage = messages.at(0); + connect(m_actionReply, &QAction::triggered, this, &GmailServiceRoot::replyToEmail); + } + + return { m_actionReply }; + } + else { + return {}; + } +} + QList GmailServiceRoot::serviceMenu() { if (m_serviceMenu.isEmpty()) { ServiceRoot::serviceMenu(); diff --git a/src/librssguard/services/gmail/gmailserviceroot.h b/src/librssguard/services/gmail/gmailserviceroot.h index 035d618ea..0227b1887 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.h +++ b/src/librssguard/services/gmail/gmailserviceroot.h @@ -22,6 +22,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { void setNetwork(GmailNetworkFactory* network); GmailNetworkFactory* network() const; + QList contextMenuMessagesList(const QList& messages); QList serviceMenu(); bool isSyncable() const; bool canBeEdited() const; @@ -41,6 +42,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { public slots: void updateTitle(); + private slots: + void replyToEmail(); + protected: RootItem* obtainNewTreeForSyncIn() const; @@ -50,6 +54,8 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { private: GmailNetworkFactory* m_network; + QAction* m_actionReply; + Message m_replyToMessage; }; inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) { diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index f9a60b02e..d180fe3fe 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -112,15 +112,8 @@ void FormAddEditEmail::onOkClicked() { msg.set_plain(m_ui.m_txtMessage->toPlainText().toStdString()); msg.set_header("Content-Type", "text/plain; charset=utf-8"); - if (m_originalMessage == nullptr) { - // Send completely new message. - } - else { - // TODO: Reply to existing message. - } - try { - m_root->network()->sendEmail(msg); + m_root->network()->sendEmail(msg, m_originalMessage); accept(); } catch (const ApplicationException& ex) { @@ -141,7 +134,9 @@ void FormAddEditEmail::addRecipientRow(const QString& recipient) { mail_rec->setPossibleRecipients(rec); } - catch (const ApplicationException& ex) {} + catch (const ApplicationException& ex) { + qWarning("Failed to get recipients: '%s'.", qPrintable(ex.message())); + } m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec); } diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp index 9951650b4..d1c917515 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp @@ -52,13 +52,31 @@ void GmailNetworkFactory::setBatchSize(int batch_size) { m_batchSize = batch_size; } -QString GmailNetworkFactory::sendEmail(const Mimesis::Message& msg) { +QString GmailNetworkFactory::sendEmail(Mimesis::Message msg, Message* reply_to_message) { QString bearer = m_oauth2->bearer().toLocal8Bit(); if (bearer.isEmpty()) { throw ApplicationException(tr("you aren't logged in")); } + if (reply_to_message != nullptr) { + // We need to obtain some extra information. + + auto metadata = getMessageMetadata(reply_to_message->m_customId, { + QSL("References"), + QSL("Message-ID") + }); + + /*if (metadata.contains(QSL("References"))) { + + }*/ + + if (metadata.contains(QSL("Message-ID"))) { + msg["References"] = metadata.value(QSL("Message-ID")).toString().toStdString(); + msg["In-Reply-To"] = metadata.value(QSL("Message-ID")).toString().toStdString(); + } + } + QString rfc_email = QString::fromStdString(msg.to_string()); QByteArray input_data = rfc_email.toUtf8(); QList> headers; @@ -501,6 +519,36 @@ QStringList GmailNetworkFactory::getAllRecipients() { } } +QVariantMap GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QStringList& metadata) { + QString bearer = m_oauth2->bearer(); + + if (bearer.isEmpty()) { + throw ApplicationException(tr("you are not logged in")); + } + + QList> headers; + QByteArray output; + int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); + + headers.append(QPair(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), + bearer.toLocal8Bit())); + + QString query = QString("%1/%2?format=metadata&metadataHeaders=%3").arg(GMAIL_API_MSGS_LIST, + msg_id, + metadata.join(QSL("&metadataHeaders="))); + NetworkResult res = NetworkFactory::performNetworkOperation(query, + timeout, + QByteArray(), + output, + QNetworkAccessManager::Operation::GetOperation, + headers); + + if (res.first == QNetworkReply::NetworkError::NoError) {} + else { + throw ApplicationException(tr("failed to get metadata")); + } +} + bool GmailNetworkFactory::obtainAndDecodeFullMessages(const QList& lite_messages, const QString& feed_id, QList& full_messages) { diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.h b/src/librssguard/services/gmail/network/gmailnetworkfactory.h index f7297a048..a8568ace9 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.h +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.h @@ -36,7 +36,7 @@ class GmailNetworkFactory : public QObject { void setBatchSize(int batch_size); // Sends e-mail, returns its ID. - QString sendEmail(const Mimesis::Message& msg); + QString sendEmail(Mimesis::Message msg, Message* reply_to_message = nullptr); // Returns all possible recipients. QStringList getAllRecipients(); @@ -53,6 +53,7 @@ class GmailNetworkFactory : public QObject { private: bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id); + QVariantMap getMessageMetadata(const QString& msg_id, const QStringList& metadata); bool obtainAndDecodeFullMessages(const QList& lite_messages, const QString& feed_id, QList& full_messages); QList decodeLiteMessages(const QString& messages_json_data, const QString& stream_id, QString& next_page_token); diff --git a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp index 8dca47766..97f82f823 100644 --- a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp +++ b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp @@ -107,7 +107,7 @@ void FormEditOwnCloudAccount::performTest() { if (!SystemFactory::isVersionEqualOrNewer(result.version(), OWNCLOUD_MIN_VERSION)) { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, tr( - "Selected Nextcloud News server is running unsupported version (%1). At least version %2 is required.").arg( + "Selected Nextcloud News server is running unsupported version %1. At least version %2 is required.").arg( result.version(), OWNCLOUD_MIN_VERSION), tr("Selected Nextcloud News server is running unsupported version.")); diff --git a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp index 8db4f756c..6a1cd3068 100644 --- a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp +++ b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp @@ -120,6 +120,8 @@ OwnCloudStatusResponse OwnCloudNetworkFactory::status() { headers); OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw)); + qDebug().noquote().nospace() << "Raw status data is:" << result_raw; + if (network_reply.first != QNetworkReply::NoError) { qWarning("Nextcloud: Obtaining status info failed with error %d.", network_reply.first); } diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index c07ff2c19..70de02350 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -51,7 +51,7 @@ StandardFeed::~StandardFeed() { qDebug("Destroying Feed instance."); } -QList StandardFeed::contextMenu() { +QList StandardFeed::contextMenuFeedsList() { return serviceRoot()->getContextMenuForFeed(this); } diff --git a/src/librssguard/services/standard/standardfeed.h b/src/librssguard/services/standard/standardfeed.h index af5f066cd..186d29b86 100644 --- a/src/librssguard/services/standard/standardfeed.h +++ b/src/librssguard/services/standard/standardfeed.h @@ -35,7 +35,7 @@ class StandardFeed : public Feed { StandardServiceRoot* serviceRoot() const; - QList contextMenu(); + QList contextMenuFeedsList(); QString additionalTooltip() const; From 64df91a89113760be13cf0503fafdb5d82918fd1 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 30 Jul 2020 08:08:45 +0200 Subject: [PATCH 4/6] gmail plugin can send/reply to messages --- src/librssguard/3rd-party/boolinq/boolinq.h | 17 +-- src/librssguard/definitions/definitions.h | 20 ++++ src/librssguard/librssguard.pro | 3 + .../miscellaneous/databasequeries.cpp | 22 ++++ .../miscellaneous/databasequeries.h | 1 + .../services/gmail/gmailserviceroot.cpp | 6 +- .../gmail/gui/emailrecipientcontrol.cpp | 4 + .../services/gmail/gui/formaddeditemail.cpp | 31 +++-- .../services/gmail/gui/formaddeditemail.h | 2 + .../gmail/network/gmailnetworkfactory.cpp | 108 +++--------------- .../gmail/network/gmailnetworkfactory.h | 5 +- .../network/owncloudnetworkfactory.cpp | 2 +- 12 files changed, 103 insertions(+), 118 deletions(-) diff --git a/src/librssguard/3rd-party/boolinq/boolinq.h b/src/librssguard/3rd-party/boolinq/boolinq.h index 0d52c1167..c1c25696d 100755 --- a/src/librssguard/3rd-party/boolinq/boolinq.h +++ b/src/librssguard/3rd-party/boolinq/boolinq.h @@ -64,7 +64,7 @@ namespace boolinq { void for_each(std::function apply) const { - return for_each_i([apply](T value, int index) { return apply(value); }); + return for_each_i([apply](T value, int) { return apply(value); }); } Linq, int>, T> where_i(std::function filter) const @@ -87,7 +87,7 @@ namespace boolinq { Linq, int>, T> where(std::function filter) const { - return where_i([filter](T value, int index) { return filter(value); }); + return where_i([filter](T value, int) { return filter(value); }); } Linq, int>, T> take(int count) const @@ -296,13 +296,14 @@ namespace boolinq { Linq &linqCopy = std::get<1>(tuple); std::unordered_set<_TKey> &set = std::get<2>(tuple); - _TKey key = apply(linq.next()); - if (set.insert(key).second) { - return std::make_pair(key, linqCopy.where([apply, key](T v){ - return apply(v) == key; - })); + while (true) { + _TKey key = apply(linq.next()); + if (set.insert(key).second) { + return std::make_pair(key, linqCopy.where([apply, key](T v){ + return apply(v) == key; + })); + } } - throw LinqEndException(); } ); } diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 504f16c17..26d960562 100755 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -141,6 +141,26 @@ #define APP_NO_THEME "" #define APP_THEME_SUFFIX ".png" +#ifndef qDebugNN +#define qDebugNN qDebug().noquote().nospace() +#endif + +#ifndef qWarningNN +#define qWarningNN qWarning().noquote().nospace() +#endif + +#ifndef qCriticalNN +#define qCriticalNN qCritical().noquote().nospace() +#endif + +#ifndef qFatalNN +#define qFatalNN qFatal().noquote().nospace() +#endif + +#ifndef qInfoNN +#define qInfoNN qInfo().noquote().nospace() +#endif + #ifndef QSL // Thin macro wrapper for literal strings. diff --git a/src/librssguard/librssguard.pro b/src/librssguard/librssguard.pro index 80c25a86b..f1713b6cb 100644 --- a/src/librssguard/librssguard.pro +++ b/src/librssguard/librssguard.pro @@ -417,6 +417,9 @@ else { SOURCES += $$files(3rd-party/mimesis/*.cpp, false) HEADERS += $$files(3rd-party/mimesis/*.hpp, false) +# Add boolinq. +HEADERS += $$files(3rd-party/boolinq/*.h, false) + INCLUDEPATH += $$PWD/. \ $$PWD/gui \ $$PWD/gui/dialogs \ diff --git a/src/librssguard/miscellaneous/databasequeries.cpp b/src/librssguard/miscellaneous/databasequeries.cpp index 01132c82e..2b8c7d83e 100755 --- a/src/librssguard/miscellaneous/databasequeries.cpp +++ b/src/librssguard/miscellaneous/databasequeries.cpp @@ -1720,6 +1720,28 @@ bool DatabaseQueries::createTtRssAccount(const QSqlDatabase& db, int id_to_assig } } +QStringList DatabaseQueries::getAllRecipients(const QSqlDatabase& db, int account_id) { + QSqlQuery query(db); + QStringList rec; + + query.prepare(QSL("SELECT DISTINCT author " + "FROM Messages " + "WHERE account_id = :account_id AND author IS NOT NULL AND author != '' " + "ORDER BY lower(author) ASC;")); + query.bindValue(QSL(":account_id"), account_id); + + if (query.exec()) { + while (query.next()) { + rec.append(query.value(0).toString()); + } + } + else { + qWarningNN << "Query for all recipients failed: '" << query.lastError().text() << "'."; + } + + return rec; +} + QList DatabaseQueries::getGmailAccounts(const QSqlDatabase& db, bool* ok) { QSqlQuery query(db); QList roots; diff --git a/src/librssguard/miscellaneous/databasequeries.h b/src/librssguard/miscellaneous/databasequeries.h index 1f0aea30d..28afa1dd2 100644 --- a/src/librssguard/miscellaneous/databasequeries.h +++ b/src/librssguard/miscellaneous/databasequeries.h @@ -145,6 +145,7 @@ class DatabaseQueries { bool force_server_side_feed_update, bool download_only_unread_messages); // Gmail account. + static QStringList getAllRecipients(const QSqlDatabase& db, int account_id); static bool deleteGmailAccount(const QSqlDatabase& db, int account_id); static QList getGmailAccounts(const QSqlDatabase& db, bool* ok = nullptr); static bool overwriteGmailAccount(const QSqlDatabase& db, const QString& username, const QString& app_id, diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 64eebcbd1..6fc84ba19 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -135,10 +135,10 @@ bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { QList GmailServiceRoot::contextMenuMessagesList(const QList& messages) { if (messages.size() == 1) { - if (m_actionReply == nullptr) { - m_actionReply = new QAction(qApp->icons()->fromTheme(QSL("mail-reply-sender")), tr("Reply"), this); + m_replyToMessage = messages.at(0); - m_replyToMessage = messages.at(0); + if (m_actionReply == nullptr) { + m_actionReply = new QAction(qApp->icons()->fromTheme(QSL("mail-reply-sender")), tr("Reply to this message"), this); connect(m_actionReply, &QAction::triggered, this, &GmailServiceRoot::replyToEmail); } diff --git a/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp b/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp index a7c1fcab3..026f7b25a 100644 --- a/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp +++ b/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp @@ -61,5 +61,9 @@ void EmailRecipientControl::setPossibleRecipients(const QStringList& rec) { QCompleter* cmpl = new QCompleter(rec, m_txtRecipient); + cmpl->setFilterMode(Qt::MatchFlag::MatchContains); + cmpl->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); + cmpl->setCompletionMode(QCompleter::CompletionMode::UnfilteredPopupCompletion); + m_txtRecipient->setCompleter(cmpl); } diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index d180fe3fe..0065d9d4e 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -7,13 +7,18 @@ #include "gui/guiutilities.h" #include "gui/messagebox.h" #include "miscellaneous/application.h" +#include "miscellaneous/databasequeries.h" #include "miscellaneous/iconfactory.h" #include "services/gmail/gmailserviceroot.h" #include "services/gmail/gui/emailrecipientcontrol.h" #include "services/gmail/network/gmailnetworkfactory.h" +#include + +#include + FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) - : QDialog(parent), m_root(root), m_originalMessage(nullptr) { + : QDialog(parent), m_root(root), m_originalMessage(nullptr), m_possibleRecipients({}) { m_ui.setupUi(this); GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("mail-message-new"))); @@ -33,6 +38,14 @@ FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) &QPushButton::clicked, this, &FormAddEditEmail::onOkClicked); + + QSqlDatabase db = qApp->database()->connection(metaObject()->className()); + + m_possibleRecipients = DatabaseQueries::getAllRecipients(db, m_root->accountId()); + + for (auto* rec: recipientControls()) { + rec->setPossibleRecipients(m_possibleRecipients); + } } void FormAddEditEmail::execForAdd() { @@ -44,7 +57,7 @@ void FormAddEditEmail::execForReply(Message* original_message) { m_originalMessage = original_message; addRecipientRow(m_originalMessage->m_author); - m_ui.m_txtSubject->setText(QSL("Re:%1").arg(m_originalMessage->m_title)); + m_ui.m_txtSubject->setText(QSL("Re: %1").arg(m_originalMessage->m_title)); exec(); } @@ -129,18 +142,14 @@ void FormAddEditEmail::addRecipientRow(const QString& recipient) { connect(mail_rec, &EmailRecipientControl::removalRequested, this, &FormAddEditEmail::removeRecipientRow); - try { - QStringList rec = m_root->network()->getAllRecipients(); - - mail_rec->setPossibleRecipients(rec); - } - catch (const ApplicationException& ex) { - qWarning("Failed to get recipients: '%s'.", qPrintable(ex.message())); - } - + mail_rec->setPossibleRecipients(m_possibleRecipients); m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec); } +void FormAddEditEmail::closeEvent(QCloseEvent* event) { + // event->ignore(); +} + QList FormAddEditEmail::recipientControls() const { QList list; diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.h b/src/librssguard/services/gmail/gui/formaddeditemail.h index 0ce4f4b82..bc641c631 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.h +++ b/src/librssguard/services/gmail/gui/formaddeditemail.h @@ -31,6 +31,7 @@ class FormAddEditEmail : public QDialog { void addRecipientRow(const QString& recipient = QString()); private: + void closeEvent(QCloseEvent* event); QList recipientControls() const; private: @@ -39,6 +40,7 @@ class FormAddEditEmail : public QDialog { Ui::FormAddEditEmail m_ui; QList m_recipientControls; Message* m_originalMessage; + QStringList m_possibleRecipients; }; #endif // FORMADDEDITEMAIL_H diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp index d1c917515..aac217702 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp @@ -56,7 +56,7 @@ QString GmailNetworkFactory::sendEmail(Mimesis::Message msg, Message* reply_to_m QString bearer = m_oauth2->bearer().toLocal8Bit(); if (bearer.isEmpty()) { - throw ApplicationException(tr("you aren't logged in")); + //throw ApplicationException(tr("you aren't logged in")); } if (reply_to_message != nullptr) { @@ -72,8 +72,8 @@ QString GmailNetworkFactory::sendEmail(Mimesis::Message msg, Message* reply_to_m }*/ if (metadata.contains(QSL("Message-ID"))) { - msg["References"] = metadata.value(QSL("Message-ID")).toString().toStdString(); - msg["In-Reply-To"] = metadata.value(QSL("Message-ID")).toString().toStdString(); + msg["References"] = metadata.value(QSL("Message-ID")).toStdString(); + msg["In-Reply-To"] = metadata.value(QSL("Message-ID")).toStdString(); } } @@ -433,93 +433,7 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json, return true; } -QStringList GmailNetworkFactory::getAllRecipients() { - QString bearer = m_oauth2->bearer().toLocal8Bit(); - - if (bearer.isEmpty()) { - throw ApplicationException(tr("not logged-in")); - } - - QStringList recipients; - QList> headers; - - headers.append(QPair(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), - m_oauth2->bearer().toLocal8Bit())); - headers.append(QPair(QString(HTTP_HEADERS_CONTENT_TYPE).toLocal8Bit(), - QString(GMAIL_CONTENT_TYPE_JSON).toLocal8Bit())); - - int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray msg_list_data; - - // TODO: Cyklicky!! - auto list_res = NetworkFactory::performNetworkOperation(GMAIL_API_MSGS_LIST, - timeout, - QByteArray(), - msg_list_data, - QNetworkAccessManager::Operation::GetOperation, - headers); - - if (list_res.first != QNetworkReply::NetworkError::NoError) { - throw ApplicationException(tr("comm error when asking for recipients")); - } - - QJsonDocument json_list = QJsonDocument::fromJson(msg_list_data); - QStringList message_ids; - - for (const auto& msg_nod : json_list.object()["messages"].toArray()) { - message_ids.append(msg_nod.toObject()["id"].toString()); - } - - auto* multi = new QHttpMultiPart(); - - multi->setContentType(QHttpMultiPart::ContentType::MixedType); - - for (const QString& msg : message_ids) { - QHttpPart part; - - part.setRawHeader(HTTP_HEADERS_CONTENT_TYPE, GMAIL_CONTENT_TYPE_HTTP); - QString full_msg_endpoint = QString("GET /gmail/v1/users/me/messages/%1?metadataHeaders=From&metadataHeaders=To&format=metadata\r\n").arg(msg); - - part.setBody(full_msg_endpoint.toUtf8()); - multi->append(part); - } - - QList output; - - headers.removeLast(); - - NetworkResult res = NetworkFactory::performNetworkOperation(GMAIL_API_BATCH, - timeout, - multi, - output, - QNetworkAccessManager::Operation::PostOperation, - headers); - - if (res.first == QNetworkReply::NetworkError::NoError) { - // We parse each part of HTTP response (it contains HTTP headers and payload with msg full data). - for (const HttpResponse& part : output) { - QJsonObject msg_doc = QJsonDocument::fromJson(part.body().toUtf8()).object(); - auto headers = msg_doc["payload"].toObject()["headers"].toArray(); - - if (headers.size() >= 2) { - for (const auto& head : headers) { - auto val = head.toObject()["value"].toString(); - - if (!recipients.contains(val)) { - recipients.append(val); - } - } - } - } - - return recipients; - } - else { - throw ApplicationException(tr("comm error when asking for recipients")); - } -} - -QVariantMap GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QStringList& metadata) { +QMap GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QStringList& metadata) { QString bearer = m_oauth2->bearer(); if (bearer.isEmpty()) { @@ -543,7 +457,19 @@ QVariantMap GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QNetworkAccessManager::Operation::GetOperation, headers); - if (res.first == QNetworkReply::NetworkError::NoError) {} + if (res.first == QNetworkReply::NetworkError::NoError) { + QJsonDocument doc = QJsonDocument::fromJson(output); + QMap result; + auto headers = doc.object()["payload"].toObject()["headers"].toArray(); + + for (const auto& header : headers) { + QJsonObject obj_header = header.toObject(); + + result.insert(obj_header["name"].toString(), obj_header["value"].toString()); + } + + return result; + } else { throw ApplicationException(tr("failed to get metadata")); } diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.h b/src/librssguard/services/gmail/network/gmailnetworkfactory.h index a8568ace9..82726ebd9 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.h +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.h @@ -38,9 +38,6 @@ class GmailNetworkFactory : public QObject { // Sends e-mail, returns its ID. QString sendEmail(Mimesis::Message msg, Message* reply_to_message = nullptr); - // Returns all possible recipients. - QStringList getAllRecipients(); - Downloader* downloadAttachment(const QString& msg_id, const QString& attachment_id); QList messages(const QString& stream_id, Feed::Status& error); @@ -53,7 +50,7 @@ class GmailNetworkFactory : public QObject { private: bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id); - QVariantMap getMessageMetadata(const QString& msg_id, const QStringList& metadata); + QMap getMessageMetadata(const QString& msg_id, const QStringList& metadata); bool obtainAndDecodeFullMessages(const QList& lite_messages, const QString& feed_id, QList& full_messages); QList decodeLiteMessages(const QString& messages_json_data, const QString& stream_id, QString& next_page_token); diff --git a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp index 6a1cd3068..eaf927f26 100644 --- a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp +++ b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp @@ -120,7 +120,7 @@ OwnCloudStatusResponse OwnCloudNetworkFactory::status() { headers); OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw)); - qDebug().noquote().nospace() << "Raw status data is:" << result_raw; + qDebugNN << "Raw status data is:" << result_raw; if (network_reply.first != QNetworkReply::NoError) { qWarning("Nextcloud: Obtaining status info failed with error %d.", network_reply.first); From fe3b8f0a1f7b520379a7685b01efaebdc10ace0a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 31 Jul 2020 11:24:33 +0200 Subject: [PATCH 5/6] replace enum with enum class, some other refactorings. --- src/librssguard/core/feedsmodel.cpp | 41 +++++------- src/librssguard/core/feedsproxymodel.cpp | 12 ++-- src/librssguard/core/feedsproxymodel.h | 2 +- src/librssguard/core/messagesmodel.cpp | 29 +++++---- src/librssguard/gui/dialogs/formabout.cpp | 2 +- src/librssguard/gui/dialogs/formmain.cpp | 8 +-- src/librssguard/gui/feedsview.cpp | 22 +++---- src/librssguard/gui/messagesview.cpp | 8 +-- src/librssguard/gui/tabbar.cpp | 27 ++++++-- src/librssguard/gui/tabbar.h | 18 +++-- src/librssguard/gui/tabwidget.cpp | 22 ++++--- src/librssguard/gui/tabwidget.h | 59 ++++++++--------- src/librssguard/gui/treewidget.cpp | 4 +- src/librssguard/gui/treewidget.h | 6 +- src/librssguard/gui/webbrowser.cpp | 49 +++++++------- src/librssguard/librssguard.pro | 1 + src/librssguard/miscellaneous/application.cpp | 38 +++++------ src/librssguard/miscellaneous/application.h | 11 ++-- .../miscellaneous/databasequeries.cpp | 16 ++--- .../miscellaneous/databasequeries.h | 8 +-- src/librssguard/miscellaneous/settings.cpp | 8 +-- .../miscellaneous/settingsproperties.h | 3 +- src/librssguard/miscellaneous/templates.h | 4 ++ .../network-web/adblock/adblocktreewidget.cpp | 2 +- .../network-web/downloadmanager.cpp | 6 +- src/librssguard/network-web/downloadmanager.h | 2 +- src/librssguard/network-web/webpage.cpp | 8 +-- src/librssguard/network-web/webpage.h | 2 +- .../services/abstract/accountcheckmodel.cpp | 16 ++--- .../services/abstract/cacheforserviceroot.cpp | 10 ++- .../services/abstract/category.cpp | 8 +-- src/librssguard/services/abstract/feed.cpp | 28 ++++---- src/librssguard/services/abstract/feed.h | 4 +- .../services/abstract/gui/formfeeddetails.cpp | 25 +++---- .../services/abstract/importantnode.cpp | 4 +- .../services/abstract/recyclebin.cpp | 4 +- .../services/abstract/rootitem.cpp | 65 +++++++++---------- src/librssguard/services/abstract/rootitem.h | 44 ++++++------- .../services/abstract/serviceroot.cpp | 34 +++++----- .../services/gmail/gui/formaddeditemail.cpp | 4 -- .../services/gmail/gui/formaddeditemail.h | 1 - .../owncloud/gui/formowncloudfeeddetails.cpp | 2 +- .../network/owncloudnetworkfactory.cpp | 4 +- .../services/owncloud/owncloudfeed.cpp | 4 +- .../gui/formstandardcategorydetails.cpp | 4 +- .../standard/gui/formstandardimportexport.cpp | 16 ++--- .../standard/gui/formstandardimportexport.h | 4 +- .../services/standard/standardcategory.cpp | 4 +- .../services/standard/standardfeed.cpp | 28 ++++---- .../services/standard/standardfeed.h | 2 +- .../standardfeedsimportexportmodel.cpp | 18 ++--- .../services/standard/standardserviceroot.cpp | 8 +-- .../tt-rss/gui/formttrssfeeddetails.cpp | 2 +- .../tt-rss/network/ttrssnetworkfactory.h | 4 +- src/librssguard/services/tt-rss/ttrssfeed.cpp | 2 +- .../services/tt-rss/ttrssserviceroot.cpp | 12 ++-- 56 files changed, 407 insertions(+), 372 deletions(-) create mode 100755 src/librssguard/miscellaneous/templates.h diff --git a/src/librssguard/core/feedsmodel.cpp b/src/librssguard/core/feedsmodel.cpp index 73a9ec008..69201010f 100644 --- a/src/librssguard/core/feedsmodel.cpp +++ b/src/librssguard/core/feedsmodel.cpp @@ -2,6 +2,7 @@ #include "core/feedsmodel.h" +#include "3rd-party/boolinq/boolinq.h" #include "definitions/definitions.h" #include "gui/dialogs/formmain.h" #include "miscellaneous/databasefactory.h" @@ -68,7 +69,7 @@ QMimeData* FeedsModel::mimeData(const QModelIndexList& indexes) const { RootItem* item_for_index = itemForIndex(index); - if (item_for_index->kind() != RootItemKind::Root) { + if (item_for_index->kind() != RootItem::Kind::Root) { stream << quintptr(item_for_index); } } @@ -291,10 +292,10 @@ void FeedsModel::reassignNodeToNewParent(RootItem* original_node, RootItem* new_ } QListFeedsModel::serviceRoots() const { - QListroots; + QList roots; for (RootItem* root : m_rootItem->childItems()) { - if (root->kind() == RootItemKind::ServiceRoot) { + if (root->kind() == RootItem::Kind::ServiceRoot) { roots.append(root->toServiceRoot()); } } @@ -303,13 +304,9 @@ QListFeedsModel::serviceRoots() const { } bool FeedsModel::containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const { - for (const ServiceRoot* root : serviceRoots()) { - if (root->code() == point->code()) { - return true; - } - } - - return false; + return boolinq::from(serviceRoots()).any([=](ServiceRoot* root) { + return root->code() == point->code(); + }); } StandardServiceRoot* FeedsModel::standardServiceRoot() const { @@ -329,12 +326,12 @@ QListFeedsModel::feedsForScheduledUpdate(bool auto_update_now) { for (Feed* feed : m_rootItem->getSubTreeFeeds()) { switch (feed->autoUpdateType()) { - case Feed::DontAutoUpdate: + case Feed::AutoUpdateType::DontAutoUpdate: // Do not auto-update this feed ever. continue; - case Feed::DefaultAutoUpdate: + case Feed::AutoUpdateType::DefaultAutoUpdate: if (auto_update_now) { feeds_for_update.append(feed); @@ -342,7 +339,7 @@ QListFeedsModel::feedsForScheduledUpdate(bool auto_update_now) { break; - case Feed::SpecificAutoUpdate: + case Feed::AutoUpdateType::SpecificAutoUpdate: default: int remaining_interval = feed->autoUpdateRemainingInterval(); @@ -383,7 +380,7 @@ RootItem* FeedsModel::itemForIndex(const QModelIndex& index) const { } QModelIndex FeedsModel::indexForItem(const RootItem* item) const { - if (item == nullptr || item->kind() == RootItemKind::Root) { + if (item == nullptr || item->kind() == RootItem::Kind::Root) { // Root item lies on invalid index. return QModelIndex(); @@ -391,7 +388,7 @@ QModelIndex FeedsModel::indexForItem(const RootItem* item) const { QStack chain; - while (item->kind() != RootItemKind::Root) { + while (item->kind() != RootItem::Kind::Root) { chain.push(item); item = item->parent(); } @@ -412,13 +409,9 @@ QModelIndex FeedsModel::indexForItem(const RootItem* item) const { } bool FeedsModel::hasAnyFeedNewMessages() const { - for (const Feed* feed : m_rootItem->getSubTreeFeeds()) { - if (feed->status() == Feed::NewMessages) { - return true; - } - } - - return false; + return boolinq::from(m_rootItem->getSubTreeFeeds()).any([](const Feed* feed) { + return feed->status() == Feed::Status::NewMessages; + }); } RootItem* FeedsModel::rootItem() const { @@ -545,9 +538,7 @@ void FeedsModel::loadActivatedServiceAccounts() { } if (serviceRoots().isEmpty()) { - QTimer::singleShot(3000, - qApp->mainForm(), - []() { + QTimer::singleShot(3000, qApp->mainForm(), []() { qApp->mainForm()->showAddAccountDialog(); }); } diff --git a/src/librssguard/core/feedsproxymodel.cpp b/src/librssguard/core/feedsproxymodel.cpp index bac2d7d69..157872344 100644 --- a/src/librssguard/core/feedsproxymodel.cpp +++ b/src/librssguard/core/feedsproxymodel.cpp @@ -26,11 +26,11 @@ FeedsProxyModel::FeedsProxyModel(FeedsModel* source_model, QObject* parent) // means it should be more on top when sorting // in ascending order. m_priorities = { - RootItemKind::Kind::Category, - RootItemKind::Kind::Feed, - RootItemKind::Kind::Labels, - RootItemKind::Kind::Important, - RootItemKind::Kind::Bin + RootItem::Kind::Category, + RootItem::Kind::Feed, + RootItem::Kind::Labels, + RootItem::Kind::Important, + RootItem::Kind::Bin }; } @@ -218,7 +218,7 @@ bool FeedsProxyModel::filterAcceptsRowInternal(int source_row, const QModelIndex const RootItem* item = m_sourceModel->itemForIndex(idx); - if (item->kind() != RootItemKind::Category && item->kind() != RootItemKind::Feed) { + if (item->kind() != RootItem::Kind::Category && item->kind() != RootItem::Kind::Feed) { // Some items are always visible. return true; } diff --git a/src/librssguard/core/feedsproxymodel.h b/src/librssguard/core/feedsproxymodel.h index 75c5c268c..f69b8e9ff 100644 --- a/src/librssguard/core/feedsproxymodel.h +++ b/src/librssguard/core/feedsproxymodel.h @@ -48,7 +48,7 @@ class FeedsProxyModel : public QSortFilterProxyModel { const RootItem* m_selectedItem; bool m_showUnreadOnly; QList> m_hiddenIndices; - QList m_priorities; + QList m_priorities; }; #endif // FEEDSPROXYMODEL_H diff --git a/src/librssguard/core/messagesmodel.cpp b/src/librssguard/core/messagesmodel.cpp index 1607146c6..df9ad79ab 100644 --- a/src/librssguard/core/messagesmodel.cpp +++ b/src/librssguard/core/messagesmodel.cpp @@ -111,7 +111,7 @@ bool MessagesModel::setMessageImportantById(int id, RootItem::Importance importa int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); if (found_id == id) { - bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), important); + bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), int(important)); if (set) { emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX)); @@ -347,7 +347,7 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const { } bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { - if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) { + if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == int(read)) { // Read status is the same is the one currently set. // In that case, no extra work is needed. return true; @@ -361,7 +361,7 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { } // Rewrite "visible" data in the model. - bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), read); + bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), int(read)); if (!working_change) { // If rewriting in the model failed, then cancel all actions. @@ -382,7 +382,7 @@ bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) { int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); if (found_id == id) { - bool set = setData(index(i, MSG_DB_READ_INDEX), read); + bool set = setData(index(i, MSG_DB_READ_INDEX), int(read)); if (set) { emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX)); @@ -398,8 +398,9 @@ bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) { bool MessagesModel::switchMessageImportance(int row_index) { const QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX); const RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt(); - const RootItem::Importance next_importance = current_importance == RootItem::Important ? - RootItem::NotImportant : RootItem::Important; + const RootItem::Importance next_importance = current_importance == RootItem::Importance::Important + ? RootItem::Importance::NotImportant + : RootItem::Importance::Important; const Message message = messageAt(row_index); const QPair pair(message, next_importance); @@ -409,7 +410,7 @@ bool MessagesModel::switchMessageImportance(int row_index) { } // Rewrite "visible" data in the model. - const bool working_change = setData(target_index, next_importance); + const bool working_change = setData(target_index, int(next_importance)); if (!working_change) { // If rewriting in the model failed, then cancel all actions. @@ -439,15 +440,15 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList& messages RootItem::Importance message_importance = messageImportance((message.row())); - message_states.append(QPair(msg, message_importance == RootItem::Important ? - RootItem::NotImportant : - RootItem::Important)); + message_states.append(QPair(msg, message_importance == RootItem::Importance::Important + ? RootItem::Importance::NotImportant + : RootItem::Importance::Important)); message_ids.append(QString::number(msg.m_id)); QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX); - setData(idx_msg_imp, message_importance == RootItem::Important ? - (int) RootItem::NotImportant : - (int) RootItem::Important); + setData(idx_msg_imp, message_importance == RootItem::Importance::Important + ? int(RootItem::Importance::NotImportant) + : int(RootItem::Importance::Important)); } reloadWholeLayout(); @@ -491,7 +492,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList& messages) { bool deleted; - if (m_selectedItem->kind() != RootItemKind::Bin) { + if (m_selectedItem->kind() != RootItem::Kind::Bin) { deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true); } else { diff --git a/src/librssguard/gui/dialogs/formabout.cpp b/src/librssguard/gui/dialogs/formabout.cpp index 632f27573..b8ee98b67 100644 --- a/src/librssguard/gui/dialogs/formabout.cpp +++ b/src/librssguard/gui/dialogs/formabout.cpp @@ -25,7 +25,7 @@ FormAbout::~FormAbout() { } void FormAbout::loadSettingsAndPaths() { - if (qApp->settings()->type() == SettingsProperties::Portable) { + if (qApp->settings()->type() == SettingsProperties::SettingsType::Portable) { m_ui.m_txtPathsSettingsType->setText(tr("FULLY portable")); } else { diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index 1f30788b5..5df1ef52a 100755 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -391,7 +391,7 @@ void FormMain::updateMessageButtonsAvailability() { const bool one_message_selected = tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().size() == 1; const bool atleast_one_message_selected = !tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().isEmpty(); const bool bin_loaded = tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem() != nullptr - && tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItemKind::Bin; + && tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItem::Kind::Bin; m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected); m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded); @@ -408,9 +408,9 @@ void FormMain::updateFeedButtonsAvailability() { const bool critical_action_running = qApp->feedUpdateLock()->isLocked(); const RootItem* selected_item = tabWidget()->feedMessageViewer()->feedsView()->selectedItem(); const bool anything_selected = selected_item != nullptr; - const bool feed_selected = anything_selected && selected_item->kind() == RootItemKind::Feed; - const bool category_selected = anything_selected && selected_item->kind() == RootItemKind::Category; - const bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot; + const bool feed_selected = anything_selected && selected_item->kind() == RootItem::Kind::Feed; + const bool category_selected = anything_selected && selected_item->kind() == RootItem::Kind::Category; + const bool service_selected = anything_selected && selected_item->kind() == RootItem::Kind::ServiceRoot; m_ui->m_actionStopRunningItemsUpdate->setEnabled(is_update_running); m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp index 343ee9511..dc66aa8f5 100755 --- a/src/librssguard/gui/feedsview.cpp +++ b/src/librssguard/gui/feedsview.cpp @@ -95,7 +95,7 @@ void FeedsView::saveAllExpandStates() { void FeedsView::saveExpandStates(RootItem* item) { Settings* settings = qApp->settings(); - QList items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot); + QList items = item->getSubTree(RootItem::Kind::Category | RootItem::Kind::ServiceRoot); // Iterate all categories and save their expand statuses. for (const RootItem* it : items) { @@ -113,7 +113,7 @@ void FeedsView::loadAllExpandStates() { const Settings* settings = qApp->settings(); QList expandable_items; - expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot)); + expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItem::Kind::Category | RootItem::Kind::ServiceRoot)); // Iterate all categories and save their expand statuses. for (const RootItem* item : expandable_items) { @@ -305,11 +305,11 @@ void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { } void FeedsView::markSelectedItemRead() { - markSelectedItemReadStatus(RootItem::Read); + markSelectedItemReadStatus(RootItem::ReadStatus::Read); } void FeedsView::markSelectedItemUnread() { - markSelectedItemReadStatus(RootItem::Unread); + markSelectedItemReadStatus(RootItem::ReadStatus::Unread); } void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { @@ -317,7 +317,7 @@ void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { } void FeedsView::markAllItemsRead() { - markAllItemsReadStatus(RootItem::Read); + markAllItemsReadStatus(RootItem::ReadStatus::Read); } void FeedsView::openSelectedItemsInNewspaperMode() { @@ -660,21 +660,21 @@ void FeedsView::contextMenuEvent(QContextMenuEvent* event) { const QModelIndex mapped_index = model()->mapToSource(clicked_index); RootItem* clicked_item = sourceModel()->itemForIndex(mapped_index); - if (clicked_item->kind() == RootItemKind::Category) { + if (clicked_item->kind() == RootItem::Kind::Category) { // Display context menu for categories. initializeContextMenuCategories(clicked_item)->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItemKind::Feed) { + else if (clicked_item->kind() == RootItem::Kind::Feed) { // Display context menu for feeds. initializeContextMenuFeeds(clicked_item)->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItemKind::Important) { + else if (clicked_item->kind() == RootItem::Kind::Important) { initializeContextMenuImportant(clicked_item)->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItemKind::Bin) { + else if (clicked_item->kind() == RootItem::Kind::Bin) { initializeContextMenuBin(clicked_item)->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItemKind::ServiceRoot) { + else if (clicked_item->kind() == RootItem::Kind::ServiceRoot) { initializeContextMenuService(clicked_item)->exec(event->globalPos()); } else { @@ -693,7 +693,7 @@ void FeedsView::mouseDoubleClickEvent(QMouseEvent* event) { if (idx.isValid()) { RootItem* item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx)); - if (item->kind() == RootItemKind::Feed || item->kind() == RootItemKind::Bin) { + if (item->kind() == RootItem::Kind::Feed || item->kind() == RootItem::Kind::Bin) { const QList messages = m_sourceModel->messagesForItem(item); if (!messages.isEmpty()) { diff --git a/src/librssguard/gui/messagesview.cpp b/src/librssguard/gui/messagesview.cpp index ff789aaec..62a8d68bf 100644 --- a/src/librssguard/gui/messagesview.cpp +++ b/src/librssguard/gui/messagesview.cpp @@ -225,7 +225,7 @@ void MessagesView::initializeContextMenu() { << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); if (m_sourceModel->loadedItem() != nullptr) { - if (m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { + if (m_sourceModel->loadedItem()->kind() == RootItem::Kind::Bin) { m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); } @@ -308,7 +308,7 @@ void MessagesView::selectionChanged(const QItemSelection& selected, const QItemS // Set this message as read only if current item // wasn't changed by "mark selected messages unread" action. - m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::Read); + m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::ReadStatus::Read); message.m_isRead = true; emit currentMessageChanged(message, m_sourceModel->loadedItem()); @@ -389,11 +389,11 @@ void MessagesView::sendSelectedMessageViaEmail() { } void MessagesView::markSelectedMessagesRead() { - setSelectedMessagesReadStatus(RootItem::Read); + setSelectedMessagesReadStatus(RootItem::ReadStatus::Read); } void MessagesView::markSelectedMessagesUnread() { - setSelectedMessagesReadStatus(RootItem::Unread); + setSelectedMessagesReadStatus(RootItem::ReadStatus::Unread); } void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) { diff --git a/src/librssguard/gui/tabbar.cpp b/src/librssguard/gui/tabbar.cpp index 9858e1531..fde45d09b 100644 --- a/src/librssguard/gui/tabbar.cpp +++ b/src/librssguard/gui/tabbar.cpp @@ -5,6 +5,7 @@ #include "definitions/definitions.h" #include "gui/plaintoolbutton.h" #include "miscellaneous/settings.h" +#include "miscellaneous/templates.h" #include #include @@ -25,8 +26,8 @@ void TabBar::setTabType(int index, const TabBar::TabType& type) { this)); switch (type) { - case TabBar::DownloadManager: - case TabBar::Closable: { + case TabBar::TabType::DownloadManager: + case TabBar::TabType::Closable: { auto* close_button = new PlainToolButton(this); close_button->setIcon(qApp->icons()->fromTheme(QSL("application-exit"))); @@ -45,7 +46,7 @@ void TabBar::setTabType(int index, const TabBar::TabType& type) { break; } - setTabData(index, QVariant(type)); + setTabData(index, QVariant(int(type))); } void TabBar::closeTabViaButton() { @@ -99,7 +100,7 @@ void TabBar::mousePressEvent(QMouseEvent* event) { // destination does not know the original event. if ((event->button() & Qt::MiddleButton) == Qt::MiddleButton && qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseMiddleClick)).toBool()) { - if (tabType(tab_index) == TabBar::Closable || tabType(tab_index) == TabBar::DownloadManager) { + if (tabType(tab_index) == TabBar::TabType::Closable || tabType(tab_index) == TabBar::TabType::DownloadManager) { // This tab is closable, so we can close it. emit tabCloseRequested(tab_index); } @@ -118,7 +119,7 @@ void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { // destination does not know the original event. if ((event->button() & Qt::LeftButton) == Qt::LeftButton && qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool()) { - if ((tabType(tab_index) & (TabBar::Closable | TabBar::DownloadManager)) > 0) { + if (int(tabType(tab_index) & (TabBar::TabType::Closable | TabBar::TabType::DownloadManager)) > 0) { // This tab is closable, so we can close it. emit tabCloseRequested(tab_index); } @@ -128,3 +129,19 @@ void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { emit emptySpaceDoubleClicked(); } } + +TabBar::TabType& operator&=(TabBar::TabType& a, TabBar::TabType b) { + return (TabBar::TabType&)((int&)a &= (int)b); +} + +TabBar::TabType& operator|=(TabBar::TabType& a, TabBar::TabType b) { + return (TabBar::TabType&)((int&)a |= (int)b); +} + +TabBar::TabType operator&(TabBar::TabType a, TabBar::TabType b) { + return (TabBar::TabType)((int)a & (int)b); +} + +TabBar::TabType operator|(TabBar::TabType a, TabBar::TabType b) { + return (TabBar::TabType)((int)a | (int)b); +} diff --git a/src/librssguard/gui/tabbar.h b/src/librssguard/gui/tabbar.h index c54a98432..5aa9b4c33 100644 --- a/src/librssguard/gui/tabbar.h +++ b/src/librssguard/gui/tabbar.h @@ -12,7 +12,7 @@ class TabBar : public QTabBar { Q_OBJECT public: - enum TabType { + enum class TabType { FeedReader = 1, DownloadManager = 2, NonClosable = 4, @@ -20,15 +20,12 @@ class TabBar : public QTabBar { }; // Constructors. - explicit TabBar(QWidget* parent = 0); + explicit TabBar(QWidget* parent = nullptr); virtual ~TabBar(); // Getter/setter for tab type. void setTabType(int index, const TabBar::TabType& type); - - inline TabBar::TabType tabType(int index) const { - return static_cast(tabData(index).toInt()); - } + TabBar::TabType tabType(int index) const; private slots: @@ -48,4 +45,13 @@ class TabBar : public QTabBar { void emptySpaceDoubleClicked(); }; +inline TabBar::TabType TabBar::tabType(int index) const { + return static_cast(tabData(index).toInt()); +} + +TabBar::TabType operator| (TabBar::TabType a, TabBar::TabType b); +TabBar::TabType operator& (TabBar::TabType a, TabBar::TabType b); +TabBar::TabType& operator|= (TabBar::TabType& a, TabBar::TabType b); +TabBar::TabType& operator&= (TabBar::TabType& a, TabBar::TabType b); + #endif // TABBAR_H diff --git a/src/librssguard/gui/tabwidget.cpp b/src/librssguard/gui/tabwidget.cpp index 6475ab14a..71eeab61b 100644 --- a/src/librssguard/gui/tabwidget.cpp +++ b/src/librssguard/gui/tabwidget.cpp @@ -77,7 +77,10 @@ void TabWidget::showDownloadManager() { // Download manager is not opened. Create tab with it. qApp->downloadManager()->setParent(this); - addTab(qApp->downloadManager(), qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("Downloads"), TabBar::DownloadManager); + addTab(qApp->downloadManager(), + qApp->icons()->fromTheme(QSL("emblem-downloads")), + tr("Downloads"), + TabBar::TabType::DownloadManager); setCurrentIndex(count() - 1); } @@ -130,7 +133,7 @@ void TabWidget::createConnections() { void TabWidget::initializeTabs() { // Create widget for "Feeds" page and add it. m_feedMessageViewer = new FeedMessageViewer(this); - const int index_of_browser = addTab(m_feedMessageViewer, QIcon(), tr("Feeds"), TabBar::FeedReader); + const int index_of_browser = addTab(m_feedMessageViewer, QIcon(), tr("Feeds"), TabBar::TabType::FeedReader); setTabToolTip(index_of_browser, tr("Browse your feeds and messages")); } @@ -140,18 +143,18 @@ void TabWidget::setupIcons() { // accordingly. for (int index = 0; index < count(); index++) { // Index 0 usually contains widget which displays feeds & messages. - if (tabBar()->tabType(index) == TabBar::FeedReader) { + if (tabBar()->tabType(index) == TabBar::TabType::FeedReader) { setTabIcon(index, qApp->icons()->fromTheme(QSL("application-rss+xml"))); } } } bool TabWidget::closeTab(int index) { - if (tabBar()->tabType(index) == TabBar::Closable) { + if (tabBar()->tabType(index) == TabBar::TabType::Closable) { removeTab(index, true); return true; } - else if (tabBar()->tabType(index) == TabBar::DownloadManager) { + else if (tabBar()->tabType(index) == TabBar::TabType::DownloadManager) { removeTab(index, false); return true; } @@ -198,7 +201,10 @@ int TabWidget::addNewspaperView(RootItem* root, const QList& messages) m_feedMessageViewer->messagesView()->sourceModel(), &MessagesModel::setMessageImportantById); #endif - int index = addTab(prev, qApp->icons()->fromTheme(QSL("format-justify-fill")), tr("Newspaper view"), TabBar::Closable); + int index = addTab(prev, + qApp->icons()->fromTheme(QSL("format-justify-fill")), + tr("Newspaper view"), + TabBar::TabType::Closable); // NOTE: Do not bring "newspaper" tabs to front anymore. //setCurrentIndex(index); @@ -236,13 +242,13 @@ int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl& if (move_after_current) { // Insert web browser after current tab. final_index = insertTab(currentIndex() + 1, browser, qApp->icons()->fromTheme(QSL("text-html")), - browser_tab_name, TabBar::Closable); + browser_tab_name, TabBar::TabType::Closable); } else { // Add new browser as the last tab. final_index = addTab(browser, qApp->icons()->fromTheme(QSL("text-html")), browser_tab_name, - TabBar::Closable); + TabBar::TabType::Closable); } // Make connections. diff --git a/src/librssguard/gui/tabwidget.h b/src/librssguard/gui/tabwidget.h index 7a3c91c4a..ff9b8fa88 100644 --- a/src/librssguard/gui/tabwidget.h +++ b/src/librssguard/gui/tabwidget.h @@ -22,33 +22,27 @@ class TabWidget : public QTabWidget { public: // Constructors and destructors. - explicit TabWidget(QWidget* parent = 0); + explicit TabWidget(QWidget* parent = nullptr); virtual ~TabWidget(); // Manimulators for tabs. int addTab(TabContent* widget, const QString&, - const TabBar::TabType& type = TabBar::NonClosable); + const TabBar::TabType& type = TabBar::TabType::NonClosable); int addTab(TabContent* widget, const QIcon& icon, - const QString& label, const TabBar::TabType& type = TabBar::NonClosable); + const QString& label, const TabBar::TabType& type = TabBar::TabType::NonClosable); int insertTab(int index, QWidget* widget, const QString& label, - const TabBar::TabType& type = TabBar::Closable); + const TabBar::TabType& type = TabBar::TabType::Closable); int insertTab(int index, QWidget* widget, const QIcon& icon, - const QString& label, const TabBar::TabType& type = TabBar::NonClosable); + const QString& label, const TabBar::TabType& type = TabBar::TabType::NonClosable); void removeTab(int index, bool clear_from_memory); // Returns tab bar. - inline TabBar* tabBar() const { - return static_cast(QTabWidget::tabBar()); - } + TabBar* tabBar() const; // Returns the central widget of this tab. - inline TabContent* widget(int index) const { - return static_cast(QTabWidget::widget(index)); - } + TabContent* widget(int index) const; - inline TabContent* currentWidget() const { - return static_cast(QTabWidget::currentWidget()); - } + TabContent* currentWidget() const; // Initializes TabWidget with tabs, this includes initialization // of main "Feeds" widget. @@ -58,21 +52,7 @@ class TabWidget : public QTabWidget { void setupIcons(); // Accessor to feed/message viewer. - inline FeedMessageViewer* feedMessageViewer() const { - return m_feedMessageViewer; - } - - protected: - - // Creates necesary connections. - void createConnections(); - - // Sets up properties of custom corner button. - void setupMainMenuButton(); - - // Handlers of insertin/removing of tabs. - void tabInserted(int index); - void tabRemoved(int index); + FeedMessageViewer* feedMessageViewer() const; public slots: @@ -117,10 +97,31 @@ class TabWidget : public QTabWidget { private: void indentTabText(int index); + void createConnections(); + void setupMainMenuButton(); + + void tabInserted(int index); + void tabRemoved(int index); PlainToolButton* m_btnMainMenu; QMenu* m_menuMain; FeedMessageViewer* m_feedMessageViewer; }; +inline TabBar* TabWidget::tabBar() const { + return static_cast(QTabWidget::tabBar()); +} + +inline TabContent* TabWidget::widget(int index) const { + return static_cast(QTabWidget::widget(index)); +} + +inline TabContent* TabWidget::currentWidget() const { + return static_cast(QTabWidget::currentWidget()); +} + +inline FeedMessageViewer* TabWidget::feedMessageViewer() const { + return m_feedMessageViewer; +} + #endif // TABWIDGET_H diff --git a/src/librssguard/gui/treewidget.cpp b/src/librssguard/gui/treewidget.cpp index b9715b446..507e0f2dd 100644 --- a/src/librssguard/gui/treewidget.cpp +++ b/src/librssguard/gui/treewidget.cpp @@ -22,7 +22,7 @@ #include TreeWidget::TreeWidget(QWidget* parent) - : QTreeWidget(parent), m_refreshAllItemsNeeded(true), m_showMode(ItemsCollapsed) { + : QTreeWidget(parent), m_refreshAllItemsNeeded(true), m_showMode(ItemShowMode::ItemsCollapsed) { connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(sheduleRefresh())); } @@ -123,7 +123,7 @@ void TreeWidget::filterString(const QString& string) { parentItem->setHidden(false); if (stringIsEmpty) { - parentItem->setExpanded(m_showMode == ItemsExpanded); + parentItem->setExpanded(m_showMode == ItemShowMode::ItemsExpanded); } else { parentItem->setExpanded(true); diff --git a/src/librssguard/gui/treewidget.h b/src/librssguard/gui/treewidget.h index d4d6595cf..22e7081b8 100644 --- a/src/librssguard/gui/treewidget.h +++ b/src/librssguard/gui/treewidget.h @@ -28,7 +28,10 @@ class TreeWidget : public QTreeWidget { public: explicit TreeWidget(QWidget* parent = 0); - enum ItemShowMode { ItemsCollapsed = 0, ItemsExpanded = 1 }; + enum class ItemShowMode { + ItemsCollapsed = 0, + ItemsExpanded = 1 + }; ItemShowMode defaultItemShowMode() { return m_showMode; @@ -69,7 +72,6 @@ class TreeWidget : public QTreeWidget { void iterateAllItems(QTreeWidgetItem* parent); bool m_refreshAllItemsNeeded; - QList m_allTreeItems; ItemShowMode m_showMode; }; diff --git a/src/librssguard/gui/webbrowser.cpp b/src/librssguard/gui/webbrowser.cpp index 3a0ddb7df..3e0f34c7b 100644 --- a/src/librssguard/gui/webbrowser.cpp +++ b/src/librssguard/gui/webbrowser.cpp @@ -156,19 +156,19 @@ bool WebBrowser::eventFilter(QObject* watched, QEvent* event) { void WebBrowser::receiveMessageStatusChangeRequest(int message_id, WebPage::MessageStatusChange change) { switch (change) { - case WebPage::MarkRead: + case WebPage::MessageStatusChange::MarkRead: markMessageAsRead(message_id, true); break; - case WebPage::MarkUnread: + case WebPage::MessageStatusChange::MarkUnread: markMessageAsRead(message_id, false); break; - case WebPage::MarkStarred: + case WebPage::MessageStatusChange::MarkStarred: switchMessageImportance(message_id, true); break; - case WebPage::MarkUnstarred: + case WebPage::MessageStatusChange::MarkUnstarred: switchMessageImportance(message_id, false); break; @@ -265,16 +265,18 @@ void WebBrowser::markMessageAsRead(int id, bool read) { if (msg != nullptr && m_root->getParentServiceRoot()->onBeforeSetMessagesRead(m_root.data(), QList() << *msg, - read ? RootItem::Read : RootItem::Unread)) { + read + ? RootItem::ReadStatus::Read + : RootItem::ReadStatus::Unread)) { DatabaseQueries::markMessagesReadUnread(qApp->database()->connection(objectName()), QStringList() << QString::number(msg->m_id), - read ? RootItem::Read : RootItem::Unread); + read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread); m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(), QList() << *msg, - read ? RootItem::Read : RootItem::Unread); - emit markMessageRead(msg->m_id, read ? RootItem::Read : RootItem::Unread); + read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread); + emit markMessageRead(msg->m_id, read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread); - msg->m_isRead = read ? RootItem::Read : RootItem::Unread; + msg->m_isRead = read; } } } @@ -283,23 +285,24 @@ void WebBrowser::switchMessageImportance(int id, bool checked) { if (!m_root.isNull()) { Message* msg = findMessage(id); - if (msg != nullptr && m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(), - QList() << - ImportanceChange(*msg, - msg - ->m_isImportant ? - RootItem - ::NotImportant : - RootItem - ::Important))) { + if (msg != nullptr && + m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(), + QList() + << ImportanceChange(*msg, + msg->m_isImportant + ? RootItem::Importance::NotImportant + : RootItem::Importance::Important))) { DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName()), QStringList() << QString::number(msg->m_id)); m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(), - QList() << ImportanceChange(*msg, - msg->m_isImportant ? - RootItem::NotImportant : - RootItem::Important)); - emit markMessageImportant(msg->m_id, msg->m_isImportant ? RootItem::NotImportant : RootItem::Important); + QList() + << ImportanceChange(*msg, + msg->m_isImportant ? + RootItem::Importance::NotImportant : + RootItem::Importance::Important)); + emit markMessageImportant(msg->m_id, msg->m_isImportant + ? RootItem::Importance::NotImportant + : RootItem::Importance::Important); msg->m_isImportant = checked; } diff --git a/src/librssguard/librssguard.pro b/src/librssguard/librssguard.pro index f1713b6cb..08d403952 100644 --- a/src/librssguard/librssguard.pro +++ b/src/librssguard/librssguard.pro @@ -109,6 +109,7 @@ HEADERS += core/feeddownloader.h \ miscellaneous/simplecrypt/simplecrypt.h \ miscellaneous/skinfactory.h \ miscellaneous/systemfactory.h \ + miscellaneous/templates.h \ miscellaneous/textfactory.h \ network-web/basenetworkaccessmanager.h \ network-web/downloader.h \ diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index dd0ed7f02..2713913c8 100755 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -57,6 +57,8 @@ Application::Application(const QString& id, int& argc, char** argv) // Setup debug output system. qInstallMessageHandler(Debugging::debugHandler); + determineFirstRuns(); + //: Abbreviation of language, e.g. en. //: Use ISO 639-1 code here combined with ISO 3166-1 (alpha-2) code. //: Examples: "cs", "en", "it", "cs_CZ", "en_GB", "en_US". @@ -129,7 +131,7 @@ void Application::showPolls() const { } void Application::offerChanges() const { - if (isFirstRun() || isFirstRun(APP_VERSION)) { + if (isFirstRunCurrentVersion()) { qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.\n\nPlease, check NEW stuff included in this\n" "version by clicking this popup notification.").arg(APP_LONG_NAME), QSystemTrayIcon::NoIcon, nullptr, false, [] { @@ -159,17 +161,11 @@ QList Application::userActions() { } bool Application::isFirstRun() const { - return settings()->value(GROUP(General), SETTING(General::FirstRun)).toBool(); + return m_firstRunEver; } -bool Application::isFirstRun(const QString& version) const { - if (version == APP_VERSION) { - // Check this only if checked version is equal to actual version. - return settings()->value(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, true).toBool(); - } - else { - return false; - } +bool Application::isFirstRunCurrentVersion() const { + return m_firstRunCurrentVersion; } WebFactory* Application::web() const { @@ -192,12 +188,9 @@ DatabaseFactory* Application::database() { return m_database; } -void Application::eliminateFirstRun() { +void Application::eliminateFirstRuns() { settings()->setValue(GROUP(General), General::FirstRun, false); -} - -void Application::eliminateFirstRun(const QString& version) { - settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, false); + settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + APP_VERSION, false); } void Application::setFeedReader(FeedReader* feed_reader) { @@ -253,7 +246,7 @@ QString Application::userDataAppFolder() { } QString Application::userDataFolder() { - if (settings()->type() == SettingsProperties::Portable) { + if (settings()->type() == SettingsProperties::SettingsType::Portable) { return userDataAppFolder(); } else { @@ -447,9 +440,6 @@ void Application::onAboutToQuit() { m_quitLogicDone = true; - eliminateFirstRun(); - eliminateFirstRun(APP_VERSION); - #if defined(USE_WEBENGINE) AdBlockManager::instance()->save(); #endif @@ -527,3 +517,13 @@ void Application::onFeedUpdatesFinished(const FeedDownloadResults& results) { nullptr, false); } } + +void Application::determineFirstRuns() { + m_firstRunEver = settings()->value(GROUP(General), + SETTING(General::FirstRun)).toBool(); + m_firstRunCurrentVersion = settings()->value(GROUP(General), + QString(General::FirstRun) + QL1C('_') + APP_VERSION, + true).toBool(); + + eliminateFirstRuns(); +} diff --git a/src/librssguard/miscellaneous/application.h b/src/librssguard/miscellaneous/application.h index 60cf6232e..4233d9370 100755 --- a/src/librssguard/miscellaneous/application.h +++ b/src/librssguard/miscellaneous/application.h @@ -55,7 +55,6 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication { bool isAlreadyRunning(); FeedReader* feedReader(); - void setFeedReader(FeedReader* feed_reader); // Globally accessible actions. @@ -64,8 +63,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication { // Check whether this application starts for the first time (ever). bool isFirstRun() const; - // Check whether GIVEN VERSION of the application starts for the first time. - bool isFirstRun(const QString& version) const; + // Check whether CURRENT VERSION of the application starts for the first time. + bool isFirstRunCurrentVersion() const; WebFactory* web() const; SystemFactory* system(); @@ -139,8 +138,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication { void onFeedUpdatesFinished(const FeedDownloadResults& results); private: - void eliminateFirstRun(); - void eliminateFirstRun(const QString& version); + void determineFirstRuns(); + void eliminateFirstRuns(); #if defined(USE_WEBENGINE) NetworkUrlInterceptor* m_urlInterceptor; @@ -176,6 +175,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication { DatabaseFactory* m_database; DownloadManager* m_downloadManager; bool m_shouldRestart; + bool m_firstRunEver; + bool m_firstRunCurrentVersion; }; inline Application* Application::instance() { diff --git a/src/librssguard/miscellaneous/databasequeries.cpp b/src/librssguard/miscellaneous/databasequeries.cpp index 2b8c7d83e..ffc38813d 100755 --- a/src/librssguard/miscellaneous/databasequeries.cpp +++ b/src/librssguard/miscellaneous/databasequeries.cpp @@ -37,7 +37,7 @@ bool DatabaseQueries::markImportantMessagesReadUnread(const QSqlDatabase& db, in q.setForwardOnly(true); q.prepare("UPDATE Messages SET is_read = :read " "WHERE is_important = 1 AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;"); - q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0); q.bindValue(QSL(":account_id"), account_id); return q.exec(); } @@ -47,7 +47,7 @@ bool DatabaseQueries::markMessagesReadUnread(const QSqlDatabase& db, const QStri q.setForwardOnly(true); return q.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) - .arg(ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0"))); + .arg(ids.join(QSL(", ")), read == RootItem::ReadStatus::Read ? QSL("1") : QSL("0"))); } bool DatabaseQueries::markMessageImportant(const QSqlDatabase& db, int id, RootItem::Importance importance) { @@ -73,7 +73,7 @@ bool DatabaseQueries::markFeedsReadUnread(const QSqlDatabase& db, const QStringL q.setForwardOnly(true); q.prepare(QString("UPDATE Messages SET is_read = :read " "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;").arg(ids.join(QSL(", ")))); - q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0); q.bindValue(QSL(":account_id"), account_id); return q.exec(); } @@ -84,7 +84,7 @@ bool DatabaseQueries::markBinReadUnread(const QSqlDatabase& db, int account_id, q.setForwardOnly(true); q.prepare("UPDATE Messages SET is_read = :read " "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); - q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0); q.bindValue(QSL(":account_id"), account_id); return q.exec(); } @@ -95,7 +95,7 @@ bool DatabaseQueries::markAccountReadUnread(const QSqlDatabase& db, int account_ q.setForwardOnly(true); q.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;")); q.bindValue(QSL(":account_id"), account_id); - q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0); return q.exec(); } @@ -915,7 +915,7 @@ bool DatabaseQueries::storeAccountTree(const QSqlDatabase& db, RootItem* tree_ro // Iterate all children. for (RootItem* child : tree_root->getSubTree()) { - if (child->kind() == RootItemKind::Category) { + if (child->kind() == RootItem::Kind::Category) { query_category.bindValue(QSL(":parent_id"), child->parent()->id()); query_category.bindValue(QSL(":title"), child->title()); query_category.bindValue(QSL(":account_id"), account_id); @@ -928,7 +928,7 @@ bool DatabaseQueries::storeAccountTree(const QSqlDatabase& db, RootItem* tree_ro return false; } } - else if (child->kind() == RootItemKind::Feed) { + else if (child->kind() == RootItem::Kind::Feed) { Feed* feed = child->toFeed(); query_feed.bindValue(QSL(":title"), feed->title()); @@ -1400,7 +1400,7 @@ bool DatabaseQueries::editStandardFeed(const QSqlDatabase& db, int parent_id, in q.bindValue(QSL(":update_type"), int(auto_update_type)); q.bindValue(QSL(":update_interval"), auto_update_interval); - q.bindValue(QSL(":type"), feed_format); + q.bindValue(QSL(":type"), int(feed_format)); q.bindValue(QSL(":id"), feed_id); bool suc = q.exec(); diff --git a/src/librssguard/miscellaneous/databasequeries.h b/src/librssguard/miscellaneous/databasequeries.h index 28afa1dd2..6001fc813 100644 --- a/src/librssguard/miscellaneous/databasequeries.h +++ b/src/librssguard/miscellaneous/databasequeries.h @@ -183,10 +183,10 @@ inline void DatabaseQueries::fillFeedData(StandardFeed* feed, const QSqlRecord& StandardFeed::Type type = static_cast(sql_record.value(FDS_DB_TYPE_INDEX).toInt()); switch (type) { - case StandardFeed::Atom10: - case StandardFeed::Rdf: - case StandardFeed::Rss0X: - case StandardFeed::Rss2X: { + case StandardFeed::Type::Atom10: + case StandardFeed::Type::Rdf: + case StandardFeed::Type::Rss0X: + case StandardFeed::Type::Rss2X: { feed->setType(type); break; } diff --git a/src/librssguard/miscellaneous/settings.cpp b/src/librssguard/miscellaneous/settings.cpp index 758fb482e..2c37cb10a 100755 --- a/src/librssguard/miscellaneous/settings.cpp +++ b/src/librssguard/miscellaneous/settings.cpp @@ -270,7 +270,7 @@ DVALUE(QString) Downloads::TargetDirectoryDef = IOFactory::getSystemFolder(QStan DKEY Downloads::RemovePolicy = "remove_policy"; -DVALUE(int) Downloads::RemovePolicyDef = DownloadManager::Never; +DVALUE(int) Downloads::RemovePolicyDef = int(DownloadManager::RemovePolicy::Never); DKEY Downloads::TargetExplicitDirectory = "target_explicit_directory"; @@ -436,7 +436,7 @@ Settings* Settings::setupSettings(QObject* parent) { new_settings = new Settings(properties.m_absoluteSettingsFileName, QSettings::IniFormat, properties.m_type, parent); // Check if portable settings are available. - if (properties.m_type == SettingsProperties::Portable) { + if (properties.m_type == SettingsProperties::SettingsType::Portable) { qDebug("Initializing settings in '%s' (portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName))); } else { @@ -468,11 +468,11 @@ SettingsProperties Settings::determineProperties() { #endif if (will_we_use_portable_settings) { - properties.m_type = SettingsProperties::Portable; + properties.m_type = SettingsProperties::SettingsType::Portable; properties.m_baseDirectory = app_path; } else { - properties.m_type = SettingsProperties::NonPortable; + properties.m_type = SettingsProperties::SettingsType::NonPortable; properties.m_baseDirectory = home_path; } diff --git a/src/librssguard/miscellaneous/settingsproperties.h b/src/librssguard/miscellaneous/settingsproperties.h index a905363f0..f79705821 100644 --- a/src/librssguard/miscellaneous/settingsproperties.h +++ b/src/librssguard/miscellaneous/settingsproperties.h @@ -7,10 +7,11 @@ // Describes characteristics of settings. struct SettingsProperties { - enum SettingsType { + enum class SettingsType { Portable, NonPortable }; + SettingsType m_type; QString m_baseDirectory; QString m_settingsSuffix; diff --git a/src/librssguard/miscellaneous/templates.h b/src/librssguard/miscellaneous/templates.h new file mode 100755 index 000000000..323dc9d15 --- /dev/null +++ b/src/librssguard/miscellaneous/templates.h @@ -0,0 +1,4 @@ +#ifndef TEMPLATES_H +#define TEMPLATES_H + +#endif // TEMPLATES_H diff --git a/src/librssguard/network-web/adblock/adblocktreewidget.cpp b/src/librssguard/network-web/adblock/adblocktreewidget.cpp index 0ebf801a8..46882d3a9 100644 --- a/src/librssguard/network-web/adblock/adblocktreewidget.cpp +++ b/src/librssguard/network-web/adblock/adblocktreewidget.cpp @@ -30,7 +30,7 @@ AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent) : TreeWidget(parent), m_subscription(subscription), m_topItem(nullptr), m_itemChangingBlock(false) { setContextMenuPolicy(Qt::CustomContextMenu); - setDefaultItemShowMode(TreeWidget::ItemsExpanded); + setDefaultItemShowMode(TreeWidget::ItemShowMode::ItemsExpanded); setHeaderHidden(true); setAlternatingRowColors(true); setLayoutDirection(Qt::LeftToRight); diff --git a/src/librssguard/network-web/downloadmanager.cpp b/src/librssguard/network-web/downloadmanager.cpp index d5ffe04d0..0bdb04a0d 100644 --- a/src/librssguard/network-web/downloadmanager.cpp +++ b/src/librssguard/network-web/downloadmanager.cpp @@ -427,7 +427,7 @@ void DownloadItem::updateInfoAndUrlLabel() { DownloadManager::DownloadManager(QWidget* parent) : TabContent(parent), m_ui(new Ui::DownloadManager), m_autoSaver(new AutoSaver(this)), m_model(new DownloadModel(this)), - m_networkManager(new SilentNetworkAccessManager(this)), m_iconProvider(nullptr), m_removePolicy(Never) { + m_networkManager(new SilentNetworkAccessManager(this)), m_iconProvider(nullptr), m_removePolicy(RemovePolicy::Never) { m_ui->setupUi(this); m_ui->m_viewDownloads->setShowGrid(false); m_ui->m_viewDownloads->verticalHeader()->hide(); @@ -585,7 +585,7 @@ void DownloadManager::updateRow(DownloadItem* item) { // a) It is not downloading and private browsing is enabled. // OR // b) Item is already downloaded and it should be remove from downloader list. - bool remove = item->downloadedSuccessfully() && removePolicy() == DownloadManager::OnSuccessfullDownload; + bool remove = item->downloadedSuccessfully() && removePolicy() == RemovePolicy::OnSuccessfullDownload; if (remove) { m_model->removeRow(row); @@ -608,7 +608,7 @@ void DownloadManager::setRemovePolicy(RemovePolicy policy) { } void DownloadManager::save() const { - if (m_removePolicy == OnExit) { + if (m_removePolicy == RemovePolicy::OnExit) { // No saving. return; } diff --git a/src/librssguard/network-web/downloadmanager.h b/src/librssguard/network-web/downloadmanager.h index 827eb615d..4fc8b0049 100644 --- a/src/librssguard/network-web/downloadmanager.h +++ b/src/librssguard/network-web/downloadmanager.h @@ -94,7 +94,7 @@ class DownloadManager : public TabContent { friend class DownloadModel; public: - enum RemovePolicy { + enum class RemovePolicy { Never, OnExit, OnSuccessfullDownload diff --git a/src/librssguard/network-web/webpage.cpp b/src/librssguard/network-web/webpage.cpp index f7359430e..1f1120c4e 100644 --- a/src/librssguard/network-web/webpage.cpp +++ b/src/librssguard/network-web/webpage.cpp @@ -27,16 +27,16 @@ void WebPage::javaScriptAlert(const QUrl& securityOrigin, const QString& msg) { const QString& action = parts.at(1); if (action == QSL("read")) { - emit messageStatusChangeRequested(message_id, MarkRead); + emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkRead); } else if (action == QSL("unread")) { - emit messageStatusChangeRequested(message_id, MarkUnread); + emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkUnread); } else if (action == QSL("starred")) { - emit messageStatusChangeRequested(message_id, MarkStarred); + emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkStarred); } else if (action == QSL("unstarred")) { - emit messageStatusChangeRequested(message_id, MarkUnstarred); + emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkUnstarred); } else { QWebEnginePage::javaScriptAlert(securityOrigin, msg); diff --git a/src/librssguard/network-web/webpage.h b/src/librssguard/network-web/webpage.h index 1070704a0..81bf7ce66 100644 --- a/src/librssguard/network-web/webpage.h +++ b/src/librssguard/network-web/webpage.h @@ -11,7 +11,7 @@ class WebPage : public QWebEnginePage { Q_OBJECT public: - enum MessageStatusChange { + enum class MessageStatusChange { MarkRead, MarkUnread, MarkStarred, diff --git a/src/librssguard/services/abstract/accountcheckmodel.cpp b/src/librssguard/services/abstract/accountcheckmodel.cpp index f0852aafe..f84289e30 100644 --- a/src/librssguard/services/abstract/accountcheckmodel.cpp +++ b/src/librssguard/services/abstract/accountcheckmodel.cpp @@ -44,7 +44,7 @@ void AccountCheckModel::setRootItem(RootItem* root_item, bool delete_previous_ro void AccountCheckModel::checkAllItems() { if (m_rootItem != nullptr) { for (RootItem* root_child : m_rootItem->childItems()) { - if (root_child->kind() == RootItemKind::Feed || root_child->kind() == RootItemKind::Category) { + if (root_child->kind() == RootItem::Kind::Feed || root_child->kind() == RootItem::Kind::Category) { setItemChecked(root_child, Qt::Checked); } } @@ -54,7 +54,7 @@ void AccountCheckModel::checkAllItems() { void AccountCheckModel::uncheckAllItems() { if (m_rootItem != nullptr) { for (RootItem* root_child : m_rootItem->childItems()) { - if (root_child->kind() == RootItemKind::Feed || root_child->kind() == RootItemKind::Category) { + if (root_child->kind() == RootItem::Kind::Feed || root_child->kind() == RootItem::Kind::Category) { setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole); } } @@ -78,7 +78,7 @@ QModelIndex AccountCheckModel::index(int row, int column, const QModelIndex& par } QModelIndex AccountCheckModel::indexForItem(RootItem* item) const { - if (item == nullptr || item->kind() == RootItemKind::ServiceRoot || item->kind() == RootItemKind::Root) { + if (item == nullptr || item->kind() == RootItem::Kind::ServiceRoot || item->kind() == RootItem::Kind::Root) { // Root item lies on invalid index. return QModelIndex(); } @@ -107,7 +107,7 @@ QModelIndex AccountCheckModel::indexForItem(RootItem* item) const { for (int i = 0; i < row_count; i++) { RootItem* possible_category = active_item->child(i); - if (possible_category->kind() == RootItemKind::Category) { + if (possible_category->kind() == RootItem::Kind::Category) { parents << index(i, 0, active_index); } } @@ -180,10 +180,10 @@ QVariant AccountCheckModel::data(const QModelIndex& index, int role) const { } else if (role == Qt::DisplayRole) { switch (item->kind()) { - case RootItemKind::Category: + case RootItem::Kind::Category: return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(category)")); - case RootItemKind::Feed: + case RootItem::Kind::Feed: return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(feed)")); default: @@ -261,8 +261,8 @@ bool AccountCheckModel::setData(const QModelIndex& index, const QVariant& value, } Qt::ItemFlags AccountCheckModel::flags(const QModelIndex& index) const { - if (!index.isValid() || (itemForIndex(index)->kind() != RootItemKind::Kind::Category && - itemForIndex(index)->kind() != RootItemKind::Kind::Feed)) { + if (!index.isValid() || (itemForIndex(index)->kind() != RootItem::Kind::Category && + itemForIndex(index)->kind() != RootItem::Kind::Feed)) { return Qt::NoItemFlags; } diff --git a/src/librssguard/services/abstract/cacheforserviceroot.cpp b/src/librssguard/services/abstract/cacheforserviceroot.cpp index 11df5a2a5..53806f1cc 100644 --- a/src/librssguard/services/abstract/cacheforserviceroot.cpp +++ b/src/librssguard/services/abstract/cacheforserviceroot.cpp @@ -18,7 +18,9 @@ void CacheForServiceRoot::addMessageStatesToCache(const QList& ids_of_m m_cacheSaveMutex->lock(); QList& list_act = m_cachedStatesImportant[importance]; - QList& list_other = m_cachedStatesImportant[importance == RootItem::Important ? RootItem::NotImportant : RootItem::Important]; + 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); @@ -45,7 +47,9 @@ void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_mess m_cacheSaveMutex->lock(); QStringList& list_act = m_cachedStatesRead[read]; - QStringList& list_other = m_cachedStatesRead[read == RootItem::Read ? RootItem::Unread : RootItem::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); @@ -134,9 +138,11 @@ QPair, QMap cached_data_read = m_cachedStatesRead; + cached_data_read.detach(); QMap> cached_data_imp = m_cachedStatesImportant; + cached_data_imp.detach(); clearCache(); diff --git a/src/librssguard/services/abstract/category.cpp b/src/librssguard/services/abstract/category.cpp index 4a30aa4e7..a79013711 100644 --- a/src/librssguard/services/abstract/category.cpp +++ b/src/librssguard/services/abstract/category.cpp @@ -11,11 +11,11 @@ #include "services/abstract/serviceroot.h" Category::Category(RootItem* parent) : RootItem(parent) { - setKind(RootItemKind::Category); + setKind(RootItem::Kind::Category); } Category::Category(const Category& other) : RootItem(other) { - setKind(RootItemKind::Category); + setKind(RootItem::Kind::Category); } Category::Category(const QSqlRecord& record) : Category(nullptr) { @@ -38,10 +38,10 @@ void Category::updateCounts(bool including_total_count) { QList feeds; for (RootItem* child : getSubTree()) { - if (child->kind() == RootItemKind::Feed) { + if (child->kind() == RootItem::Kind::Feed) { feeds.append(child->toFeed()); } - else if (child->kind() != RootItemKind::Category && child->kind() != RootItemKind::ServiceRoot) { + else if (child->kind() != RootItem::Kind::Category && child->kind() != RootItem::Kind::ServiceRoot) { child->updateCounts(including_total_count); } } diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index 46ccc959a..d41e2c79c 100755 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -17,10 +17,10 @@ #include Feed::Feed(RootItem* parent) - : RootItem(parent), m_url(QString()), m_status(Normal), m_autoUpdateType(DefaultAutoUpdate), + : RootItem(parent), m_url(QString()), m_status(Status::Normal), m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_messageFilters(QList>()) { - setKind(RootItemKind::Feed); + setKind(RootItem::Kind::Feed); } Feed::Feed(const QSqlRecord& record) : Feed(nullptr) { @@ -43,7 +43,7 @@ Feed::Feed(const QSqlRecord& record) : Feed(nullptr) { } Feed::Feed(const Feed& other) : RootItem(other) { - setKind(RootItemKind::Feed); + setKind(RootItem::Kind::Feed); setCountOfAllMessages(other.countOfAllMessages()); setCountOfUnreadMessages(other.countOfUnreadMessages()); @@ -67,13 +67,13 @@ QVariant Feed::data(int column, int role) const { switch (role) { case Qt::ForegroundRole: switch (status()) { - case NewMessages: + case Status::NewMessages: return QColor(Qt::blue); - case NetworkError: - case ParsingError: - case AuthError: - case OtherError: + case Status::NetworkError: + case Status::ParsingError: + case Status::AuthError: + case Status::OtherError: return QColor(Qt::red); default: @@ -102,8 +102,8 @@ void Feed::setCountOfAllMessages(int count_all_messages) { } void Feed::setCountOfUnreadMessages(int count_unread_messages) { - if (status() == NewMessages && count_unread_messages < countOfUnreadMessages()) { - setStatus(Normal); + if (status() == Status::NewMessages && count_unread_messages < countOfUnreadMessages()) { + setStatus(Status::Normal); } m_unreadCount = count_unread_messages; @@ -209,7 +209,7 @@ int Feed::updateMessages(const QList& messages, bool error_during_obtai } if (ok) { - setStatus(updated_messages > 0 ? NewMessages : Normal); + setStatus(updated_messages > 0 ? Status::NewMessages : Status::Normal); updateCounts(true); if (getParentServiceRoot()->recycleBin() != nullptr && anything_updated) { @@ -238,13 +238,13 @@ QString Feed::getAutoUpdateStatusDescription() const { QString auto_update_string; switch (autoUpdateType()) { - case DontAutoUpdate: + case AutoUpdateType::DontAutoUpdate: //: Describes feed auto-update status. auto_update_string = tr("does not use auto-update"); break; - case DefaultAutoUpdate: + case AutoUpdateType::DefaultAutoUpdate: //: Describes feed auto-update status. auto_update_string = qApp->feedReader()->autoUpdateEnabled() @@ -254,7 +254,7 @@ QString Feed::getAutoUpdateStatusDescription() const { : tr("uses global settings (global feed auto-updating is disabled)"); break; - case SpecificAutoUpdate: + case AutoUpdateType::SpecificAutoUpdate: default: //: Describes feed auto-update status. diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index dffef60c7..1014ef85c 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -18,7 +18,7 @@ class Feed : public RootItem { public: // Specifies the auto-update strategy for the feed. - enum AutoUpdateType { + enum class AutoUpdateType { DontAutoUpdate = 0, DefaultAutoUpdate = 1, SpecificAutoUpdate = 2 @@ -27,7 +27,7 @@ class Feed : public RootItem { // Specifies the actual "status" of the feed. // For example if it has new messages, error // occurred, and so on. - enum Status { + enum class Status { Normal = 0, NewMessages = 1, NetworkError = 2, diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.cpp b/src/librssguard/services/abstract/gui/formfeeddetails.cpp index bbcd4adae..b55a6fb8e 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.cpp +++ b/src/librssguard/services/abstract/gui/formfeeddetails.cpp @@ -59,10 +59,10 @@ int FormFeedDetails::addEditFeed(Feed* input_feed, RootItem* parent_to_select, c } if (parent_to_select != nullptr) { - if (parent_to_select->kind() == RootItemKind::Category) { + if (parent_to_select->kind() == RootItem::Kind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItemKind::Feed) { + else if (parent_to_select->kind() == RootItem::Kind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { @@ -153,8 +153,8 @@ void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) { Feed::AutoUpdateType auto_update_type = static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt()); switch (auto_update_type) { - case Feed::DontAutoUpdate: - case Feed::DefaultAutoUpdate: + case Feed::AutoUpdateType::DontAutoUpdate: + case Feed::AutoUpdateType::DefaultAutoUpdate: m_ui->m_spinAutoUpdateInterval->setEnabled(false); break; @@ -315,10 +315,10 @@ void FormFeedDetails::initialize() { m_ui->m_txtPassword->lineEdit()->setToolTip(tr("Set password to access the feed.")); // Add standard feed types. - m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Atom10), QVariant::fromValue((int) StandardFeed::Atom10)); - m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rdf), QVariant::fromValue((int) StandardFeed::Rdf)); - m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss0X), QVariant::fromValue((int) StandardFeed::Rss0X)); - m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss2X), QVariant::fromValue((int) StandardFeed::Rss2X)); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Atom10), QVariant::fromValue(int(StandardFeed::Type::Atom10))); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rdf), QVariant::fromValue(int(StandardFeed::Type::Rdf))); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rss0X), QVariant::fromValue(int(StandardFeed::Type::Rss0X))); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rss2X), QVariant::fromValue(int(StandardFeed::Type::Rss2X))); // Load available encodings. const QList encodings = QTextCodec::availableCodecs(); @@ -358,9 +358,12 @@ void FormFeedDetails::initialize() { // Setup auto-update options. m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL); - m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) Feed::DefaultAutoUpdate)); - m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), QVariant::fromValue((int) Feed::SpecificAutoUpdate)); - m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), QVariant::fromValue((int) Feed::DontAutoUpdate)); + m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), + QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate))); + m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), + QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate))); + m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), + QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate))); // Set tab order. setTabOrder(m_ui->m_cmbParentCategory, m_ui->m_cmbType); diff --git a/src/librssguard/services/abstract/importantnode.cpp b/src/librssguard/services/abstract/importantnode.cpp index 85fec863b..4ba20c0bb 100755 --- a/src/librssguard/services/abstract/importantnode.cpp +++ b/src/librssguard/services/abstract/importantnode.cpp @@ -11,7 +11,7 @@ #include ImportantNode::ImportantNode(RootItem* parent_item) : RootItem(parent_item) { - setKind(RootItemKind::Important); + setKind(RootItem::Kind::Important); setId(ID_IMPORTANT); setIcon(qApp->icons()->fromTheme(QSL("mail-mark-important"))); setTitle(tr("Important messages")); @@ -67,7 +67,7 @@ bool ImportantNode::markAsReadUnread(RootItem::ReadStatus status) { if (DatabaseQueries::markImportantMessagesReadUnread(database, service->accountId(), status)) { service->updateCounts(true); service->itemChanged(getSubTree()); - service->requestReloadMessageList(status == RootItem::Read); + service->requestReloadMessageList(status == RootItem::ReadStatus::Read); return true; } else { diff --git a/src/librssguard/services/abstract/recyclebin.cpp b/src/librssguard/services/abstract/recyclebin.cpp index 5268d2f7e..25403e1fc 100644 --- a/src/librssguard/services/abstract/recyclebin.cpp +++ b/src/librssguard/services/abstract/recyclebin.cpp @@ -13,7 +13,7 @@ RecycleBin::RecycleBin(RootItem* parent_item) : RootItem(parent_item), m_totalCount(0), m_unreadCount(0) { - setKind(RootItemKind::Bin); + setKind(RootItem::Kind::Bin); setId(ID_RECYCLE_BIN); setIcon(qApp->icons()->fromTheme(QSL("user-trash"))); setTitle(tr("Recycle bin")); @@ -84,7 +84,7 @@ bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { if (DatabaseQueries::markBinReadUnread(database, parent_root->accountId(), status)) { updateCounts(false); parent_root->itemChanged(QList() << this); - parent_root->requestReloadMessageList(status == RootItem::Read); + parent_root->requestReloadMessageList(status == RootItem::ReadStatus::Read); return true; } else { diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp index b6ad95294..74e05e6a4 100644 --- a/src/librssguard/services/abstract/rootitem.cpp +++ b/src/librssguard/services/abstract/rootitem.cpp @@ -2,6 +2,7 @@ #include "services/abstract/rootitem.h" +#include "3rd-party/boolinq/boolinq.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "services/abstract/category.h" @@ -12,7 +13,7 @@ #include RootItem::RootItem(RootItem* parent_item) - : QObject(nullptr), m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_customId(QL1S("")), + : QObject(nullptr), m_kind(RootItem::Kind::Root), m_id(NO_PARENT_CATEGORY), m_customId(QL1S("")), m_title(QString()), m_description(QString()), m_keepOnTop(false), m_parentItem(parent_item) {} RootItem::RootItem(const RootItem& other) : RootItem(nullptr) { @@ -36,7 +37,7 @@ QString RootItem::hashCode() const { return QString::number(acc_id) + QL1S("-") + - QString::number(kind()) + QL1S("-") + + QString::number(int(kind())) + QL1S("-") + QString::number(id()); } @@ -88,7 +89,7 @@ bool RootItem::cleanMessages(bool clear_only_read) { bool result = true; for (RootItem* child : m_childItems) { - if (child->kind() != RootItemKind::Bin) { + if (child->kind() != RootItem::Kind::Bin) { result &= child->cleanMessages(clear_only_read); } } @@ -173,10 +174,10 @@ QVariant RootItem::data(int column, int role) const { QIcon ico = icon(); if (ico.isNull()) { - if (kind() == RootItemKind::Feed) { + if (kind() == RootItem::Kind::Feed) { return qApp->icons()->fromTheme(QSL("application-rss+xml")); } - else if (kind() == RootItemKind::Category) { + else if (kind() == RootItem::Kind::Category) { return qApp->icons()->fromTheme(QSL("folder")); } } @@ -210,27 +211,15 @@ bool RootItem::performDragDropChange(RootItem* target_item) { } int RootItem::countOfUnreadMessages() const { - int total_count = 0; - - for (RootItem* child_item : m_childItems) { - if (child_item->kind() != RootItemKind::Kind::Important) { - total_count += child_item->countOfUnreadMessages(); - } - } - - return total_count; + return boolinq::from(m_childItems).sum([](RootItem* it) { + return it->kind() == RootItem::Kind::Important ? 0 : it->countOfUnreadMessages(); + }); } int RootItem::countOfAllMessages() const { - int total_count = 0; - - for (RootItem* child_item : m_childItems) { - if (child_item->kind() != RootItemKind::Kind::Important) { - total_count += child_item->countOfAllMessages(); - } - } - - return total_count; + return boolinq::from(m_childItems).sum([](RootItem* it) { + return it->kind() == RootItem::Kind::Important ? 0 : it->countOfAllMessages(); + }); } bool RootItem::isChildOf(const RootItem* root) const { @@ -240,7 +229,7 @@ bool RootItem::isChildOf(const RootItem* root) const { const RootItem* this_item = this; - while (this_item->kind() != RootItemKind::Root) { + while (this_item->kind() != RootItem::Kind::Root) { if (root->childItems().contains(const_cast(this_item))) { return true; } @@ -278,7 +267,7 @@ QList RootItem::getSubTree() const { return children; } -QList RootItem::getSubTree(RootItemKind::Kind kind_of_item) const { +QList RootItem::getSubTree(RootItem::Kind kind_of_item) const { QList children; QList traversable_items; @@ -288,7 +277,7 @@ QList RootItem::getSubTree(RootItemKind::Kind kind_of_item) const { while (!traversable_items.isEmpty()) { RootItem* active_item = traversable_items.takeFirst(); - if ((active_item->kind() & kind_of_item) > 0) { + if (int(active_item->kind() & kind_of_item) > 0) { children.append(active_item); } @@ -308,7 +297,7 @@ QList RootItem::getSubTreeCategories() const { while (!traversable_items.isEmpty()) { RootItem* active_item = traversable_items.takeFirst(); - if (active_item->kind() == RootItemKind::Category) { + if (active_item->kind() == RootItem::Kind::Category) { children.append(active_item->toCategory()); } @@ -328,7 +317,7 @@ QHash RootItem::getHashedSubTreeCategories() const { while (!traversable_items.isEmpty()) { RootItem* active_item = traversable_items.takeFirst(); - if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) { + if (active_item->kind() == RootItem::Kind::Category && !children.contains(active_item->id())) { children.insert(active_item->id(), active_item->toCategory()); } @@ -348,7 +337,7 @@ QHash RootItem::getHashedSubTreeFeeds() const { while (!traversable_items.isEmpty()) { RootItem* active_item = traversable_items.takeFirst(); - if (active_item->kind() == RootItemKind::Feed && !children.contains(active_item->customId())) { + if (active_item->kind() == RootItem::Kind::Feed && !children.contains(active_item->customId())) { children.insert(active_item->customId(), active_item->toFeed()); } @@ -368,7 +357,7 @@ QList RootItem::getSubTreeFeeds() const { while (!traversable_items.isEmpty()) { RootItem* active_item = traversable_items.takeFirst(); - if (active_item->kind() == RootItemKind::Feed) { + if (active_item->kind() == RootItem::Kind::Feed) { children.append(active_item->toFeed()); } @@ -381,8 +370,8 @@ QList RootItem::getSubTreeFeeds() const { ServiceRoot* RootItem::getParentServiceRoot() const { const RootItem* working_parent = this; - while (working_parent->kind() != RootItemKind::Root) { - if (working_parent->kind() == RootItemKind::ServiceRoot) { + while (working_parent->kind() != RootItem::Kind::Root) { + if (working_parent->kind() == RootItem::Kind::ServiceRoot) { return working_parent->toServiceRoot(); } else { @@ -393,11 +382,11 @@ ServiceRoot* RootItem::getParentServiceRoot() const { return nullptr; } -RootItemKind::Kind RootItem::kind() const { +RootItem::Kind RootItem::kind() const { return m_kind; } -void RootItem::setKind(RootItemKind::Kind kind) { +void RootItem::setKind(RootItem::Kind kind) { m_kind = kind; } @@ -518,3 +507,11 @@ QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj) { return out; } + +RootItem::Kind operator|(RootItem::Kind a, RootItem::Kind b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +RootItem::Kind operator&(RootItem::Kind a, RootItem::Kind b) { + return static_cast(static_cast(a) & static_cast(b)); +} diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h index 1020c097c..f3392161a 100644 --- a/src/librssguard/services/abstract/rootitem.h +++ b/src/librssguard/services/abstract/rootitem.h @@ -14,24 +14,6 @@ class Feed; class ServiceRoot; class QAction; -namespace RootItemKind { - // Describes the kind of the item. - enum Kind { - Root = 1, - Bin = 2, - Feed = 4, - Category = 8, - ServiceRoot = 16, - Labels = 32, - Important = 64 - }; - - inline Kind operator|(Kind a, Kind b) { - return static_cast(static_cast(a) | static_cast(b)); - } - -} - // Represents ROOT item of FeedsModel. // NOTE: This class is derived to add functionality for // all other non-root items of FeedsModel. @@ -39,18 +21,29 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { Q_OBJECT public: - enum ReadStatus { + enum class ReadStatus { Unread = 0, Read = 1 }; // Holds statuses for messages // to be switched importance (starred). - enum Importance { + enum class Importance { NotImportant = 0, Important = 1 }; + // Describes the kind of the item. + enum class Kind { + Root = 1, + Bin = 2, + Feed = 4, + Category = 8, + ServiceRoot = 16, + Labels = 32, + Important = 64 + }; + // Constructors and destructors. explicit RootItem(RootItem* parent_item = nullptr); explicit RootItem(const RootItem& other); @@ -159,7 +152,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { // Returns flat list of all items from subtree where this item is a root. // Returned list includes this item too. QList getSubTree() const; - QList getSubTree(RootItemKind::Kind kind_of_item) const; + QList getSubTree(RootItem::Kind kind_of_item) const; QList getSubTreeCategories() const; // Returns list of categories complemented by their own integer primary ID. @@ -172,8 +165,8 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { // Returns the service root node which is direct or indirect parent of current item. ServiceRoot* getParentServiceRoot() const; - RootItemKind::Kind kind() const; - void setKind(RootItemKind::Kind kind); + RootItem::Kind kind() const; + void setKind(RootItem::Kind kind); // Each item can have icon. QIcon icon() const; @@ -208,7 +201,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { void setKeepOnTop(bool keep_on_top); private: - RootItemKind::Kind m_kind; + RootItem::Kind m_kind; int m_id; QString m_customId; QString m_title; @@ -220,6 +213,9 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { RootItem* m_parentItem; }; +RootItem::Kind operator|(RootItem::Kind a, RootItem::Kind b); +RootItem::Kind operator&(RootItem::Kind a, RootItem::Kind b); + QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj); QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj); QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj); diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index 61c52919e..6fd3d5db4 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -16,7 +16,7 @@ ServiceRoot::ServiceRoot(RootItem* parent) : RootItem(parent), m_recycleBin(new RecycleBin(this)), m_importantNode(new ImportantNode(this)), m_accountId(NO_PARENT_CATEGORY) { - setKind(RootItemKind::ServiceRoot); + setKind(RootItem::Kind::ServiceRoot); setCreationDate(QDateTime::currentDateTime()); } @@ -47,7 +47,7 @@ bool ServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { if (DatabaseQueries::markAccountReadUnread(database, accountId(), status)) { updateCounts(false); itemChanged(getSubTree()); - requestReloadMessageList(status == RootItem::Read); + requestReloadMessageList(status == RootItem::ReadStatus::Read); return true; } else { @@ -101,10 +101,10 @@ void ServiceRoot::updateCounts(bool including_total_count) { QList feeds; for (RootItem* child : getSubTree()) { - if (child->kind() == RootItemKind::Feed) { + if (child->kind() == RootItem::Kind::Feed) { feeds.append(child->toFeed()); } - else if (child->kind() != RootItemKind::Category && child->kind() != RootItemKind::ServiceRoot) { + else if (child->kind() != RootItem::Kind::Category && child->kind() != RootItem::Kind::ServiceRoot) { child->updateCounts(including_total_count); } } @@ -154,7 +154,7 @@ void ServiceRoot::removeOldAccountFromDatabase(bool including_messages) { void ServiceRoot::cleanAllItemsFromModel() { for (RootItem* top_level_item : childItems()) { - if (top_level_item->kind() != RootItemKind::Bin && top_level_item->kind() != RootItemKind::Important) { + if (top_level_item->kind() != RootItem::Kind::Bin && top_level_item->kind() != RootItem::Kind::Important) { requestItemRemoval(top_level_item); } } @@ -279,7 +279,7 @@ QMap ServiceRoot::storeCustomFeedsData() { QVariantMap feed_custom_data; feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInitialInterval()); - feed_custom_data.insert(QSL("auto_update_type"), feed->autoUpdateType()); + feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType())); feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters())); custom_data.insert(feed->customId(), feed_custom_data); } @@ -366,7 +366,7 @@ QStringList ServiceRoot::customIDSOfMessagesForItem(RootItem* item) { QStringList list; switch (item->kind()) { - case RootItemKind::Category: { + case RootItem::Kind::Category: { for (RootItem* child : item->childItems()) { list.append(customIDSOfMessagesForItem(child)); } @@ -374,28 +374,28 @@ QStringList ServiceRoot::customIDSOfMessagesForItem(RootItem* item) { return list; } - case RootItemKind::ServiceRoot: { + case RootItem::Kind::ServiceRoot: { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); list = DatabaseQueries::customIdsOfMessagesFromAccount(database, accountId()); break; } - case RootItemKind::Bin: { + case RootItem::Kind::Bin: { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); list = DatabaseQueries::customIdsOfMessagesFromBin(database, accountId()); break; } - case RootItemKind::Feed: { + case RootItem::Kind::Feed: { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); list = DatabaseQueries::customIdsOfMessagesFromFeed(database, item->customId(), accountId()); break; } - case RootItemKind::Important: { + case RootItem::Kind::Important: { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); list = DatabaseQueries::customIdsOfImportantMessages(database, accountId()); @@ -430,7 +430,7 @@ bool ServiceRoot::markFeedsReadUnread(QList items, RootItem::ReadStatus r } itemChanged(itemss); - requestReloadMessageList(read == RootItem::Read); + requestReloadMessageList(read == RootItem::ReadStatus::Read); return true; } else { @@ -491,11 +491,11 @@ void ServiceRoot::setAccountId(int account_id) { } bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) { - if (item->kind() == RootItemKind::Bin) { + if (item->kind() == RootItem::Kind::Bin) { model->setFilter(QString("Messages.is_deleted = 1 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1") .arg(QString::number(accountId()))); } - else if (item->kind() == RootItemKind::Kind::Important) { + else if (item->kind() == RootItem::Kind::Important) { model->setFilter(QString("Messages.is_important = 1 AND Messages.is_deleted = 0 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1") .arg(QString::number(accountId()))); } @@ -569,7 +569,7 @@ bool ServiceRoot::onBeforeSwitchMessageImportance(RootItem* selected_item, const QList mark_unstarred_msgs; for (const ImportanceChange& pair : changes) { - if (pair.second == RootItem::Important) { + if (pair.second == RootItem::Importance::Important) { mark_starred_msgs.append(pair.first); } else { @@ -578,11 +578,11 @@ bool ServiceRoot::onBeforeSwitchMessageImportance(RootItem* selected_item, const } if (!mark_starred_msgs.isEmpty()) { - cache->addMessageStatesToCache(mark_starred_msgs, RootItem::Important); + cache->addMessageStatesToCache(mark_starred_msgs, RootItem::Importance::Important); } if (!mark_unstarred_msgs.isEmpty()) { - cache->addMessageStatesToCache(mark_unstarred_msgs, RootItem::NotImportant); + cache->addMessageStatesToCache(mark_unstarred_msgs, RootItem::Importance::NotImportant); } } diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index 0065d9d4e..58519bd6a 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -146,10 +146,6 @@ void FormAddEditEmail::addRecipientRow(const QString& recipient) { m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec); } -void FormAddEditEmail::closeEvent(QCloseEvent* event) { - // event->ignore(); -} - QList FormAddEditEmail::recipientControls() const { QList list; diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.h b/src/librssguard/services/gmail/gui/formaddeditemail.h index bc641c631..a1985d9e8 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.h +++ b/src/librssguard/services/gmail/gui/formaddeditemail.h @@ -31,7 +31,6 @@ class FormAddEditEmail : public QDialog { void addRecipientRow(const QString& recipient = QString()); private: - void closeEvent(QCloseEvent* event); QList recipientControls() const; private: diff --git a/src/librssguard/services/owncloud/gui/formowncloudfeeddetails.cpp b/src/librssguard/services/owncloud/gui/formowncloudfeeddetails.cpp index da95a2aee..5a1931135 100644 --- a/src/librssguard/services/owncloud/gui/formowncloudfeeddetails.cpp +++ b/src/librssguard/services/owncloud/gui/formowncloudfeeddetails.cpp @@ -52,7 +52,7 @@ void FormOwnCloudFeedDetails::apply() { else { const RootItem* parent = static_cast(m_ui->m_cmbParentCategory->itemData( m_ui->m_cmbParentCategory->currentIndex()).value()); - const int category_id = parent->kind() == RootItemKind::ServiceRoot ? 0 : parent->customId().toInt(); + const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customId().toInt(); const bool response = qobject_cast(m_serviceRoot)->network()->createFeed(m_ui->m_txtUrl->lineEdit()->text(), category_id); diff --git a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp index eaf927f26..cf56264dd 100644 --- a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp +++ b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp @@ -331,7 +331,7 @@ void OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const QJsonArray ids; QString final_url; - if (status == RootItem::Read) { + if (status == RootItem::ReadStatus::Read) { final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/read/multiple"; } else { @@ -377,7 +377,7 @@ void OwnCloudNetworkFactory::markMessagesStarred(RootItem::Importance importance QJsonArray ids; QString final_url; - if (importance == RootItem::Important) { + if (importance == RootItem::Importance::Important) { final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/star/multiple"; } else { diff --git a/src/librssguard/services/owncloud/owncloudfeed.cpp b/src/librssguard/services/owncloud/owncloudfeed.cpp index 7a9ba9ffe..d94e5c257 100644 --- a/src/librssguard/services/owncloud/owncloudfeed.cpp +++ b/src/librssguard/services/owncloud/owncloudfeed.cpp @@ -70,8 +70,8 @@ OwnCloudServiceRoot* OwnCloudFeed::serviceRoot() const { QList OwnCloudFeed::obtainNewMessages(bool* error_during_obtaining) { OwnCloudGetMessagesResponse messages = serviceRoot()->network()->getMessages(customNumericId()); - if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) { - setStatus(Feed::NetworkError); + if (serviceRoot()->network()->lastError() != QNetworkReply::NetworkError::NoError) { + setStatus(Feed::Status::NetworkError); *error_during_obtaining = true; serviceRoot()->itemChanged(QList() << this); return QList(); diff --git a/src/librssguard/services/standard/gui/formstandardcategorydetails.cpp b/src/librssguard/services/standard/gui/formstandardcategorydetails.cpp index cb96753b0..c83ebd477 100644 --- a/src/librssguard/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/librssguard/services/standard/gui/formstandardcategorydetails.cpp @@ -70,10 +70,10 @@ int FormStandardCategoryDetails::addEditCategory(StandardCategory* input_categor // Load parent from suggested item. if (parent_to_select != nullptr) { - if (parent_to_select->kind() == RootItemKind::Category) { + if (parent_to_select->kind() == RootItem::Kind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItemKind::Feed) { + else if (parent_to_select->kind() == RootItem::Kind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { diff --git a/src/librssguard/services/standard/gui/formstandardimportexport.cpp b/src/librssguard/services/standard/gui/formstandardimportexport.cpp index 094ea04a3..d7b0f258b 100644 --- a/src/librssguard/services/standard/gui/formstandardimportexport.cpp +++ b/src/librssguard/services/standard/gui/formstandardimportexport.cpp @@ -143,14 +143,14 @@ void FormStandardImportExport::selectExportFile() { if (!selected_file.isEmpty()) { if (selected_filter == filter_opml20) { - m_conversionType = OPML20; + m_conversionType = ConversionType::OPML20; if (!selected_file.endsWith(QL1S(".opml"))) { selected_file += QL1S(".opml"); } } else if (selected_filter == filter_txt_url_per_line) { - m_conversionType = TXTUrlPerLine; + m_conversionType = ConversionType::TxtUrlPerLine; if (!selected_file.endsWith(QL1S(".txt"))) { selected_file += QL1S(".txt"); @@ -178,10 +178,10 @@ void FormStandardImportExport::selectImportFile() { if (!selected_file.isEmpty()) { if (selected_filter == filter_opml20) { - m_conversionType = OPML20; + m_conversionType = ConversionType::OPML20; } else if (selected_filter == filter_txt_url_per_line) { - m_conversionType = TXTUrlPerLine; + m_conversionType = ConversionType::TxtUrlPerLine; } m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::StatusType::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); @@ -213,11 +213,11 @@ void FormStandardImportExport::parseImportFile(const QString& file_name, bool fe } switch (m_conversionType) { - case OPML20: + case ConversionType::OPML20: m_model->importAsOPML20(input_data, fetch_metadata_online); break; - case TXTUrlPerLine: + case ConversionType::TxtUrlPerLine: m_model->importAsTxtURLPerLine(input_data, fetch_metadata_online); break; @@ -246,11 +246,11 @@ void FormStandardImportExport::exportFeeds() { bool result_export = false; switch (m_conversionType) { - case OPML20: + case ConversionType::OPML20: result_export = m_model->exportToOMPL20(result_data); break; - case TXTUrlPerLine: + case ConversionType::TxtUrlPerLine: result_export = m_model->exportToTxtURLPerLine(result_data); break; diff --git a/src/librssguard/services/standard/gui/formstandardimportexport.h b/src/librssguard/services/standard/gui/formstandardimportexport.h index 6d2df56ae..fe83e9d89 100644 --- a/src/librssguard/services/standard/gui/formstandardimportexport.h +++ b/src/librssguard/services/standard/gui/formstandardimportexport.h @@ -19,9 +19,9 @@ class FormStandardImportExport : public QDialog { Q_OBJECT public: - enum ConversionType { + enum class ConversionType { OPML20 = 0, - TXTUrlPerLine = 1 + TxtUrlPerLine = 1 }; // Constructors. diff --git a/src/librssguard/services/standard/standardcategory.cpp b/src/librssguard/services/standard/standardcategory.cpp index 1f96fcffb..3356ccf2a 100644 --- a/src/librssguard/services/standard/standardcategory.cpp +++ b/src/librssguard/services/standard/standardcategory.cpp @@ -73,10 +73,10 @@ bool StandardCategory::removeItself() { // Remove all child items (feeds and categories) // from the database. for (RootItem* child : childItems()) { - if (child->kind() == RootItemKind::Category) { + if (child->kind() == RootItem::Kind::Category) { children_removed &= dynamic_cast(child)->removeItself(); } - else if (child->kind() == RootItemKind::Feed) { + else if (child->kind() == RootItem::Kind::Feed) { children_removed &= dynamic_cast(child)->removeItself(); } } diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index 70de02350..0cdefcc61 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -33,7 +33,7 @@ StandardFeed::StandardFeed(RootItem* parent_item) m_username = QString(); m_password = QString(); m_networkError = QNetworkReply::NoError; - m_type = Rss0X; + m_type = Type::Rss0X; m_encoding = QString(); } @@ -94,16 +94,16 @@ bool StandardFeed::deleteViaGui() { QString StandardFeed::typeToString(StandardFeed::Type type) { switch (type) { - case Atom10: + case Type::Atom10: return QSL("ATOM 1.0"); - case Rdf: + case Type::Rdf: return QSL("RDF (RSS 1.0)"); - case Rss0X: + case Type::Rss0X: return QSL("RSS 0.91/0.92/0.93"); - case Rss2X: + case Type::Rss2X: default: return QSL("RSS 2.0/2.0.1"); } @@ -218,7 +218,7 @@ QPair StandardFeed::guessFeed(const // We found RDF feed. QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement(); - result.first->setType(Rdf); + result.first->setType(Type::Rdf); result.first->setTitle(channel_element.namedItem(QSL("title")).toElement().text()); result.first->setDescription(channel_element.namedItem(QSL("description")).toElement().text()); QString source_link = channel_element.namedItem(QSL("link")).toElement().text(); @@ -232,10 +232,10 @@ QPair StandardFeed::guessFeed(const QString rss_type = root_element.attribute("version", "2.0"); if (rss_type == QL1S("0.91") || rss_type == QL1S("0.92") || rss_type == QL1S("0.93")) { - result.first->setType(Rss0X); + result.first->setType(Type::Rss0X); } else { - result.first->setType(Rss2X); + result.first->setType(Type::Rss2X); } QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement(); @@ -250,7 +250,7 @@ QPair StandardFeed::guessFeed(const } else if (root_tag_name == QL1S("feed")) { // We found ATOM feed. - result.first->setType(Atom10); + result.first->setType(Type::Atom10); result.first->setTitle(root_element.namedItem(QSL("title")).toElement().text()); result.first->setDescription(root_element.namedItem(QSL("subtitle")).toElement().text()); QString source_link = root_element.namedItem(QSL("link")).toElement().text(); @@ -415,7 +415,7 @@ QList StandardFeed::obtainNewMessages(bool* error_during_obtaining) { if (m_networkError != QNetworkReply::NoError) { qWarning("Error during fetching of new messages for feed '%s' (id %d).", qPrintable(url()), id()); - setStatus(NetworkError); + setStatus(Status::NetworkError); *error_during_obtaining = true; return QList(); } @@ -441,16 +441,16 @@ QList StandardFeed::obtainNewMessages(bool* error_during_obtaining) { QList messages; switch (type()) { - case StandardFeed::Rss0X: - case StandardFeed::Rss2X: + case StandardFeed::Type::Rss0X: + case StandardFeed::Type::Rss2X: messages = RssParser(formatted_feed_contents).messages(); break; - case StandardFeed::Rdf: + case StandardFeed::Type::Rdf: messages = RdfParser().parseXmlData(formatted_feed_contents); break; - case StandardFeed::Atom10: + case StandardFeed::Type::Atom10: messages = AtomParser(formatted_feed_contents).messages(); default: diff --git a/src/librssguard/services/standard/standardfeed.h b/src/librssguard/services/standard/standardfeed.h index 186d29b86..d60a4ed6a 100644 --- a/src/librssguard/services/standard/standardfeed.h +++ b/src/librssguard/services/standard/standardfeed.h @@ -20,7 +20,7 @@ class StandardFeed : public Feed { Q_OBJECT public: - enum Type { + enum class Type { Rss0X = 0, Rss2X = 1, Rdf = 2, // Sometimes denoted as RSS 1.0. diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp index 3f73891cb..b7b31a37b 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp @@ -70,7 +70,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { } switch (child_item->kind()) { - case RootItemKind::Category: { + case RootItem::Kind::Category: { QDomElement outline_category = opml_document.createElement(QSL("outline")); outline_category.setAttribute(QSL("text"), child_item->title()); @@ -82,7 +82,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { break; } - case RootItemKind::Feed: { + case RootItem::Kind::Feed: { auto* child_feed = dynamic_cast(child_item); QDomElement outline_feed = opml_document.createElement("outline"); @@ -95,16 +95,16 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { outline_feed.setAttribute(QSL("rssguard:icon"), QString(qApp->icons()->toByteArray(child_feed->icon()))); switch (child_feed->type()) { - case StandardFeed::Rss0X: - case StandardFeed::Rss2X: + case StandardFeed::Type::Rss0X: + case StandardFeed::Type::Rss2X: outline_feed.setAttribute(QSL("version"), QSL("RSS")); break; - case StandardFeed::Rdf: + case StandardFeed::Type::Rdf: outline_feed.setAttribute(QSL("version"), QSL("RSS1")); break; - case StandardFeed::Atom10: + case StandardFeed::Type::Atom10: outline_feed.setAttribute(QSL("version"), QSL("ATOM")); break; @@ -200,13 +200,13 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m new_feed->setIcon(feed_icon); if (feed_type == QL1S("RSS1")) { - new_feed->setType(StandardFeed::Rdf); + new_feed->setType(StandardFeed::Type::Rdf); } else if (feed_type == QL1S("ATOM")) { - new_feed->setType(StandardFeed::Atom10); + new_feed->setType(StandardFeed::Type::Atom10); } else { - new_feed->setType(StandardFeed::Rss2X); + new_feed->setType(StandardFeed::Type::Rss2X); } active_model_item->appendChild(new_feed); diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp index 0b19ae0bd..1865f730b 100644 --- a/src/librssguard/services/standard/standardserviceroot.cpp +++ b/src/librssguard/services/standard/standardserviceroot.cpp @@ -40,7 +40,7 @@ StandardServiceRoot::~StandardServiceRoot() { void StandardServiceRoot::start(bool freshly_activated) { loadFromDatabase(); - if (freshly_activated && getSubTree(RootItemKind::Feed).isEmpty()) { + if (freshly_activated && getSubTree(RootItem::Kind::Feed).isEmpty()) { // In other words, if there are no feeds or categories added. if (MessageBox::show(qApp->mainFormWidget(), QMessageBox::Question, QObject::tr("Load initial set of feeds"), tr("This new account does not include any feeds. You can now add default set of feeds."), @@ -211,7 +211,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, continue; } - if (source_item->kind() == RootItemKind::Category) { + if (source_item->kind() == RootItem::Kind::Category) { auto* source_category = dynamic_cast(source_item); auto* new_category = new StandardCategory(*source_category); QString new_category_title = new_category->title(); @@ -235,7 +235,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, RootItem* existing_category = nullptr; for (RootItem* child : target_parent->childItems()) { - if (child->kind() == RootItemKind::Category && child->title() == new_category_title) { + if (child->kind() == RootItem::Kind::Category && child->title() == new_category_title) { existing_category = child; } } @@ -249,7 +249,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, } } } - else if (source_item->kind() == RootItemKind::Feed) { + else if (source_item->kind() == RootItem::Kind::Feed) { auto* source_feed = dynamic_cast(source_item); auto* new_feed = new StandardFeed(*source_feed); diff --git a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp b/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp index fd7c1cb9c..8f5c01011 100644 --- a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp +++ b/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp @@ -37,7 +37,7 @@ void FormTtRssFeedDetails::apply() { RootItem* parent = static_cast(m_ui->m_cmbParentCategory->itemData( m_ui->m_cmbParentCategory->currentIndex()).value()); auto* root = qobject_cast(parent->getParentServiceRoot()); - const int category_id = parent->kind() == RootItemKind::ServiceRoot ? + const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customId().toInt(); const TtRssSubscribeToFeedResponse response = root->network()->subscribeToFeed(m_ui->m_txtUrl->lineEdit()->text(), diff --git a/src/librssguard/services/tt-rss/network/ttrssnetworkfactory.h b/src/librssguard/services/tt-rss/network/ttrssnetworkfactory.h index 154074da1..90419b88e 100644 --- a/src/librssguard/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/librssguard/services/tt-rss/network/ttrssnetworkfactory.h @@ -86,12 +86,12 @@ class TtRssUnsubscribeFeedResponse : public TtRssResponse { }; namespace UpdateArticle { - enum Mode { + enum class Mode { SetToFalse = 0, SetToTrue = 1, Togggle = 2 }; - enum OperatingField { + enum class OperatingField { Starred = 0, Published = 1, Unread = 2 diff --git a/src/librssguard/services/tt-rss/ttrssfeed.cpp b/src/librssguard/services/tt-rss/ttrssfeed.cpp index a273cbf60..f90bc2c24 100644 --- a/src/librssguard/services/tt-rss/ttrssfeed.cpp +++ b/src/librssguard/services/tt-rss/ttrssfeed.cpp @@ -79,7 +79,7 @@ QList TtRssFeed::obtainNewMessages(bool* error_during_obtaining) { serviceRoot()->network()->downloadOnlyUnreadMessages()); if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) { - setStatus(Feed::NetworkError); + setStatus(Feed::Status::NetworkError); *error_during_obtaining = true; serviceRoot()->itemChanged(QList() << this); return QList(); diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp index 12d57a16d..4cfb85616 100644 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp +++ b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp @@ -127,8 +127,10 @@ void TtRssServiceRoot::saveAllCachedData(bool async) { if (!ids.isEmpty()) { network()->updateArticles(ids, - UpdateArticle::Unread, - key == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse, + UpdateArticle::OperatingField::Unread, + key == RootItem::ReadStatus::Unread + ? UpdateArticle::Mode::SetToTrue + : UpdateArticle::Mode::SetToFalse, async); } } @@ -145,8 +147,10 @@ void TtRssServiceRoot::saveAllCachedData(bool async) { QStringList ids = customIDsOfMessages(messages); network()->updateArticles(ids, - UpdateArticle::Starred, - key == RootItem::Important ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse, + UpdateArticle::OperatingField::Starred, + key == RootItem::Importance::Important + ? UpdateArticle::Mode::SetToTrue + : UpdateArticle::Mode::SetToFalse, async); } } From 0d1ef7cd8886fa3c8336d0408e90cc921aa1aa31 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 31 Jul 2020 12:11:30 +0200 Subject: [PATCH 6/6] Fix #256 - some files were not downloaded because their Content-Disposition header was badly parsed. --- src/librssguard/network-web/downloadmanager.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/librssguard/network-web/downloadmanager.cpp b/src/librssguard/network-web/downloadmanager.cpp index 0bdb04a0d..7d60c450b 100644 --- a/src/librssguard/network-web/downloadmanager.cpp +++ b/src/librssguard/network-web/downloadmanager.cpp @@ -135,17 +135,14 @@ QString DownloadItem::saveFileName(const QString& directory) const { QString path; if (m_reply->hasRawHeader("Content-Disposition")) { - const QString value = QLatin1String(m_reply->rawHeader("Content-Disposition")); - const int pos = value.indexOf(QL1S("filename=")); + QString value = QLatin1String(m_reply->rawHeader("Content-Disposition")); + QRegularExpression exp(".*filename=?\"([^\"]+)\"?"); + QRegularExpressionMatch match = exp.match(value); - if (pos != -1) { - QString name = value.mid(pos + 9); + if (match.isValid()) { + QString name = match.captured(1); - if (name.startsWith(QL1C('"')) && name.endsWith(QL1C('"'))) { - name = name.mid(1, name.size() - 2); - } - - path = name; + path = QUrl::fromPercentEncoding(name.toLocal8Bit()); } }