diff --git a/src/librssguard/services/greader/greaderfeed.cpp b/src/librssguard/services/greader/greaderfeed.cpp new file mode 100644 index 000000000..ee44dd506 --- /dev/null +++ b/src/librssguard/services/greader/greaderfeed.cpp @@ -0,0 +1,46 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/greaderfeed.h" + +#include "database/databasequeries.h" +#include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" +#include "services/greader/definitions.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/greaderserviceroot.h" + +#include + +GreaderFeed::GreaderFeed(RootItem* parent) : Feed(parent) {} + +GreaderServiceRoot* GreaderFeed::serviceRoot() const { + return qobject_cast(getParentServiceRoot()); +} + +bool GreaderFeed::canBeDeleted() const { + return true; +} + +bool GreaderFeed::deleteItem() { + try { + serviceRoot()->network()->subscriptionEdit(QSL(GREADER_API_EDIT_SUBSCRIPTION_DELETE), + customId(), + {}, + {}, + {}, + serviceRoot()->networkProxy()); + serviceRoot()->requestItemRemoval(this); + return true; + } + catch (const ApplicationException& ex) { + qWarningNN << LOGSEC_GREADER << "Unsubscribing from feed failed, error:" << QUOTE_W_SPACE_DOT(ex.message()); + return false; + } +} + +bool GreaderFeed::removeItself() { + QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); + + return DatabaseQueries::deleteFeed(database, this, serviceRoot()->accountId()); +} diff --git a/src/librssguard/services/greader/greaderfeed.h b/src/librssguard/services/greader/greaderfeed.h new file mode 100644 index 000000000..c653d242d --- /dev/null +++ b/src/librssguard/services/greader/greaderfeed.h @@ -0,0 +1,26 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERFEED_H +#define GREADERFEED_H + +#include "services/abstract/feed.h" + +class GreaderServiceRoot; + +class GreaderFeed : public Feed { + Q_OBJECT + + friend class FormGreaderFeedDetails; + + public: + explicit GreaderFeed(RootItem* parent = nullptr); + + virtual bool canBeDeleted() const; + virtual bool deleteItem(); + + private: + GreaderServiceRoot* serviceRoot() const; + bool removeItself(); +}; + +#endif // TTRSSFEED_H diff --git a/src/librssguard/services/greader/gui/formgreaderfeeddetails.cpp b/src/librssguard/services/greader/gui/formgreaderfeeddetails.cpp new file mode 100644 index 000000000..0de207f44 --- /dev/null +++ b/src/librssguard/services/greader/gui/formgreaderfeeddetails.cpp @@ -0,0 +1,108 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/gui/formgreaderfeeddetails.h" + +#include "exceptions/applicationexception.h" +#include "miscellaneous/application.h" +#include "services/greader/definitions.h" +#include "services/greader/greaderfeed.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/greaderserviceroot.h" +#include "services/greader/gui/greaderfeeddetails.h" + +#include +#include + +FormGreaderFeedDetails::FormGreaderFeedDetails(ServiceRoot* service_root, + RootItem* parent_to_select, + const QString& url, + QWidget* parent) + : FormFeedDetails(service_root, parent), m_feedDetails(nullptr), m_parentToSelect(parent_to_select), + m_urlToProcess(url) {} + +void FormGreaderFeedDetails::apply() { + if (!m_creatingNew) { + if (!m_isBatchEdit) { + GreaderFeed* fd = feed(); + RootItem* parent = m_feedDetails->ui.m_cmbParentCategory->currentData().value(); + const QString category_id = parent->kind() == RootItem::Kind::ServiceRoot ? QString() : parent->customId(); + + try { + fd->serviceRoot()->network()->subscriptionEdit(QSL(GREADER_API_EDIT_SUBSCRIPTION_MODIFY), + fd->customId(), + m_feedDetails->ui.m_txtTitle->lineEdit()->text(), + category_id, + {}, + m_serviceRoot->networkProxy()); + } + catch (const ApplicationException& ex) { + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Feed NOT updated"), + tr("Error: %1").arg(ex.message()), + QSystemTrayIcon::MessageIcon::Critical}, + GuiMessageDestination(true, true)); + } + } + + // NOTE: We can only edit base properties, therefore + // base method is fine. + FormFeedDetails::apply(); + } + else { + RootItem* parent = m_feedDetails->ui.m_cmbParentCategory->currentData().value(); + auto* root = qobject_cast(parent->getParentServiceRoot()); + const QString category_id = parent->kind() == RootItem::Kind::ServiceRoot ? QString() : parent->customId(); + + try { + root->network()->subscriptionEdit(QSL(GREADER_API_EDIT_SUBSCRIPTION_ADD), + QSL("feed/") + m_feedDetails->ui.m_txtUrl->lineEdit()->text(), + m_feedDetails->ui.m_txtTitle->lineEdit()->text(), + category_id, + {}, + m_serviceRoot->networkProxy()); + + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Feed added"), + tr("Feed was added, obtaining new tree of feeds now."), + QSystemTrayIcon::MessageIcon::Information}); + QTimer::singleShot(300, root, &GreaderServiceRoot::syncIn); + } + catch (const ApplicationException& ex) { + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Feed NOT added"), + tr("Error: %1").arg(ex.message()), + QSystemTrayIcon::MessageIcon::Critical}, + GuiMessageDestination(true, true)); + } + } +} + +void FormGreaderFeedDetails::loadFeedData() { + FormFeedDetails::loadFeedData(); + + if (!m_isBatchEdit) { + m_feedDetails = new GreaderFeedDetails(this); + + insertCustomTab(m_feedDetails, tr("General"), 0); + activateTab(0); + + GreaderFeed* fd = feed(); + + m_feedDetails->loadCategories(m_serviceRoot->getSubTreeCategories(), + m_serviceRoot, + m_creatingNew ? m_parentToSelect : fd->parent()); + + if (m_creatingNew) { + if (!m_urlToProcess.isEmpty()) { + m_feedDetails->ui.m_txtUrl->lineEdit()->setText(m_urlToProcess); + } + + m_feedDetails->ui.m_txtUrl->setFocus(); + m_feedDetails->ui.m_txtUrl->lineEdit()->selectAll(); + } + else { + m_feedDetails->ui.m_txtTitle->lineEdit()->setText(fd->title()); + m_feedDetails->ui.m_txtUrl->lineEdit()->setText(fd->source()); + } + } +} diff --git a/src/librssguard/services/greader/gui/formgreaderfeeddetails.h b/src/librssguard/services/greader/gui/formgreaderfeeddetails.h new file mode 100644 index 000000000..edaa37c75 --- /dev/null +++ b/src/librssguard/services/greader/gui/formgreaderfeeddetails.h @@ -0,0 +1,30 @@ +// For license of this file, see /LICENSE.md. + +#ifndef FORMGREADERFEEDDETAILS_H +#define FORMGREADERFEEDDETAILS_H + +#include "services/abstract/gui/formfeeddetails.h" + +class GreaderFeed; +class GreaderFeedDetails; + +class FormGreaderFeedDetails : public FormFeedDetails { + public: + explicit FormGreaderFeedDetails(ServiceRoot* service_root, + RootItem* parent_to_select = nullptr, + const QString& url = QString(), + QWidget* parent = nullptr); + + protected slots: + virtual void apply(); + + private: + virtual void loadFeedData(); + + private: + GreaderFeedDetails* m_feedDetails; + RootItem* m_parentToSelect; + QString m_urlToProcess; +}; + +#endif // FORMGREADERFEEDDETAILS_H diff --git a/src/librssguard/services/greader/gui/greaderfeeddetails.cpp b/src/librssguard/services/greader/gui/greaderfeeddetails.cpp new file mode 100644 index 000000000..24255326f --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderfeeddetails.cpp @@ -0,0 +1,70 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/gui/greaderfeeddetails.h" + +#include "definitions/definitions.h" +#include "services/abstract/category.h" + +GreaderFeedDetails::GreaderFeedDetails(QWidget* parent) : QWidget(parent) { + ui.setupUi(this); + + ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("Full feed URL including scheme")); + ui.m_txtUrl->lineEdit()->setToolTip(tr("Provide URL for your feed.")); + + connect(ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderFeedDetails::onUrlChanged); + onUrlChanged(QString()); + + connect(ui.m_txtTitle->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderFeedDetails::onTitleChanged); + onTitleChanged(QString()); +} + +void GreaderFeedDetails::onUrlChanged(const QString& new_url) { + if (QRegularExpression(QSL(URL_REGEXP)).match(new_url).hasMatch()) { + // New url is well-formed. + ui.m_txtUrl->setStatus(LineEditWithStatus::StatusType::Ok, tr("The URL is ok.")); + } + else if (!new_url.simplified().isEmpty()) { + // New url is not well-formed but is not empty on the other hand. + ui.m_txtUrl->setStatus( + LineEditWithStatus::StatusType::Warning, + tr(R"(The URL does not meet standard pattern. Does your URL start with "http://" or "https://" prefix.)")); + } + else { + // New url is empty. + ui.m_txtUrl->setStatus(LineEditWithStatus::StatusType::Error, tr("The URL is empty.")); + } +} + +void GreaderFeedDetails::onTitleChanged(const QString& new_title) { + if (new_title.isEmpty()) { + ui.m_txtTitle->setStatus(WidgetWithStatus::StatusType::Ok, tr("Title is entered.")); + } + else { + ui.m_txtTitle->setStatus(WidgetWithStatus::StatusType::Warning, + tr("No title is entered. If you are creating new feed, title will be automatically " + "extracted from it.")); + } +} + +void GreaderFeedDetails::loadCategories(const QList& categories, + RootItem* root_item, + RootItem* parent_to_select) { + ui.m_cmbParentCategory->addItem(root_item->fullIcon(), root_item->title(), QVariant::fromValue(root_item)); + + for (Category* category : categories) { + ui.m_cmbParentCategory->addItem(category->fullIcon(), category->title(), QVariant::fromValue(category)); + } + + if (parent_to_select != nullptr) { + if (parent_to_select->kind() == RootItem::Kind::Category) { + ui.m_cmbParentCategory->setCurrentIndex(ui.m_cmbParentCategory->findData(QVariant::fromValue(parent_to_select))); + } + else if (parent_to_select->kind() == RootItem::Kind::Feed) { + int target_item = ui.m_cmbParentCategory->findData(QVariant::fromValue(parent_to_select->parent())); + + if (target_item >= 0) { + ui.m_cmbParentCategory->setCurrentIndex(target_item); + } + } + } +} diff --git a/src/librssguard/services/greader/gui/greaderfeeddetails.h b/src/librssguard/services/greader/gui/greaderfeeddetails.h new file mode 100644 index 000000000..d651e273d --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderfeeddetails.h @@ -0,0 +1,32 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERFEEDDETAILS_H +#define GREADERFEEDDETAILS_H + +#include + +#include "ui_greaderfeeddetails.h" + +class Category; +class RootItem; + +class GreaderFeedDetails : public QWidget { + Q_OBJECT + + friend class FormGreaderFeedDetails; + + public: + explicit GreaderFeedDetails(QWidget* parent = nullptr); + + private slots: + void onUrlChanged(const QString& new_url); + void onTitleChanged(const QString& new_title); + + private: + void loadCategories(const QList& categories, RootItem* root_item, RootItem* parent_to_select = nullptr); + + private: + Ui::GreaderFeedDetails ui; +}; + +#endif // GREADERFEEDDETAILS_H diff --git a/src/librssguard/services/greader/gui/greaderfeeddetails.ui b/src/librssguard/services/greader/gui/greaderfeeddetails.ui new file mode 100644 index 000000000..c65701c6a --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderfeeddetails.ui @@ -0,0 +1,81 @@ + + + GreaderFeedDetails + + + + 0 + 0 + 367 + 202 + + + + Form + + + + + + Parent folder + + + m_cmbParentCategory + + + + + + + Select parent item for your feed. + + + + 12 + 12 + + + + true + + + + + + + URL + + + m_txtUrl + + + + + + + + + + + + + Title + + + m_txtTitle + + + + + + + + LineEditWithStatus + QWidget +
lineeditwithstatus.h
+ 1 +
+
+ + +