diff --git a/resources/icons.qrc b/resources/icons.qrc
index 2d41be1a3..f8a10e675 100644
--- a/resources/icons.qrc
+++ b/resources/icons.qrc
@@ -27,6 +27,7 @@
./graphics/Breeze/actions/32/document-open.svg
./graphics/Breeze/actions/32/document-revert.svg
./graphics/Breeze/actions/22/download.svg
+ ./graphics/Breeze/actions/22/draw-line.svg
./graphics/Breeze/actions/22/edit-clear.svg
./graphics/Breeze/actions/22/edit-copy.svg
./graphics/Breeze/actions/22/edit-cut.svg
@@ -120,6 +121,7 @@
./graphics/Breeze Dark/actions/32/document-open.svg
./graphics/Breeze Dark/actions/32/document-revert.svg
./graphics/Breeze Dark/actions/22/download.svg
+ ./graphics/Breeze Dark/actions/22/draw-line.svg
./graphics/Breeze Dark/actions/22/edit-clear.svg
./graphics/Breeze Dark/actions/22/edit-copy.svg
./graphics/Breeze Dark/actions/22/edit-cut.svg
diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt
index 020343dc8..6c4bf3852 100644
--- a/src/librssguard/CMakeLists.txt
+++ b/src/librssguard/CMakeLists.txt
@@ -117,8 +117,6 @@ set(SOURCES
gui/reusable/colortoolbutton.h
gui/reusable/comboboxwithstatus.cpp
gui/reusable/comboboxwithstatus.h
- gui/reusable/discoverfeedsbutton.cpp
- gui/reusable/discoverfeedsbutton.h
gui/reusable/edittableview.cpp
gui/reusable/edittableview.h
gui/reusable/helpspoiler.cpp
@@ -296,6 +294,8 @@ set(SOURCES
services/abstract/gui/formcategorydetails.h
services/abstract/gui/formfeeddetails.cpp
services/abstract/gui/formfeeddetails.h
+ services/abstract/gui/multifeededitcheckbox.cpp
+ services/abstract/gui/multifeededitcheckbox.h
services/abstract/importantnode.cpp
services/abstract/importantnode.h
services/abstract/label.cpp
@@ -674,6 +674,7 @@ target_include_directories(rssguard
${CMAKE_CURRENT_SOURCE_DIR}/gui
${CMAKE_CURRENT_SOURCE_DIR}/gui/dialogs
${CMAKE_CURRENT_SOURCE_DIR}/gui/reusable
+ ${CMAKE_CURRENT_SOURCE_DIR}/services/abstract/gui
${CMAKE_CURRENT_SOURCE_DIR}/dynamic-shortcuts
PRIVATE
diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp
index 68bb9aa31..b4cad0e99 100644
--- a/src/librssguard/gui/dialogs/formmain.cpp
+++ b/src/librssguard/gui/dialogs/formmain.cpp
@@ -231,6 +231,8 @@ QList FormMain::allActions() const {
actions << m_ui->m_actionExpandCollapseItem;
actions << m_ui->m_actionExpandCollapseItemRecursively;
actions << m_ui->m_actionMessageFilters;
+ actions << m_ui->m_actionEmptyAllRecycleBins;
+ actions << m_ui->m_actionRestoreAllRecycleBins;
actions << m_ui->m_actionTabNewWebBrowser;
actions << m_ui->m_actionTabsCloseCurrent;
actions << m_ui->m_actionTabsCloseAll;
diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp
index 88b41abb1..a2e8de708 100644
--- a/src/librssguard/gui/feedsview.cpp
+++ b/src/librssguard/gui/feedsview.cpp
@@ -2,6 +2,7 @@
#include "gui/feedsview.h"
+#include "3rd-party/boolinq/boolinq.h"
#include "core/feedsmodel.h"
#include "core/feedsproxymodel.h"
#include "definitions/definitions.h"
@@ -13,6 +14,7 @@
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include "services/abstract/feed.h"
+#include "services/abstract/gui/formaccountdetails.h"
#include "services/abstract/rootitem.h"
#include "services/abstract/serviceroot.h"
@@ -24,6 +26,8 @@
#include
#include
+#include
+
FeedsView::FeedsView(QWidget* parent)
: BaseTreeView(parent), m_contextMenuService(nullptr), m_contextMenuBin(nullptr), m_contextMenuCategories(nullptr),
m_contextMenuFeeds(nullptr), m_contextMenuImportant(nullptr), m_contextMenuEmptySpace(nullptr),
@@ -80,6 +84,7 @@ QList FeedsView::selectedFeeds() const {
RootItem* FeedsView::selectedItem() const {
const QModelIndexList selected_rows = selectionModel()->selectedRows();
+ const QModelIndex current_row = currentIndex();
if (selected_rows.isEmpty()) {
return nullptr;
@@ -87,10 +92,39 @@ RootItem* FeedsView::selectedItem() const {
else {
RootItem* selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0)));
- return selected_item == m_sourceModel->rootItem() ? nullptr : selected_item;
+ if (selected_rows.size() == 1) {
+ return selected_item;
+ }
+
+ auto selected_items = boolinq::from(selected_rows)
+ .select([this](const QModelIndex& idx) {
+ return m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx));
+ })
+ .toStdList();
+
+ RootItem* current_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(current_row));
+
+ if (std::find(selected_items.begin(), selected_items.end(), current_item) != selected_items.end()) {
+ return current_item;
+ }
+ else {
+ return selected_items.front();
+ }
}
}
+QList FeedsView::selectedItems() const {
+ const QModelIndexList selected_rows = selectionModel()->selectedRows();
+
+ auto selected_items = boolinq::from(selected_rows)
+ .select([this](const QModelIndex& idx) {
+ return m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx));
+ })
+ .toStdList();
+
+ return FROM_STD_LIST(QList, selected_items);
+}
+
void FeedsView::copyUrlOfSelectedFeeds() const {
auto feeds = selectedFeeds();
QStringList urls;
@@ -218,16 +252,84 @@ void FeedsView::editSelectedItem() {
return;
}
- if (selectedItem()->canBeEdited()) {
- selectedItem()->editViaGui();
+ auto selected_items = selectedItems();
+
+ if (selected_items.isEmpty()) {
+ qApp->feedUpdateLock()->unlock();
+ return;
}
- else {
+
+ auto std_editable_items = boolinq::from(selected_items)
+ .where([](RootItem* it) {
+ return it->canBeEdited();
+ })
+ .toStdList();
+
+ if (std_editable_items.empty()) {
qApp->showGuiMessage(Notification::Event::GeneralEvent,
- {tr("Cannot edit item"),
- tr("Selected item cannot be edited, this is not (yet?) supported."),
+ {tr("Cannot edit items"),
+ tr("Selected items cannot be edited. This is not supported (yet)."),
+ QSystemTrayIcon::MessageIcon::Critical});
+
+ qApp->feedUpdateLock()->unlock();
+ return;
+ }
+
+ if (std_editable_items.front()->kind() == RootItem::Kind::ServiceRoot && std_editable_items.size() > 1) {
+ qApp->showGuiMessage(Notification::Event::GeneralEvent,
+ {tr("Cannot edit items"),
+ tr("%1 does not support batch editing of multiple accounts.").arg(QSL(APP_NAME)),
+ QSystemTrayIcon::MessageIcon::Critical});
+
+ qApp->feedUpdateLock()->unlock();
+ return;
+ }
+
+ // We also check if items are from single account, if not we end.
+ std::list distinct_accounts = boolinq::from(std_editable_items)
+ .select([](RootItem* it) {
+ return it->getParentServiceRoot();
+ })
+ .distinct()
+ .toStdList();
+
+ if (distinct_accounts.size() != 1) {
+ qApp->showGuiMessage(Notification::Event::GeneralEvent,
+ {tr("Cannot edit items"),
+ tr("%1 does not support batch editing of items from multiple accounts.").arg(QSL(APP_NAME)),
+ QSystemTrayIcon::MessageIcon::Critical});
+
+ qApp->feedUpdateLock()->unlock();
+ return;
+ }
+
+ std::list distinct_types = boolinq::from(std_editable_items)
+ .select([](RootItem* it) {
+ return it->kind();
+ })
+ .distinct()
+ .toStdList();
+
+ if (distinct_types.size() != 1) {
+ qApp->showGuiMessage(Notification::Event::GeneralEvent,
+ {tr("Cannot edit items"),
+ tr("%1 does not support batch editing of items of varying types.").arg(QSL(APP_NAME)),
+ QSystemTrayIcon::MessageIcon::Critical});
+
+ qApp->feedUpdateLock()->unlock();
+ return;
+ }
+
+ if (qsizetype(std_editable_items.size()) < selected_items.size()) {
+ // Some items are not editable.
+ qApp->showGuiMessage(Notification::Event::GeneralEvent,
+ {tr("Cannot edit some items"),
+ tr("Some of selected items cannot be edited. Proceeding to edit the rest."),
QSystemTrayIcon::MessageIcon::Warning});
}
+ distinct_accounts.front()->editItemsViaGui(FROM_STD_LIST(QList, std_editable_items));
+
// Changes are done, unlock the update master lock.
qApp->feedUpdateLock()->unlock();
diff --git a/src/librssguard/gui/feedsview.h b/src/librssguard/gui/feedsview.h
index 8836531be..403e79a48 100644
--- a/src/librssguard/gui/feedsview.h
+++ b/src/librssguard/gui/feedsview.h
@@ -32,9 +32,11 @@ class RSSGUARD_DLLSPEC FeedsView : public BaseTreeView {
// NOTE: This is recursive method which returns all descendants.
QList selectedFeeds() const;
- // Returns pointers to selected feed/category if they are really
- // selected.
+ // Returns selected item. If multiple items are selected, returns
+ // the one of them which is also "current". If none of them is
+ // "current", returns firs item of selected ones.
RootItem* selectedItem() const;
+ QList selectedItems() const;
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
void saveAllExpandStates();
diff --git a/src/librssguard/gui/reusable/discoverfeedsbutton.cpp b/src/librssguard/gui/reusable/discoverfeedsbutton.cpp
deleted file mode 100644
index 5f257c00e..000000000
--- a/src/librssguard/gui/reusable/discoverfeedsbutton.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// For license of this file, see /LICENSE.md.
-
-#include "gui/reusable/discoverfeedsbutton.h"
-
-#include "core/feedsmodel.h"
-#include "gui/dialogs/formmain.h"
-#include "gui/feedmessageviewer.h"
-#include "gui/feedsview.h"
-#include "gui/tabwidget.h"
-#include "miscellaneous/application.h"
-#include "miscellaneous/feedreader.h"
-#include "miscellaneous/iconfactory.h"
-#include "services/abstract/serviceroot.h"
-
-#include
-
-DiscoverFeedsButton::DiscoverFeedsButton(QWidget* parent) : QToolButton(parent), m_addresses(QStringList()) {
- setEnabled(false);
- setIcon(qApp->icons()->fromTheme(QSL("application-rss+xml")));
- setPopupMode(QToolButton::ToolButtonPopupMode::InstantPopup);
-}
-
-DiscoverFeedsButton::~DiscoverFeedsButton() {}
-
-void DiscoverFeedsButton::clearFeedAddresses() {
- setFeedAddresses({});
-}
-
-void DiscoverFeedsButton::setFeedAddresses(const QStringList& addresses) {
- setEnabled(!addresses.isEmpty());
- setToolTip(addresses.isEmpty() ?
- tr("This website does not contain any feeds") :
- tr("Add one of %n feed(s)", 0, addresses.size()));
-
- if (menu() == nullptr) {
- // Initialize the menu.
- setMenu(new QMenu(this));
- connect(menu(), &QMenu::triggered, this, &DiscoverFeedsButton::linkTriggered);
- connect(menu(), &QMenu::aboutToShow, this, &DiscoverFeedsButton::fillMenu);
- }
-
- menu()->hide();
- m_addresses = addresses;
-}
-
-void DiscoverFeedsButton::linkTriggered(QAction* action) {
- const QString url = action->property("url").toString();
- ServiceRoot* root = static_cast(action->property("root").value());
-
- if (root->supportsFeedAdding()) {
- root->addNewFeed(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->selectedItem(), url);
- }
- else {
- qApp->showGuiMessage(Notification::Event::GeneralEvent, {
- tr("Not supported by account"),
- tr("Given account does not support adding feeds."),
- QSystemTrayIcon::MessageIcon::Warning });
- }
-}
-
-void DiscoverFeedsButton::fillMenu() {
- menu()->clear();
- auto srts = qApp->feedReader()->feedsModel()->serviceRoots();
-
- for (const ServiceRoot* root : qAsConst(srts)) {
- if (root->supportsFeedAdding()) {
- QMenu* root_menu = menu()->addMenu(root->icon(), root->title());
-
- for (const QString& url : qAsConst(m_addresses)) {
- QAction* url_action = root_menu->addAction(root->icon(), url);
-
- url_action->setProperty("url", url);
- url_action->setProperty("root", QVariant::fromValue((void*) root));
- }
- }
- }
-
- if (menu()->isEmpty()) {
- menu()->addAction(tr("Feeds were detected, but no suitable accounts are configured."))->setEnabled(false);
- }
-}
diff --git a/src/librssguard/gui/reusable/discoverfeedsbutton.h b/src/librssguard/gui/reusable/discoverfeedsbutton.h
deleted file mode 100644
index 5f21f5e2e..000000000
--- a/src/librssguard/gui/reusable/discoverfeedsbutton.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// For license of this file, see /LICENSE.md.
-
-#ifndef DISCOVERFEEDSBUTTON_H
-#define DISCOVERFEEDSBUTTON_H
-
-#include
-
-class DiscoverFeedsButton : public QToolButton {
- Q_OBJECT
-
- public:
- explicit DiscoverFeedsButton(QWidget* parent = nullptr);
- virtual ~DiscoverFeedsButton();
-
- void clearFeedAddresses();
- void setFeedAddresses(const QStringList& addresses);
-
- private slots:
- void linkTriggered(QAction* action);
- void fillMenu();
-
- private:
- QStringList m_addresses;
-};
-
-#endif // DISCOVERFEEDSBUTTON_H
diff --git a/src/librssguard/gui/toolbars/toolbareditor.cpp b/src/librssguard/gui/toolbars/toolbareditor.cpp
index 24278269e..52cbaefe0 100644
--- a/src/librssguard/gui/toolbars/toolbareditor.cpp
+++ b/src/librssguard/gui/toolbars/toolbareditor.cpp
@@ -80,7 +80,7 @@ void ToolBarEditor::loadEditor(const QList& activated_actions, const Q
if (action->isSeparator()) {
action_item->setData(Qt::ItemDataRole::UserRole, SEPARATOR_ACTION_NAME);
- action_item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
+ action_item->setIcon(qApp->icons()->fromTheme(QSL("draw-line"), QSL("insert-object")));
action_item->setText(tr("Separator"));
action_item->setToolTip(tr("Separator"));
}
diff --git a/src/librssguard/gui/webbrowser.cpp b/src/librssguard/gui/webbrowser.cpp
index 4ea62b274..6e1c91532 100644
--- a/src/librssguard/gui/webbrowser.cpp
+++ b/src/librssguard/gui/webbrowser.cpp
@@ -5,7 +5,6 @@
#include "definitions/globals.h"
#include "gui/dialogs/formmain.h"
#include "gui/messagebox.h"
-#include "gui/reusable/discoverfeedsbutton.h"
#include "gui/reusable/locationlineedit.h"
#include "gui/reusable/searchtextwidget.h"
#include "gui/tabwidget.h"
@@ -27,7 +26,6 @@
WebBrowser::WebBrowser(WebViewer* viewer, QWidget* parent)
: TabContent(parent), m_layout(new QVBoxLayout(this)), m_toolBar(new QToolBar(tr("Navigation panel"), this)),
m_webView(viewer), m_searchWidget(new SearchTextWidget(this)), m_txtLocation(new LocationLineEdit(this)),
- m_btnDiscoverFeeds(new DiscoverFeedsButton(this)),
m_actionOpenInSystemBrowser(new QAction(qApp->icons()->fromTheme(QSL("document-open")),
tr("Open this website in system web browser"),
this)),
@@ -297,15 +295,9 @@ void WebBrowser::initializeLayout() {
m_actionReload->setIcon(qApp->icons()->fromTheme(QSL("reload"), QSL("view-refresh")));
m_actionStop->setIcon(qApp->icons()->fromTheme(QSL("process-stop")));
- m_btnDiscoverFeedsAction = new QWidgetAction(this);
-
m_actionOpenInSystemBrowser->setEnabled(false);
m_actionReadabilePage->setEnabled(false);
- // m_btnDiscoverFeedsAction->setDefaultWidget(new QWidget(this));
-
- m_btnDiscoverFeedsAction->setDefaultWidget(m_btnDiscoverFeeds);
-
// Add needed actions into toolbar.
m_toolBar->addAction(m_actionBack);
m_toolBar->addAction(m_actionForward);
@@ -314,7 +306,6 @@ void WebBrowser::initializeLayout() {
m_toolBar->addAction(m_actionOpenInSystemBrowser);
m_toolBar->addAction(m_actionReadabilePage);
- m_toolBar->addAction(m_btnDiscoverFeedsAction);
m_txtLocationAction = m_toolBar->addWidget(m_txtLocation);
m_loadingProgress = new QProgressBar(this);
@@ -336,7 +327,6 @@ void WebBrowser::initializeLayout() {
}
void WebBrowser::onLoadingStarted() {
- m_btnDiscoverFeeds->clearFeedAddresses();
m_loadingProgress->show();
m_actionOpenInSystemBrowser->setEnabled(false);
m_actionReadabilePage->setEnabled(false);
@@ -359,15 +349,6 @@ void WebBrowser::onLoadingFinished(bool success) {
m_actionOpenInSystemBrowser->setEnabled(false);
m_actionReadabilePage->setEnabled(false);
}
-
- // TODO: nevolat toto u internich "rssguard" adres
- // Let's check if there are any feeds defined on the web and eventually
- // display "Add feeds" button.
- m_btnDiscoverFeeds->setFeedAddresses(NetworkFactory::extractFeedLinksFromHtmlPage(m_webView->url(),
- m_webView->html()));
- }
- else {
- m_btnDiscoverFeeds->clearFeedAddresses();
}
m_loadingProgress->hide();
diff --git a/src/librssguard/gui/webbrowser.h b/src/librssguard/gui/webbrowser.h
index 425660b96..fc0172622 100644
--- a/src/librssguard/gui/webbrowser.h
+++ b/src/librssguard/gui/webbrowser.h
@@ -22,7 +22,6 @@ class QLabel;
class TabWidget;
class WebViewer;
class LocationLineEdit;
-class DiscoverFeedsButton;
class SearchTextWidget;
class WebBrowser : public TabContent {
@@ -91,8 +90,6 @@ class WebBrowser : public TabContent {
SearchTextWidget* m_searchWidget;
LocationLineEdit* m_txtLocation;
QAction* m_txtLocationAction;
- DiscoverFeedsButton* m_btnDiscoverFeeds;
- QWidgetAction* m_btnDiscoverFeedsAction;
QProgressBar* m_loadingProgress;
QAction* m_actionBack;
QAction* m_actionForward;
diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp
index cdcc99199..7943b506c 100644
--- a/src/librssguard/services/abstract/feed.cpp
+++ b/src/librssguard/services/abstract/feed.cpp
@@ -150,13 +150,6 @@ bool Feed::canBeEdited() const {
return true;
}
-bool Feed::editViaGui() {
- QScopedPointer form_pointer(new FormFeedDetails(getParentServiceRoot(), qApp->mainFormWidget()));
-
- form_pointer->addEditFeed(this);
- return false;
-}
-
void Feed::setAutoUpdateInterval(int auto_update_interval) {
// If new initial auto-update interval is set, then
// we should reset time that remains to the next auto-update.
diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h
index 922eeb6a8..4cbf1f432 100644
--- a/src/librssguard/services/abstract/feed.h
+++ b/src/librssguard/services/abstract/feed.h
@@ -17,7 +17,11 @@ class Feed : public RootItem {
public:
// Specifies the auto-download strategy for the feed.
- enum class AutoUpdateType { DontAutoUpdate = 0, DefaultAutoUpdate = 1, SpecificAutoUpdate = 2 };
+ enum class AutoUpdateType {
+ DontAutoUpdate = 0,
+ DefaultAutoUpdate = 1,
+ SpecificAutoUpdate = 2
+ };
// Specifies the actual "status" of the feed.
// For example if it has new messages, error
@@ -47,7 +51,6 @@ class Feed : public RootItem {
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual bool canBeEdited() const;
- virtual bool editViaGui();
virtual QVariant data(int column, int role) const;
void setCountOfAllMessages(int count_all_messages);
diff --git a/src/librssguard/services/abstract/gui/authenticationdetails.ui b/src/librssguard/services/abstract/gui/authenticationdetails.ui
index 050b6302d..a0f264d67 100644
--- a/src/librssguard/services/abstract/gui/authenticationdetails.ui
+++ b/src/librssguard/services/abstract/gui/authenticationdetails.ui
@@ -7,73 +7,92 @@
0
0
350
- 196
+ 153
Form
- -
-
-
- Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported.
-
-
- Credentials
-
-
- false
-
-
- false
-
-
-
-
-
-
- Username
-
-
- m_txtUsername
-
-
-
- -
-
-
- -
-
-
- Password
-
-
- m_txtPassword
-
-
-
- -
-
-
-
-
-
-
-
-
- Authentication type
-
-
- m_cbAuthType
-
-
+
+
-
+
+
+ -
+
+
+ Authentication type
+
+
+ m_cbAuthType
+
+
+
+
-
+ -
+
+
-
+
+
+ -
+
+
+ Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported.
+
+
+ Credentials
+
+
+ false
+
+
+ false
+
+
+
-
+
+
+ Username
+
+
+ m_txtUsername
+
+
+
+ -
+
+
+ -
+
+
+ Password
+
+
+ m_txtPassword
+
+
+
+ -
+
+
+
+
+
+
+
+
+ MultiFeedEditCheckBox
+ QCheckBox
+
+
LineEditWithStatus
QWidget
diff --git a/src/librssguard/services/abstract/gui/formcategorydetails.cpp b/src/librssguard/services/abstract/gui/formcategorydetails.cpp
index b21507ac4..61216b752 100644
--- a/src/librssguard/services/abstract/gui/formcategorydetails.cpp
+++ b/src/librssguard/services/abstract/gui/formcategorydetails.cpp
@@ -10,6 +10,7 @@
#include "gui/reusable/baselineedit.h"
#include "miscellaneous/iconfactory.h"
#include "services/abstract/category.h"
+#include "services/abstract/gui/multifeededitcheckbox.h"
#include "services/abstract/rootitem.h"
#include
@@ -23,7 +24,7 @@
#include
FormCategoryDetails::FormCategoryDetails(ServiceRoot* service_root, RootItem* parent_to_select, QWidget* parent)
- : QDialog(parent), m_category(nullptr), m_serviceRoot(service_root), m_parentToSelect(parent_to_select) {
+ : QDialog(parent), m_serviceRoot(service_root), m_parentToSelect(parent_to_select) {
initialize();
createConnections();
@@ -50,8 +51,28 @@ void FormCategoryDetails::createConnections() {
connect(m_actionUseDefaultIcon, &QAction::triggered, this, &FormCategoryDetails::onUseDefaultIcon);
}
+bool FormCategoryDetails::isChangeAllowed(MultiFeedEditCheckBox* mcb) const {
+ return !m_isBatchEdit || mcb->isChecked();
+}
+
void FormCategoryDetails::loadCategoryData() {
- loadCategories(m_serviceRoot->getSubTreeCategories(), m_serviceRoot, m_category);
+ Category* cat = category();
+
+ if (m_isBatchEdit) {
+ // We hook batch selectors.
+ m_ui->m_mcbParent->addActionWidget(m_ui->m_cmbParentCategory);
+ m_ui->m_mcbTitle->addActionWidget(m_ui->m_txtTitle);
+ m_ui->m_mcbDescription->addActionWidget(m_ui->m_txtDescription);
+ m_ui->m_mcbIcon->addActionWidget(m_ui->m_btnIcon);
+ }
+ else {
+ // We hide batch selectors.
+ for (auto* cb : findChildren()) {
+ cb->hide();
+ }
+ }
+
+ loadCategories(m_serviceRoot->getSubTreeCategories(), m_serviceRoot, cat);
if (m_creatingNew) {
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("folder")), tr("Add new category"));
@@ -76,42 +97,69 @@ void FormCategoryDetails::loadCategoryData() {
}
}
else {
- GuiUtilities::applyDialogProperties(*this, m_category->fullIcon(), tr("Edit \"%1\"").arg(m_category->title()));
+ if (!m_isBatchEdit) {
+ GuiUtilities::applyDialogProperties(*this, cat->fullIcon(), tr("Edit \"%1\"").arg(cat->title()));
+ }
+ else {
+ GuiUtilities::applyDialogProperties(*this,
+ qApp->icons()->fromTheme(QSL("folder")),
+ tr("Edit %n categories", nullptr, m_categories.size()));
+ }
- m_ui->m_cmbParentCategory
- ->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue(m_category->parent())));
+ m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue(cat->parent())));
}
- m_ui->m_txtTitle->lineEdit()->setText(m_category->title());
- m_ui->m_txtDescription->lineEdit()->setText(m_category->description());
- m_ui->m_btnIcon->setIcon(m_category->icon());
+ m_ui->m_txtTitle->lineEdit()->setText(cat->title());
+ m_ui->m_txtDescription->lineEdit()->setText(cat->description());
+ m_ui->m_btnIcon->setIcon(cat->icon());
m_ui->m_txtTitle->lineEdit()->setFocus();
}
void FormCategoryDetails::apply() {
+ QList cats = categories();
RootItem* parent = m_ui->m_cmbParentCategory->currentData().value();
-
- m_category->setTitle(m_ui->m_txtTitle->lineEdit()->text());
- m_category->setDescription(m_ui->m_txtDescription->lineEdit()->text());
- m_category->setIcon(m_ui->m_btnIcon->icon());
-
QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
- try {
- DatabaseQueries::createOverwriteCategory(database, m_category, m_serviceRoot->accountId(), parent->id());
- }
- catch (const ApplicationException& ex) {
- qFatal("Cannot save category: '%s'.", qPrintable(ex.message()));
- }
-
- m_serviceRoot->requestItemReassignment(m_category, parent);
- m_serviceRoot->itemChanged({m_category});
-
- if (m_creatingNew) {
- m_serviceRoot->requestItemExpand({parent}, true);
+ for (Category* cat : cats) {
+ if (isChangeAllowed(m_ui->m_mcbTitle)) {
+ cat->setTitle(m_ui->m_txtTitle->lineEdit()->text());
+ }
+
+ if (isChangeAllowed(m_ui->m_mcbDescription)) {
+ cat->setDescription(m_ui->m_txtDescription->lineEdit()->text());
+ }
+
+ if (isChangeAllowed(m_ui->m_mcbIcon)) {
+ cat->setIcon(m_ui->m_btnIcon->icon());
+ }
+
+ int new_parent_id;
+
+ if (isChangeAllowed(m_ui->m_mcbParent)) {
+ new_parent_id = parent->id();
+ }
+ else {
+ new_parent_id = cat->parent()->id();
+ }
+
+ try {
+ DatabaseQueries::createOverwriteCategory(database, cat, m_serviceRoot->accountId(), new_parent_id);
+ }
+ catch (const ApplicationException& ex) {
+ qFatal("Cannot save category: '%s'.", qPrintable(ex.message()));
+ }
+
+ if (isChangeAllowed(m_ui->m_mcbParent)) {
+ m_serviceRoot->requestItemReassignment(cat, parent);
+ }
+
+ if (m_creatingNew) {
+ m_serviceRoot->requestItemExpand({parent}, true);
+ }
}
+ m_serviceRoot->itemChanged(categories());
accept();
}
diff --git a/src/librssguard/services/abstract/gui/formcategorydetails.h b/src/librssguard/services/abstract/gui/formcategorydetails.h
index 218e80ec5..82ca17a6a 100644
--- a/src/librssguard/services/abstract/gui/formcategorydetails.h
+++ b/src/librssguard/services/abstract/gui/formcategorydetails.h
@@ -7,6 +7,9 @@
#include
+#include "3rd-party/boolinq/boolinq.h"
+#include "definitions/definitions.h"
+
namespace Ui {
class FormCategoryDetails;
}
@@ -17,21 +20,29 @@ class FeedsModel;
class RootItem;
class QMenu;
class QAction;
+class MultiFeedEditCheckBox;
class FormCategoryDetails : public QDialog {
- Q_OBJECT
+ Q_OBJECT
public:
- explicit FormCategoryDetails(ServiceRoot* service_root, RootItem* parent_to_select = nullptr, QWidget* parent = nullptr);
+ explicit FormCategoryDetails(ServiceRoot* service_root,
+ RootItem* parent_to_select = nullptr,
+ QWidget* parent = nullptr);
virtual ~FormCategoryDetails();
- template
- T* addEditCategory(T* category_to_edit = nullptr);
+ template
+ QList addEditCategory(const QList& cats_to_edit = {});
- template
+ template
T* category() const;
+ // Returns all cats.
+ template
+ QList categories() const;
+
protected:
+ bool isChangeAllowed(MultiFeedEditCheckBox* mcb) const;
virtual void loadCategoryData();
protected slots:
@@ -58,39 +69,52 @@ class FormCategoryDetails : public QDialog {
private:
QScopedPointer m_ui;
- Category* m_category;
+ QList m_categories;
ServiceRoot* m_serviceRoot;
QMenu* m_iconMenu{};
QAction* m_actionLoadIconFromFile{};
QAction* m_actionUseDefaultIcon{};
RootItem* m_parentToSelect;
bool m_creatingNew;
+ bool m_isBatchEdit;
};
-template
-inline T* FormCategoryDetails::addEditCategory(T* category_to_edit) {
- m_creatingNew = category_to_edit == nullptr;
+template
+inline QList FormCategoryDetails::addEditCategory(const QList& cats_to_edit) {
+ m_creatingNew = cats_to_edit.isEmpty();
+ m_isBatchEdit = cats_to_edit.size() > 1;
if (m_creatingNew) {
- m_category = new T();
+ m_categories.append(new T());
}
else {
- m_category = category_to_edit;
+ m_categories.append(cats_to_edit);
}
loadCategoryData();
if (exec() == QDialog::DialogCode::Accepted) {
- return category();
+ return categories();
}
else {
- return nullptr;
+ return {};
}
}
-template
+template
inline T* FormCategoryDetails::category() const {
- return qobject_cast(m_category);
+ return qobject_cast(m_categories.first());
+}
+
+template
+inline QList FormCategoryDetails::categories() const {
+ std::list std_cats = boolinq::from(m_categories)
+ .select([](Category* fd) {
+ return qobject_cast(fd);
+ })
+ .toStdList();
+
+ return FROM_STD_LIST(QList, std_cats);
}
#endif // FORMCATEGORYDETAILS_H
diff --git a/src/librssguard/services/abstract/gui/formcategorydetails.ui b/src/librssguard/services/abstract/gui/formcategorydetails.ui
index cf99b996c..1f544fe46 100644
--- a/src/librssguard/services/abstract/gui/formcategorydetails.ui
+++ b/src/librssguard/services/abstract/gui/formcategorydetails.ui
@@ -6,8 +6,8 @@
0
0
- 397
- 209
+ 455
+ 262
@@ -19,13 +19,13 @@
-
- -
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
-
+
+
-
+
+
-
+
+
+ -
Parent folder
@@ -35,20 +35,27 @@
- -
-
-
- Select parent item for your category.
-
-
-
- 13
- 12
-
-
-
+
+
+ -
+
+
+ Select parent item for your category.
+
+
+
+ 13
+ 12
+
+
+
+
+ -
+
+
-
+
- -
+
-
Title
@@ -58,7 +65,17 @@
- -
+
+
+ -
+
+
+ -
+
+
-
+
+
+ -
Description
@@ -68,7 +85,17 @@
- -
+
+
+ -
+
+
+ -
+
+
-
+
+
+ -
Icon
@@ -78,52 +105,46 @@
- -
-
-
-
- 0
- 0
-
-
-
-
- 40
- 40
-
-
-
- Select icon for your category.
-
-
-
-
-
-
- 20
- 20
-
-
-
- QToolButton::InstantPopup
-
-
- false
-
-
- Qt::NoArrow
-
-
-
- -
-
-
- -
-
-
- -
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 40
+ 40
+
+
+
+ Select icon for your category.
+
+
+
+
+
+
+ 20
+ 20
+
+
+
+ QToolButton::InstantPopup
+
+
+ false
+
+
+ Qt::NoArrow
+
+
+
+ -
Qt::Horizontal
@@ -133,9 +154,27 @@
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+ MultiFeedEditCheckBox
+ QCheckBox
+
+
LineEditWithStatus
QWidget
@@ -157,8 +196,8 @@
reject()
- 325
- 170
+ 340
+ 353
286
diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.cpp b/src/librssguard/services/abstract/gui/formfeeddetails.cpp
index fe691542a..19dafd509 100644
--- a/src/librssguard/services/abstract/gui/formfeeddetails.cpp
+++ b/src/librssguard/services/abstract/gui/formfeeddetails.cpp
@@ -8,6 +8,7 @@
#include "gui/guiutilities.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/textfactory.h"
+#include "services/abstract/gui/multifeededitcheckbox.h"
#include "services/abstract/rootitem.h"
#include
@@ -17,92 +18,150 @@
#include
FormFeedDetails::FormFeedDetails(ServiceRoot* service_root, QWidget* parent)
- : QDialog(parent), m_feed(nullptr), m_serviceRoot(service_root) {
+ : QDialog(parent), m_serviceRoot(service_root) {
initialize();
createConnections();
}
void FormFeedDetails::activateTab(int index) {
- m_ui->m_tabWidget->setCurrentIndex(index);
+ m_ui.m_tabWidget->setCurrentIndex(index);
}
void FormFeedDetails::clearTabs() {
- m_ui->m_tabWidget->clear();
+ m_ui.m_tabWidget->clear();
}
void FormFeedDetails::insertCustomTab(QWidget* custom_tab, const QString& title, int index) {
- m_ui->m_tabWidget->insertTab(index, custom_tab, title);
+ m_ui.m_tabWidget->insertTab(index, custom_tab, title);
}
void FormFeedDetails::apply() {
- // Setup common data for the feed.
- m_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType
- ->itemData(m_ui->m_cmbAutoUpdateType->currentIndex())
+ QList fds = feeds();
+
+ for (Feed* fd : fds) {
+ // Setup common data for the feed.
+ if (isChangeAllowed(m_ui.m_mcbAutoDownloading)) {
+ fd->setAutoUpdateType(static_cast(m_ui.m_cmbAutoUpdateType
+ ->itemData(m_ui.m_cmbAutoUpdateType->currentIndex())
.toInt()));
- m_feed->setAutoUpdateInterval(int(m_ui->m_spinAutoUpdateInterval->value()));
- m_feed->setOpenArticlesDirectly(m_ui->m_cbOpenArticlesAutomatically->isChecked());
- m_feed->setIsRtl(m_ui->m_cbFeedRTL->isChecked());
- m_feed->setAddAnyDatetimeArticles(m_ui->m_cbAddAnyDateArticles->isChecked());
- m_feed->setDatetimeToAvoid(m_ui->m_gbAvoidOldArticles->isChecked() ? m_ui->m_dtDateTimeToAvoid->dateTime()
- : TextFactory::parseDateTime(0));
- m_feed->setIsSwitchedOff(m_ui->m_cbDisableFeed->isChecked());
- m_feed->setIsQuiet(m_ui->m_cbSuppressFeed->isChecked());
+ fd->setAutoUpdateInterval(int(m_ui.m_spinAutoUpdateInterval->value()));
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbOpenArticlesAutomatically)) {
+ fd->setOpenArticlesDirectly(m_ui.m_cbOpenArticlesAutomatically->isChecked());
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbFeedRtl)) {
+ fd->setIsRtl(m_ui.m_cbFeedRTL->isChecked());
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbAddAnyDateArticles)) {
+ fd->setAddAnyDatetimeArticles(m_ui.m_cbAddAnyDateArticles->isChecked());
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbAvoidOldArticles)) {
+ fd->setDatetimeToAvoid(m_ui.m_gbAvoidOldArticles->isChecked() ? m_ui.m_dtDateTimeToAvoid->dateTime()
+ : TextFactory::parseDateTime(0));
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbDisableFeed)) {
+ fd->setIsSwitchedOff(m_ui.m_cbDisableFeed->isChecked());
+ }
+
+ if (isChangeAllowed(m_ui.m_mcbSuppressFeed)) {
+ fd->setIsQuiet(m_ui.m_cbSuppressFeed->isChecked());
+ }
+
+ if (!m_creatingNew) {
+ // We need to make sure that common data are saved.
+ QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
+
+ DatabaseQueries::createOverwriteFeed(database, fd, m_serviceRoot->accountId(), fd->parent()->id());
+ }
+ }
if (!m_creatingNew) {
- // We need to make sure that common data are saved.
- QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
-
- DatabaseQueries::createOverwriteFeed(database, m_feed, m_serviceRoot->accountId(), m_feed->parent()->id());
+ m_serviceRoot->itemChanged(feeds());
}
}
+bool FormFeedDetails::isChangeAllowed(MultiFeedEditCheckBox* mcb) const {
+ return !m_isBatchEdit || mcb->isChecked();
+}
+
void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) {
Feed::AutoUpdateType auto_update_type =
- static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt());
+ static_cast(m_ui.m_cmbAutoUpdateType->itemData(new_index).toInt());
switch (auto_update_type) {
case Feed::AutoUpdateType::DontAutoUpdate:
case Feed::AutoUpdateType::DefaultAutoUpdate:
- m_ui->m_spinAutoUpdateInterval->setEnabled(false);
+ m_ui.m_spinAutoUpdateInterval->setEnabled(false);
break;
default:
- m_ui->m_spinAutoUpdateInterval->setEnabled(true);
+ m_ui.m_spinAutoUpdateInterval->setEnabled(true);
}
}
void FormFeedDetails::createConnections() {
- connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormFeedDetails::acceptIfPossible);
- connect(m_ui->m_cmbAutoUpdateType,
+ connect(m_ui.m_buttonBox, &QDialogButtonBox::accepted, this, &FormFeedDetails::acceptIfPossible);
+ connect(m_ui.m_cmbAutoUpdateType,
static_cast(&QComboBox::currentIndexChanged),
this,
&FormFeedDetails::onAutoUpdateTypeChanged);
- connect(m_ui->m_cbAddAnyDateArticles, &QCheckBox::toggled, this, [this](bool checked) {
- m_ui->m_gbAvoidOldArticles->setEnabled(!checked);
+ connect(m_ui.m_cbAddAnyDateArticles, &QCheckBox::toggled, this, [this](bool checked) {
+ m_ui.m_gbAvoidOldArticles->setEnabled(!checked);
});
}
void FormFeedDetails::loadFeedData() {
+ Feed* fd = feed();
+
+ if (m_isBatchEdit) {
+ // We hook batch selectors.
+ m_ui.m_mcbAutoDownloading->addActionWidget(m_ui.m_wdgAutoUpdate);
+ m_ui.m_mcbAddAnyDateArticles->addActionWidget(m_ui.m_cbAddAnyDateArticles);
+ m_ui.m_mcbOpenArticlesAutomatically->addActionWidget(m_ui.m_cbOpenArticlesAutomatically);
+ m_ui.m_mcbAvoidOldArticles->addActionWidget(m_ui.m_gbAvoidOldArticles);
+ m_ui.m_mcbDisableFeed->addActionWidget(m_ui.m_cbDisableFeed);
+ m_ui.m_mcbSuppressFeed->addActionWidget(m_ui.m_cbSuppressFeed);
+ m_ui.m_mcbFeedRtl->addActionWidget(m_ui.m_cbFeedRTL);
+ }
+ else {
+ // We hide batch selectors.
+ for (auto* cb : findChildren()) {
+ cb->hide();
+ }
+ }
+
if (m_creatingNew) {
GuiUtilities::applyDialogProperties(*this,
qApp->icons()->fromTheme(QSL("application-rss+xml")),
tr("Add new feed"));
}
else {
- GuiUtilities::applyDialogProperties(*this, m_feed->fullIcon(), tr("Edit \"%1\"").arg(m_feed->title()));
+ if (!m_isBatchEdit) {
+ GuiUtilities::applyDialogProperties(*this, fd->fullIcon(), tr("Edit \"%1\"").arg(fd->title()));
+ }
+ else {
+ GuiUtilities::applyDialogProperties(*this,
+ qApp->icons()->fromTheme(QSL("application-rss+xml")),
+ tr("Edit %n feeds", nullptr, m_feeds.size()));
+ }
}
- m_ui->m_cmbAutoUpdateType
- ->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(m_feed->autoUpdateType()))));
- m_ui->m_spinAutoUpdateInterval->setValue(m_feed->autoUpdateInterval());
- m_ui->m_cbOpenArticlesAutomatically->setChecked(m_feed->openArticlesDirectly());
- m_ui->m_cbFeedRTL->setChecked(m_feed->isRtl());
- m_ui->m_cbAddAnyDateArticles->setChecked(m_feed->addAnyDatetimeArticles());
- m_ui->m_gbAvoidOldArticles->setChecked(m_feed->datetimeToAvoid().toMSecsSinceEpoch() > 0);
- m_ui->m_dtDateTimeToAvoid->setDateTime(m_feed->datetimeToAvoid());
- m_ui->m_cbDisableFeed->setChecked(m_feed->isSwitchedOff());
- m_ui->m_cbSuppressFeed->setChecked(m_feed->isQuiet());
+ m_ui.m_cmbAutoUpdateType
+ ->setCurrentIndex(m_ui.m_cmbAutoUpdateType->findData(QVariant::fromValue(int(fd->autoUpdateType()))));
+ m_ui.m_spinAutoUpdateInterval->setValue(fd->autoUpdateInterval());
+ m_ui.m_cbOpenArticlesAutomatically->setChecked(fd->openArticlesDirectly());
+ m_ui.m_cbFeedRTL->setChecked(fd->isRtl());
+ m_ui.m_cbAddAnyDateArticles->setChecked(fd->addAnyDatetimeArticles());
+ m_ui.m_gbAvoidOldArticles->setChecked(fd->datetimeToAvoid().toMSecsSinceEpoch() > 0);
+ m_ui.m_dtDateTimeToAvoid->setDateTime(fd->datetimeToAvoid());
+ m_ui.m_cbDisableFeed->setChecked(fd->isSwitchedOff());
+ m_ui.m_cbSuppressFeed->setChecked(fd->isQuiet());
}
void FormFeedDetails::acceptIfPossible() {
@@ -122,19 +181,18 @@ void FormFeedDetails::acceptIfPossible() {
}
void FormFeedDetails::initialize() {
- m_ui.reset(new Ui::FormFeedDetails());
- m_ui->setupUi(this);
+ m_ui.setupUi(this);
- m_ui->m_dtDateTimeToAvoid
+ m_ui.m_dtDateTimeToAvoid
->setDisplayFormat(qApp->localization()->loadedLocale().dateTimeFormat(QLocale::FormatType::ShortFormat));
// Setup auto-update options.
- m_ui->m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds);
- m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
- m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles using global interval"),
- QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate)));
- m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles every"),
- QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate)));
- m_ui->m_cmbAutoUpdateType->addItem(tr("Disable auto-fetching of articles"),
- QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate)));
+ m_ui.m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds);
+ m_ui.m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
+ m_ui.m_cmbAutoUpdateType->addItem(tr("Fetch articles using global interval"),
+ QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate)));
+ m_ui.m_cmbAutoUpdateType->addItem(tr("Fetch articles every"),
+ QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate)));
+ m_ui.m_cmbAutoUpdateType->addItem(tr("Disable auto-fetching of articles"),
+ QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate)));
}
diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.h b/src/librssguard/services/abstract/gui/formfeeddetails.h
index f603810bc..7e08feca8 100644
--- a/src/librssguard/services/abstract/gui/formfeeddetails.h
+++ b/src/librssguard/services/abstract/gui/formfeeddetails.h
@@ -7,6 +7,9 @@
#include "ui_formfeeddetails.h"
+#include "3rd-party/boolinq/boolinq.h"
+#include "definitions/definitions.h"
+
namespace Ui {
class FormFeedDetails;
}
@@ -17,18 +20,23 @@ class Category;
class RootItem;
class FormFeedDetails : public QDialog {
- Q_OBJECT
+ Q_OBJECT
public:
explicit FormFeedDetails(ServiceRoot* service_root, QWidget* parent = nullptr);
virtual ~FormFeedDetails() = default;
- template
- T* addEditFeed(T* feed_to_edit = nullptr);
+ template
+ QList addEditFeed(const QList& feeds_to_edit = {});
- template
+ // Returns first feed.
+ template
T* feed() const;
+ // Returns all feeds.
+ template
+ QList feeds() const;
+
protected slots:
void activateTab(int index);
void clearTabs();
@@ -39,6 +47,7 @@ class FormFeedDetails : public QDialog {
virtual void apply();
protected:
+ bool isChangeAllowed(MultiFeedEditCheckBox* mcb) const;
void insertCustomTab(QWidget* custom_tab, const QString& title, int index);
// Sets the feed which will be edited.
@@ -55,37 +64,49 @@ class FormFeedDetails : public QDialog {
void initialize();
protected:
- QScopedPointer m_ui;
- Feed* m_feed;
+ Ui::FormFeedDetails m_ui;
+ QList m_feeds;
ServiceRoot* m_serviceRoot;
bool m_creatingNew;
+ bool m_isBatchEdit;
};
-template
-inline T* FormFeedDetails::addEditFeed(T* feed_to_edit) {
- m_creatingNew = feed_to_edit == nullptr;
+template
+inline QList FormFeedDetails::addEditFeed(const QList& feeds_to_edit) {
+ m_creatingNew = feeds_to_edit.isEmpty();
+ m_isBatchEdit = feeds_to_edit.size() > 1;
if (m_creatingNew) {
- m_feed = new T();
+ m_feeds.append(new T());
}
else {
- m_feed = feed_to_edit;
+ m_feeds.append(feeds_to_edit);
}
- // Load custom logic for feed data loading.
loadFeedData();
if (exec() == QDialog::DialogCode::Accepted) {
- return feed();
+ return feeds();
}
else {
- return nullptr;
+ return {};
}
}
-template
+template
inline T* FormFeedDetails::feed() const {
- return qobject_cast(m_feed);
+ return qobject_cast(m_feeds.first());
+}
+
+template
+inline QList FormFeedDetails::feeds() const {
+ std::list std_fds = boolinq::from(m_feeds)
+ .select([](Feed* fd) {
+ return qobject_cast(fd);
+ })
+ .toStdList();
+
+ return FROM_STD_LIST(QList, std_fds);
}
#endif // FORMFEEDDETAILS_H
diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.ui b/src/librssguard/services/abstract/gui/formfeeddetails.ui
index 5b77aced4..fd5538426 100644
--- a/src/librssguard/services/abstract/gui/formfeeddetails.ui
+++ b/src/librssguard/services/abstract/gui/formfeeddetails.ui
@@ -24,92 +24,140 @@
Articles
- -
-
-
- Auto-downloading of articles
-
-
- m_cmbAutoUpdateType
-
-
-
- -
-
+
-
+
-
-
-
- Select the auto-download strategy for messages of this feed. Default auto-download strategy means that new messges of this feed will be downloaded in time intervals set in application settings.
-
-
+
-
-
-
- false
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Auto-downloading of articles
+
+
+ m_cmbAutoUpdateType
+
+
+
+ -
+
+
+ Select the auto-download strategy for messages of this feed. Default auto-download strategy means that new messges of this feed will be downloaded in time intervals set in application settings.
+
+
+
+ -
+
+
+ false
+
+
+
+
-
-
-
- Open articles via their URL automatically
-
-
+
+
-
+
+
+ -
+
+
+ Open articles via their URL automatically
+
+
+
+
-
+
+
+ 150
+ 0
+
+
Qt::Horizontal
-
-
-
- Add articles with any date into the database
-
-
+
+
-
+
+
+ -
+
+
+ Add articles with any date into the database
+
+
+
+
-
-
-
- true
-
-
- Avoid adding articles before this date into the database
-
-
- true
-
-
- false
-
-
-
-
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
+
+ -
+
+
+ -
+
+
+ true
+
+
+ Avoid adding articles before this date into the database
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
@@ -118,26 +166,47 @@
Miscellaneous
- -
-
-
- Ignore notifications for this feed
-
-
+
-
+
+
-
+
+
+ -
+
+
+ Ignore notifications for this feed
+
+
+
+
- -
-
-
- Disable this feed
-
-
+
-
+
+
-
+
+
+ -
+
+
+ Disable this feed
+
+
+
+
- -
-
-
- Right-to-left layout
-
-
+
-
+
+
-
+
+
+ -
+
+
+ Right-to-left layout
+
+
+
+
@@ -164,11 +233,13 @@
QDoubleSpinBox
+
+ MultiFeedEditCheckBox
+ QCheckBox
+
+
- m_tabWidget
- m_cmbAutoUpdateType
- m_spinAutoUpdateInterval
m_cbOpenArticlesAutomatically
m_cbAddAnyDateArticles
m_gbAvoidOldArticles
diff --git a/src/librssguard/services/abstract/gui/multifeededitcheckbox.cpp b/src/librssguard/services/abstract/gui/multifeededitcheckbox.cpp
new file mode 100644
index 000000000..388c616a1
--- /dev/null
+++ b/src/librssguard/services/abstract/gui/multifeededitcheckbox.cpp
@@ -0,0 +1,22 @@
+// For license of this file, see /LICENSE.md.
+
+#include "services/abstract/gui/multifeededitcheckbox.h"
+
+MultiFeedEditCheckBox::MultiFeedEditCheckBox(QWidget* parent) : QCheckBox(parent) {
+ setToolTip(tr("Apply this to all edited feeds."));
+ setText(QString(4, ' '));
+ setSizePolicy(QSizePolicy::Policy::Maximum, QSizePolicy::Policy::Maximum);
+}
+
+QList MultiFeedEditCheckBox::actionWidgets() const {
+ return m_actionWidgets;
+}
+
+void MultiFeedEditCheckBox::addActionWidget(QWidget* widget) {
+ if (widget != nullptr) {
+ m_actionWidgets.append(widget);
+ connect(this, &MultiFeedEditCheckBox::toggled, widget, &QWidget::setEnabled);
+
+ emit toggled(isChecked());
+ }
+}
diff --git a/src/librssguard/services/abstract/gui/multifeededitcheckbox.h b/src/librssguard/services/abstract/gui/multifeededitcheckbox.h
new file mode 100644
index 000000000..835ecde3b
--- /dev/null
+++ b/src/librssguard/services/abstract/gui/multifeededitcheckbox.h
@@ -0,0 +1,21 @@
+// For license of this file, see /LICENSE.md.
+
+#ifndef MULTIFEEDEDITCHECKBOX_H
+#define MULTIFEEDEDITCHECKBOX_H
+
+#include
+
+class MultiFeedEditCheckBox : public QCheckBox {
+ Q_OBJECT
+
+ public:
+ explicit MultiFeedEditCheckBox(QWidget* parent = nullptr);
+
+ QList actionWidgets() const;
+ void addActionWidget(QWidget* widget);
+
+ private:
+ QList m_actionWidgets;
+};
+
+#endif // MULTIFEEDEDITCHECKBOX_H
diff --git a/src/librssguard/services/abstract/label.cpp b/src/librssguard/services/abstract/label.cpp
index 8791a4845..24dfa8823 100644
--- a/src/librssguard/services/abstract/label.cpp
+++ b/src/librssguard/services/abstract/label.cpp
@@ -43,19 +43,6 @@ bool Label::canBeEdited() const {
return Globals::hasFlag(getParentServiceRoot()->supportedLabelOperations(), ServiceRoot::LabelOperation::Editing);
}
-bool Label::editViaGui() {
- FormAddEditLabel form(qApp->mainFormWidget());
-
- if (form.execForEdit(this)) {
- QSqlDatabase db = qApp->database()->driver()->connection(metaObject()->className());
-
- return DatabaseQueries::updateLabel(db, this);
- }
- else {
- return false;
- }
-}
-
bool Label::canBeDeleted() const {
return Globals::hasFlag(getParentServiceRoot()->supportedLabelOperations(), ServiceRoot::LabelOperation::Deleting);
}
diff --git a/src/librssguard/services/abstract/label.h b/src/librssguard/services/abstract/label.h
index d6358087b..bf32acdf8 100644
--- a/src/librssguard/services/abstract/label.h
+++ b/src/librssguard/services/abstract/label.h
@@ -28,7 +28,6 @@ class RSSGUARD_DLLSPEC Label : public RootItem {
virtual int countOfAllMessages() const;
virtual int countOfUnreadMessages() const;
virtual bool canBeEdited() const;
- virtual bool editViaGui();
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
virtual void updateCounts(bool including_total_count);
diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp
index d1a836ad0..db48bcecd 100644
--- a/src/librssguard/services/abstract/rootitem.cpp
+++ b/src/librssguard/services/abstract/rootitem.cpp
@@ -59,10 +59,6 @@ bool RootItem::canBeEdited() const {
return false;
}
-bool RootItem::editViaGui() {
- return false;
-}
-
bool RootItem::canBeDeleted() const {
return false;
}
diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h
index 748519d13..182d34eda 100644
--- a/src/librssguard/services/abstract/rootitem.h
+++ b/src/librssguard/services/abstract/rootitem.h
@@ -28,11 +28,19 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
Q_PROPERTY(QString customId READ customId)
public:
- enum class ReadStatus { Unread = 0, Read = 1, Unknown = 256 };
+ enum class ReadStatus {
+ Unread = 0,
+ Read = 1,
+ Unknown = 256
+ };
// Holds statuses for messages
// to be switched importance (starred).
- enum class Importance { NotImportant = 0, Important = 1, Unknown = 256 };
+ enum class Importance {
+ NotImportant = 0,
+ Important = 1,
+ Unknown = 256
+ };
// Describes the kind of the item.
enum class Kind {
@@ -66,10 +74,6 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
// Can properties of this item be edited?
virtual bool canBeEdited() const;
- // Performs editing of properties of this item (probably via dialog)
- // and returns result status.
- virtual bool editViaGui();
-
// Can the item be deleted?
virtual bool canBeDeleted() const;
diff --git a/src/librssguard/services/abstract/search.cpp b/src/librssguard/services/abstract/search.cpp
index a5141229b..342ec6390 100644
--- a/src/librssguard/services/abstract/search.cpp
+++ b/src/librssguard/services/abstract/search.cpp
@@ -44,28 +44,6 @@ bool Search::canBeEdited() const {
return true;
}
-bool Search::editViaGui() {
- FormAddEditProbe form(qApp->mainFormWidget());
-
- if (form.execForEdit(this)) {
- QSqlDatabase db = qApp->database()->driver()->connection(metaObject()->className());
-
- try {
- DatabaseQueries::updateProbe(db, this);
- updateCounts(true);
- getParentServiceRoot()->itemChanged({this});
- return true;
- }
- catch (const ApplicationException& ex) {
- qCriticalNN << LOGSEC_CORE << "Failed to edit probe:" << QUOTE_W_SPACE_DOT(ex.message());
- return false;
- }
- }
- else {
- return true;
- }
-}
-
bool Search::canBeDeleted() const {
return true;
}
diff --git a/src/librssguard/services/abstract/search.h b/src/librssguard/services/abstract/search.h
index e9a89898f..56b0e7fe4 100644
--- a/src/librssguard/services/abstract/search.h
+++ b/src/librssguard/services/abstract/search.h
@@ -32,7 +32,6 @@ class RSSGUARD_DLLSPEC Search : public RootItem {
virtual int countOfAllMessages() const;
virtual int countOfUnreadMessages() const;
virtual bool canBeEdited() const;
- virtual bool editViaGui();
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
virtual void updateCounts(bool including_total_count);
diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp
index b2a8f2293..8e6344ab2 100644
--- a/src/librssguard/services/abstract/serviceroot.cpp
+++ b/src/librssguard/services/abstract/serviceroot.cpp
@@ -14,6 +14,11 @@
#include "services/abstract/category.h"
#include "services/abstract/feed.h"
#include "services/abstract/gui/custommessagepreviewer.h"
+#include "services/abstract/gui/formaccountdetails.h"
+#include "services/abstract/gui/formaddeditlabel.h"
+#include "services/abstract/gui/formaddeditprobe.h"
+#include "services/abstract/gui/formcategorydetails.h"
+#include "services/abstract/gui/formfeeddetails.h"
#include "services/abstract/importantnode.h"
#include "services/abstract/labelsnode.h"
#include "services/abstract/recyclebin.h"
@@ -44,6 +49,95 @@ bool ServiceRoot::deleteViaGui() {
}
}
+void ServiceRoot::editItemsViaGui(const QList& items) {
+ // Feed editing.
+ auto std_feeds = boolinq::from(items)
+ .select([](RootItem* it) {
+ return qobject_cast(it);
+ })
+ .where([](Feed* fd) {
+ return fd != nullptr;
+ })
+ .toStdList();
+
+ if (!std_feeds.empty()) {
+ QScopedPointer form_pointer(new FormFeedDetails(this, qApp->mainFormWidget()));
+
+ form_pointer->addEditFeed(FROM_STD_LIST(QList, std_feeds));
+ return;
+ }
+
+ // Category editing.
+ auto std_categories = boolinq::from(items)
+ .select([](RootItem* it) {
+ return qobject_cast(it);
+ })
+ .where([](Category* fd) {
+ return fd != nullptr;
+ })
+ .toStdList();
+
+ if (!std_categories.empty()) {
+ QScopedPointer form_pointer(new FormCategoryDetails(this, nullptr, qApp->mainFormWidget()));
+
+ form_pointer->addEditCategory(FROM_STD_LIST(QList, std_categories));
+ return;
+ }
+
+ // Label editing.
+ auto std_labels = boolinq::from(items)
+ .select([](RootItem* it) {
+ return qobject_cast
@@ -15,14 +15,21 @@
-
-
-
- Parent folder
-
-
- m_cmbParentCategory
-
-
+
+
-
+
+
+ -
+
+
+ Parent folder
+
+
+ m_cmbParentCategory
+
+
+
+
-
@@ -41,14 +48,21 @@
-
-
-
- Type
-
-
- m_cmbType
-
-
+
+
-
+
+
+ -
+
+
+ Type
+
+
+ m_cmbType
+
+
+
+
-
@@ -59,6 +73,9 @@
+ -
+
+
-
@@ -69,45 +86,66 @@
-
-
-
- Title
-
-
- m_txtTitle
-
-
+
+
-
+
+
+ -
+
+
+ Title
+
+
+ m_txtTitle
+
+
+
+
-
-
-
-
- Description
-
-
- m_txtDescription
-
-
+
+
-
+
+
+ -
+
+
+ Description
+
+
+ m_txtDescription
+
+
+
+
-
-
-
-
- Source
-
-
- m_txtSource
-
-
+
+
-
+
+
+ -
+
+
+ Source
+
+
+ m_txtSource
+
+
+
+
-
- -
+
-
@@ -124,14 +162,21 @@
-
-
-
- Post-processing script
-
-
- m_txtPostProcessScript
-
-
+
+
-
+
+
+ -
+
+
+ Post-processing script
+
+
+ m_txtPostProcessScript
+
+
+
+
-
@@ -187,14 +232,21 @@
-
-
-
- Icon
-
-
- m_btnIcon
-
-
+
+
-
+
+
+ -
+
+
+ Icon
+
+
+ m_btnIcon
+
+
+
+
-
@@ -246,9 +298,17 @@
+ -
+
+
+
+ MultiFeedEditCheckBox
+ QCheckBox
+
+
HelpSpoiler
QWidget
diff --git a/src/librssguard/services/standard/standardcategory.cpp b/src/librssguard/services/standard/standardcategory.cpp
index 88326728f..7aff840f3 100644
--- a/src/librssguard/services/standard/standardcategory.cpp
+++ b/src/librssguard/services/standard/standardcategory.cpp
@@ -47,15 +47,6 @@ bool StandardCategory::canBeDeleted() const {
return true;
}
-bool StandardCategory::editViaGui() {
- QScopedPointer form_pointer(new FormCategoryDetails(serviceRoot(),
- nullptr,
- qApp->mainFormWidget()));
-
- form_pointer->addEditCategory(this);
- return false;
-}
-
bool StandardCategory::deleteViaGui() {
if (removeItself()) {
serviceRoot()->requestItemRemoval(this);
diff --git a/src/librssguard/services/standard/standardcategory.h b/src/librssguard/services/standard/standardcategory.h
index db952c09f..ab824b3b8 100644
--- a/src/librssguard/services/standard/standardcategory.h
+++ b/src/librssguard/services/standard/standardcategory.h
@@ -10,7 +10,7 @@
class StandardServiceRoot;
class StandardCategory : public Category {
- Q_OBJECT
+ Q_OBJECT
public:
explicit StandardCategory(RootItem* parent_item = nullptr);
@@ -21,7 +21,6 @@ class StandardCategory : public Category {
virtual Qt::ItemFlags additionalFlags() const;
virtual bool performDragDropChange(RootItem* target_item);
virtual bool canBeEdited() const;
- virtual bool editViaGui();
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp
index 023ec1561..6046ea9ca 100644
--- a/src/librssguard/services/standard/standardfeed.cpp
+++ b/src/librssguard/services/standard/standardfeed.cpp
@@ -78,19 +78,6 @@ StandardServiceRoot* StandardFeed::serviceRoot() const {
return qobject_cast(getParentServiceRoot());
}
-bool StandardFeed::editViaGui() {
- QScopedPointer form_pointer(new FormStandardFeedDetails(serviceRoot(),
- nullptr,
- {},
- qApp->mainFormWidget()));
-
- if (form_pointer->addEditFeed(this) != nullptr) {
- setLastEtag({});
- }
-
- return false;
-}
-
bool StandardFeed::deleteViaGui() {
if (removeItself()) {
serviceRoot()->requestItemRemoval(this);
diff --git a/src/librssguard/services/standard/standardfeed.h b/src/librssguard/services/standard/standardfeed.h
index 755cbdbc0..58548d7a8 100644
--- a/src/librssguard/services/standard/standardfeed.h
+++ b/src/librssguard/services/standard/standardfeed.h
@@ -46,7 +46,6 @@ class StandardFeed : public Feed {
virtual QString additionalTooltip() const;
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
- virtual bool editViaGui();
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual Qt::ItemFlags additionalFlags() const;
diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp
index 3695de269..4ab10c9a6 100644
--- a/src/librssguard/services/standard/standardserviceroot.cpp
+++ b/src/librssguard/services/standard/standardserviceroot.cpp
@@ -113,11 +113,38 @@ bool StandardServiceRoot::canBeEdited() const {
return true;
}
-bool StandardServiceRoot::editViaGui() {
- FormEditStandardAccount form_pointer(qApp->mainFormWidget());
+FormAccountDetails* StandardServiceRoot::accountSetupDialog() const {
+ return new FormEditStandardAccount(qApp->mainFormWidget());
+}
- form_pointer.addEditAccount(this);
- return true;
+void StandardServiceRoot::editItemsViaGui(const QList& items) {
+ auto std_feeds = boolinq::from(items)
+ .select([](RootItem* it) {
+ return qobject_cast(it);
+ })
+ .where([](Feed* fd) {
+ return fd != nullptr;
+ })
+ .toStdList();
+
+ if (!std_feeds.empty()) {
+ QScopedPointer form_pointer(new FormStandardFeedDetails(this,
+ nullptr,
+ {},
+ qApp->mainFormWidget()));
+
+ form_pointer->addEditFeed(FROM_STD_LIST(QList, std_feeds));
+ return;
+ }
+
+ if (items.first()->kind() == RootItem::Kind::ServiceRoot) {
+ QScopedPointer p(qobject_cast(accountSetupDialog()));
+
+ p->addEditAccount(this);
+ return;
+ }
+
+ ServiceRoot::editItemsViaGui(items);
}
bool StandardServiceRoot::supportsFeedAdding() const {
diff --git a/src/librssguard/services/standard/standardserviceroot.h b/src/librssguard/services/standard/standardserviceroot.h
index 95f2fc7bf..5430ada24 100644
--- a/src/librssguard/services/standard/standardserviceroot.h
+++ b/src/librssguard/services/standard/standardserviceroot.h
@@ -24,12 +24,13 @@ class StandardServiceRoot : public ServiceRoot {
explicit StandardServiceRoot(RootItem* parent = nullptr);
virtual ~StandardServiceRoot();
+ virtual FormAccountDetails* accountSetupDialog() const;
virtual void onDatabaseCleanup();
virtual void start(bool freshly_activated);
virtual void stop();
virtual QString code() const;
virtual bool canBeEdited() const;
- virtual bool editViaGui();
+ virtual void editItemsViaGui(const QList& items);
virtual bool supportsFeedAdding() const;
virtual bool supportsCategoryAdding() const;
virtual Qt::ItemFlags additionalFlags() const;
diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp
index b3f9571b1..c8f716181 100644
--- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp
+++ b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp
@@ -75,11 +75,19 @@ bool TtRssServiceRoot::isSyncable() const {
return true;
}
-bool TtRssServiceRoot::editViaGui() {
- QScopedPointer form_pointer(new FormEditTtRssAccount(qApp->mainFormWidget()));
+FormAccountDetails* TtRssServiceRoot::accountSetupDialog() const {
+ return new FormEditTtRssAccount(qApp->mainFormWidget());
+}
- form_pointer->addEditAccount(this);
- return true;
+void TtRssServiceRoot::editItemsViaGui(const QList& items) {
+ if (items.first()->kind() == RootItem::Kind::ServiceRoot) {
+ QScopedPointer p(qobject_cast(accountSetupDialog()));
+
+ p->addEditAccount(this);
+ return;
+ }
+
+ ServiceRoot::editItemsViaGui(items);
}
bool TtRssServiceRoot::supportsFeedAdding() const {
diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.h b/src/librssguard/services/tt-rss/ttrssserviceroot.h
index bf8171370..c4ce702d4 100644
--- a/src/librssguard/services/tt-rss/ttrssserviceroot.h
+++ b/src/librssguard/services/tt-rss/ttrssserviceroot.h
@@ -26,7 +26,8 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual QString code() const;
virtual bool isSyncable() const;
virtual bool canBeEdited() const;
- virtual bool editViaGui();
+ virtual void editItemsViaGui(const QList& items);
+ virtual FormAccountDetails* accountSetupDialog() const;
virtual bool supportsFeedAdding() const;
virtual bool supportsCategoryAdding() const;
virtual void addNewFeed(RootItem* selected_item, const QString& url = QString());