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; };