diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index 4d3f9db79..3c575bea3 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -30,7 +30,7 @@ https://martinrotter.github.io/donate/ - + none diff --git a/resources/docs/Documentation.md b/resources/docs/Documentation.md index e8f06f480..da2650049 100644 --- a/resources/docs/Documentation.md +++ b/resources/docs/Documentation.md @@ -11,6 +11,7 @@ * [RSS Guard 3 vs. RSS Guard 4](#rss-guard-3-vs-rss-guard-4) * [Features](#features) * [List of main features](#list-of-main-features) + * [Core concepts](#core-concepts) * [Supported feed formats and online feed services](Feed-formats.md) * [Message filtering](Message-filters.md) * [Database backends](#database-backends) @@ -120,8 +121,7 @@ RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most kno * support for all feed formats (RSS/RDF/ATOM/JSON), * full support of podcasts (RSS/ATOM/JSON), * import/export of feeds to/from OPML 2.0, - * universal plugin for online services with [Google Reader API](#google-reader-api), - * possibility of using custom 3rd-party feed synchronization services, + * possibility of using custom 3rd-party feed [synchronization services](Feed-formats.md), * feed metadata fetching including icons, * support for [scraping websites](#websites-scraping) which do not offer RSS/ATOM feeds and other related advanced features, * simple internal Chromium-based web viewer (or alternative version with simpler and much more lightweight internal viewer), @@ -144,7 +144,6 @@ RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most kno * support for `feed://` URI scheme. * user interface: * message list filter with regular expressions, - * drag-n-drop for feed list, * able to show unread feeds/messages only, * can be controlled via keyboard, * fully adjustable toolbars (changeable buttons and style), @@ -155,9 +154,18 @@ RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most kno * tabbed interface, * ability to hide list of feeds/categories, * desktop integration via tray icon, - * localizations to some languages, + * localizations to many languages, * ability to tweak columns in displayed list of messages. +## Core concepts +RSS Guard is multi-protocol and multi-account application. If you start it for the first time, `Add account` dialog will pop-up. + + + +You can also display this dialog from main menu `Accounts -> Add new account`. + +You must have added some account to start using RSS Guard. Each account provides access to some specific online service while `Standard online feeds` account is there to provide access to classic `RSS` and `ATOM` feeds. You can have activated many accounts in the same time and even multiple accounts of the same type, for example two distinct `Gmail` accounts. + ## Database backends RSS Guard offers switchable database backends which hold your data. At this point, two backends are available: * MariaDB, @@ -187,7 +195,6 @@ Note that even when all Google Reader API enabled services should follow the API For example The Old Reader does not seem to offer tags/labels functionality, therefore tags/labels in RSS Guard are not synchronized, but you can still use offline labels. ## Websites scraping - > **Only proceed if you consider yourself to be a power user and you know what you are doing!** RSS Guard 3.9.0+ offers extra advanced features which are inspired by [Liferea](https://lzone.de/liferea/). diff --git a/resources/docs/Downloads.md b/resources/docs/Downloads.md index 2f63370ef..6047ba025 100755 --- a/resources/docs/Downloads.md +++ b/resources/docs/Downloads.md @@ -12,7 +12,7 @@ Official downloads are available [here](https://github.com/martinrotter/rssguard Development builds can be downloaded [here](https://github.com/martinrotter/rssguard/releases/tag/devbuild). ## Installation packages naming -**Windows builds** of RSS Guard are generated automatically by the tool called AppVeyor. These builds have auto-generated names. In RSS Guard [downloads page](https://github.com/martinrotter/rssguard/releases) you can see filenames like: +**All builds** of RSS Guard are generated automatically by GitHub. These builds have auto-generated names. In RSS Guard [downloads page](https://github.com/martinrotter/rssguard/releases) you can see filenames like: * `rssguard-3.4.2-7bad9d1-nowebengine-win32.7z`, * `rssguard-3.4.2-7bad9d1-win32.7z`, * `rssguard-3.4.2-95ee6be-nowebengine-win32.exe`, @@ -25,4 +25,6 @@ The structure of these filenames is quite trivial and easily understandable for * `` = `win32` (This is the target platform which the application can run on.), * `` = `exe` (This is self-explanatory.). -Note that same file naming scheme for development builds might be little different. Specifically, `` field is omitted. \ No newline at end of file +Note that same file naming scheme for development builds might be little different. Specifically, `` field is omitted. + +If you use `7z` packages on Windows, then you need to manually install all needed MSVC++ runtime libraries. Their installers are included inside the archive. \ No newline at end of file diff --git a/resources/docs/images/add-acc.png b/resources/docs/images/add-acc.png new file mode 100755 index 000000000..0f46df137 Binary files /dev/null and b/resources/docs/images/add-acc.png differ diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index 34129fc4b..29814a4fc 100755 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -190,6 +190,7 @@ QList FormMain::allActions() const { actions << m_ui->m_actionSelectPreviousMessage; actions << m_ui->m_actionSelectNextUnreadMessage; actions << m_ui->m_actionExpandCollapseItem; + actions << m_ui->m_actionExpandCollapseItemRecursively; actions << m_ui->m_actionMessageFilters; #if defined(USE_WEBENGINE) @@ -448,7 +449,8 @@ void FormMain::updateFeedButtonsAvailability() { m_ui->m_actionUpdateSelectedItemsWithCustomTimers->setEnabled(!critical_action_running); m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(anything_selected); - m_ui->m_actionExpandCollapseItem->setEnabled(anything_selected); + m_ui->m_actionExpandCollapseItem->setEnabled(category_selected || service_selected); + m_ui->m_actionExpandCollapseItemRecursively->setEnabled(category_selected || service_selected); m_ui->m_actionServiceDelete->setEnabled(service_selected); m_ui->m_actionServiceEdit->setEnabled(service_selected); m_ui->m_actionAddFeedIntoSelectedItem->setEnabled(anything_selected); @@ -545,6 +547,7 @@ void FormMain::setupIcons() { m_ui->m_actionShowOnlyUnreadItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionShowOnlyUnreadMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionExpandCollapseItem->setIcon(icon_theme_factory->fromTheme(QSL("format-indent-more"))); + m_ui->m_actionExpandCollapseItemRecursively->setIcon(icon_theme_factory->fromTheme(QSL("format-indent-more"))); m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("view-refresh"))); m_ui->m_actionRestoreAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("view-refresh"))); m_ui->m_actionEmptyAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("edit-clear"))); @@ -741,7 +744,17 @@ void FormMain::createConnections() { connect(m_ui->m_actionMarkSelectedItemsAsRead, &QAction::triggered, tabWidget()->feedMessageViewer()->feedsView(), &FeedsView::markSelectedItemRead); connect(m_ui->m_actionExpandCollapseItem, - &QAction::triggered, tabWidget()->feedMessageViewer()->feedsView(), &FeedsView::expandCollapseCurrentItem); + &QAction::triggered, + tabWidget()->feedMessageViewer()->feedsView(), + [this]() { + tabWidget()->feedMessageViewer()->feedsView()->expandCollapseCurrentItem(false); + }); + connect(m_ui->m_actionExpandCollapseItemRecursively, + &QAction::triggered, + tabWidget()->feedMessageViewer()->feedsView(), + [this]() { + tabWidget()->feedMessageViewer()->feedsView()->expandCollapseCurrentItem(true); + }); connect(m_ui->m_actionMarkSelectedItemsAsUnread, &QAction::triggered, tabWidget()->feedMessageViewer()->feedsView(), &FeedsView::markSelectedItemUnread); connect(m_ui->m_actionClearSelectedItems, diff --git a/src/librssguard/gui/dialogs/formmain.ui b/src/librssguard/gui/dialogs/formmain.ui index 43edc1194..a256b44c1 100755 --- a/src/librssguard/gui/dialogs/formmain.ui +++ b/src/librssguard/gui/dialogs/formmain.ui @@ -120,6 +120,7 @@ + @@ -805,6 +806,11 @@ Message viewer toolbars + + + Expand/collapse selected item &recursively + + diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp index 6e245f8a7..3a76164d1 100755 --- a/src/librssguard/gui/feedsview.cpp +++ b/src/librssguard/gui/feedsview.cpp @@ -191,7 +191,7 @@ void FeedsView::addCategoryIntoSelectedAccount() { } } -void FeedsView::expandCollapseCurrentItem() { +void FeedsView::expandCollapseCurrentItem(bool recursive) { if (selectionModel()->selectedRows().size() == 1) { QModelIndex index = selectionModel()->selectedRows().at(0); @@ -200,7 +200,32 @@ void FeedsView::expandCollapseCurrentItem() { index = index.parent(); } - isExpanded(index) ? collapse(index) : expand(index); + if (recursive) { + QList to_process = { index }; + bool expa = !isExpanded(index); + + while (!to_process.isEmpty()) { + auto idx = to_process.takeFirst(); + + if (idx.isValid()) { + setExpanded(idx, expa); + + for (int i = 0; i < m_proxyModel->rowCount(idx); i++) { + auto new_idx = m_proxyModel->index(i, 0, idx); + + if (new_idx.isValid()) { + to_process << new_idx; + } + } + } + else { + break; + } + } + } + else { + isExpanded(index) ? collapse(index) : expand(index); + } } } @@ -460,14 +485,15 @@ QMenu* FeedsView::initializeContextMenuService(RootItem* clicked_item) { QList specific_actions = clicked_item->contextMenuFeedsList(); - m_contextMenuService->addActions(QList() << - qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << - qApp->mainForm()->m_ui->m_actionEditSelectedItem << - qApp->mainForm()->m_ui->m_actionCopyUrlSelectedFeed << - qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << - qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << - qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << - qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); + m_contextMenuService->addActions({ qApp->mainForm()->m_ui->m_actionUpdateSelectedItems, + qApp->mainForm()->m_ui->m_actionEditSelectedItem, + qApp->mainForm()->m_ui->m_actionCopyUrlSelectedFeed, + qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode, + qApp->mainForm()->m_ui->m_actionExpandCollapseItem, + qApp->mainForm()->m_ui->m_actionExpandCollapseItemRecursively, + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead, + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread, + qApp->mainForm()->m_ui->m_actionDeleteSelectedItem }); auto cat_add = clicked_item->getParentServiceRoot()->supportsCategoryAdding(); auto feed_add = clicked_item->getParentServiceRoot()->supportsFeedAdding(); @@ -545,14 +571,15 @@ QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) { QList specific_actions = clicked_item->contextMenuFeedsList(); - m_contextMenuCategories->addActions(QList() << - qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << - qApp->mainForm()->m_ui->m_actionEditSelectedItem << - qApp->mainForm()->m_ui->m_actionCopyUrlSelectedFeed << - qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << - qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << - qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << - qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); + m_contextMenuCategories->addActions({ qApp->mainForm()->m_ui->m_actionUpdateSelectedItems, + qApp->mainForm()->m_ui->m_actionEditSelectedItem, + qApp->mainForm()->m_ui->m_actionCopyUrlSelectedFeed, + qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode, + qApp->mainForm()->m_ui->m_actionExpandCollapseItem, + qApp->mainForm()->m_ui->m_actionExpandCollapseItemRecursively, + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead, + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread, + qApp->mainForm()->m_ui->m_actionDeleteSelectedItem }); auto cat_add = clicked_item->getParentServiceRoot()->supportsCategoryAdding(); auto feed_add = clicked_item->getParentServiceRoot()->supportsFeedAdding(); diff --git a/src/librssguard/gui/feedsview.h b/src/librssguard/gui/feedsview.h index 2bd7c0ab3..debb5a6d0 100755 --- a/src/librssguard/gui/feedsview.h +++ b/src/librssguard/gui/feedsview.h @@ -45,7 +45,7 @@ class RSSGUARD_DLLSPEC FeedsView : public QTreeView { void addFeedIntoSelectedAccount(); void addCategoryIntoSelectedAccount(); - void expandCollapseCurrentItem(); + void expandCollapseCurrentItem(bool recursive); // Feed updating. void updateSelectedItems();