Experimentally fixed #52.

This commit is contained in:
Martin Rotter 2015-07-16 09:18:07 +02:00
parent 41c239ff03
commit 1e12713a1a
11 changed files with 140 additions and 4 deletions

View File

@ -1,7 +1,29 @@
<body>
<style>
body {
font-size: 150%;
}
ul {
list-style-type: square;
}
ul > li {
margin-top: 3px;
margin-bottom: 3px;
}
</style>
<center><h2>2.5.0</h2></center>
Added:
<ul>
<li>Implemented ability to display <b>ONLY FEEDS WITH SOME UNREAD MESSAGES</b>. This behavior can be controlled by action in menu 'Feeds -> Show only unread feeds/categories' (issue #52). Behavior is this:
<ol>
<li>User selects some feeds with unread messages, reads them all.</li>
<li>User switches to another feed.</li>
<li>Previously selected feed (now has no unread messages) is now hidden.</li>
</ol>
Note that this feature also works when you e.g. mark message(s) as read/unread or when you restore some messages from recycle bin. Also when feeds are updated, then filter is invalidated.
</li>
<li><b>Password in feeds & proxy & MySQL are now saved in encrypted form. This means that all passwords from RSS Guard older than 2.5.0 are lost!!! Set your passwords again.</b> Used encryption scheme is meant to only make sure that passwords are not stored in DB/settings in plain form. It is not meant to protect your passwords in any broader way. Attacker can exploit your passwords if he really wants.</li>
<li><b>Fancy & modern popup notifications</b> (turned on by default).</li>
<li>Enhanced information in download manager.</li>

View File

@ -94,6 +94,10 @@ class FeedsModelRootItem {
// Checks whether THIS object is child (direct or indirect)
// of the given root.
bool isChildOf(FeedsModelRootItem *root) {
if (root == NULL) {
return false;
}
FeedsModelRootItem *this_item = this;
while (this_item->kind() != FeedsModelRootItem::RootItem) {
@ -108,6 +112,15 @@ class FeedsModelRootItem {
return false;
}
bool isParentOf(FeedsModelRootItem *child) {
if (child == NULL) {
return false;
}
else {
return child->isChildOf(this);
}
}
// Removes all children from this item.
// NOTE: Children are NOT freed from the memory.
inline void clearChildren() {

View File

@ -25,7 +25,7 @@
FeedsProxyModel::FeedsProxyModel(QObject *parent)
: QSortFilterProxyModel(parent) {
: QSortFilterProxyModel(parent), m_selectedItem(NULL), m_showUnreadOnly(false) {
m_sourceModel = new FeedsModel(this);
setObjectName(QSL("FeedsProxyModel"));
@ -34,7 +34,7 @@ FeedsProxyModel::FeedsProxyModel(QObject *parent)
setFilterCaseSensitivity(Qt::CaseInsensitive);
setFilterKeyColumn(-1);
setFilterRole(Qt::EditRole);
setDynamicSortFilter(true);
setDynamicSortFilter(false);
setSourceModel(m_sourceModel);
}
@ -180,7 +180,53 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right
}
bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
if (!m_showUnreadOnly) {
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
// TODO: učechrat
QModelIndex idx = m_sourceModel->index(source_row, 0, source_parent);
if (!idx.isValid()) {
return false;
}
FeedsModelRootItem *item = m_sourceModel->itemForIndex(idx);
if (item->kind() == FeedsModelRootItem::RecycleBin) {
// Recycle bin is always displayed.
return true;
}
/*
if (m_selectedItem == NULL) {
return item->countOfUnreadMessages() > 0;
}
*/
if (item->isParentOf(m_selectedItem)/* || item->isChildOf(m_selectedItem)*/ || m_selectedItem == item) {
// Currently selected item and all its parents and children must be displayed.
return true;
}
else {
return item->countOfUnreadMessages() > 0;
}
}
FeedsModelRootItem *FeedsProxyModel::selectedItem() const {
return m_selectedItem;
}
void FeedsProxyModel::setSelectedItem(FeedsModelRootItem *selectedItem) {
m_selectedItem = selectedItem;
}
bool FeedsProxyModel::showUnreadOnly() const {
return m_showUnreadOnly;
}
void FeedsProxyModel::setShowUnreadOnly(bool showUnreadOnly) {
m_showUnreadOnly = showUnreadOnly;
}
QModelIndexList FeedsProxyModel::mapListToSource(const QModelIndexList &indexes) {

View File

@ -18,6 +18,8 @@
#ifndef FEEDSPROXYMODEL_H
#define FEEDSPROXYMODEL_H
#include "feedsmodelrootitem.h"
#include <QSortFilterProxyModel>
@ -41,6 +43,12 @@ class FeedsProxyModel : public QSortFilterProxyModel {
// Maps list of indexes.
QModelIndexList mapListToSource(const QModelIndexList &indexes);
bool showUnreadOnly() const;
void setShowUnreadOnly(bool showUnreadOnly);
FeedsModelRootItem *selectedItem() const;
void setSelectedItem(FeedsModelRootItem *selectedItem);
public slots:
void invalidateFilter();
@ -52,6 +60,9 @@ class FeedsProxyModel : public QSortFilterProxyModel {
private:
// Source model pointer.
FeedsModel *m_sourceModel;
FeedsModelRootItem *m_selectedItem;
bool m_showUnreadOnly;
};
#endif // FEEDSPROXYMODEL_H

View File

@ -276,6 +276,7 @@ void FormMain::setupIcons() {
m_ui->m_actionSelectPreviousFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("go-up")));
m_ui->m_actionSelectNextMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-down")));
m_ui->m_actionSelectPreviousMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-up")));
m_ui->m_actionShowOnlyUnreadFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread")));
// Setup icons for underlying components: opened web browsers...
foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) {

View File

@ -144,6 +144,8 @@
<addaction name="m_actionEditSelectedFeedCategory"/>
<addaction name="m_actionDeleteSelectedFeedCategory"/>
<addaction name="separator"/>
<addaction name="m_actionShowOnlyUnreadFeeds"/>
<addaction name="separator"/>
<addaction name="m_actionSelectNextFeedCategory"/>
<addaction name="m_actionSelectPreviousFeedCategory"/>
<addaction name="separator"/>
@ -649,6 +651,17 @@
<string notr="true">Ctrl+Shift+Del</string>
</property>
</action>
<action name="m_actionShowOnlyUnreadFeeds">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show only unread feeds/categories</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+U</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -276,6 +276,10 @@ void FeedMessageViewer::switchFeedComponentVisibility() {
m_feedsWidget->setVisible(!m_feedsWidget->isVisible());
}
void FeedMessageViewer::toggleShowOnlyUnreadFeeds() {
m_feedsView->invalidateReadFeedsFilter(true, qobject_cast<QAction*>(sender())->isChecked());
}
void FeedMessageViewer::updateMessageButtonsAvailability() {
bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1;
bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty();
@ -423,6 +427,8 @@ void FeedMessageViewer::createConnections() {
SIGNAL(triggered()), m_messagesView, SLOT(selectPreviousItem()));
connect(form_main->m_ui->m_actionSwitchMessageListOrientation, SIGNAL(triggered()),
this, SLOT(switchMessageSplitterOrientation()));
connect(form_main->m_ui->m_actionShowOnlyUnreadFeeds, SIGNAL(toggled(bool)),
this, SLOT(toggleShowOnlyUnreadFeeds()));
}
void FeedMessageViewer::initialize() {

View File

@ -118,6 +118,8 @@ class FeedMessageViewer : public TabContent {
// toolbar.
void switchFeedComponentVisibility();
void toggleShowOnlyUnreadFeeds();
void updateMessageButtonsAvailability();
void updateFeedButtonsAvailability();

View File

@ -165,6 +165,14 @@ void FeedsView::loadExpandedStates() {
}
}
void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) {
if (set_new_value) {
m_proxyModel->setShowUnreadOnly(show_unread_only);
}
QTimer::singleShot(0, m_proxyModel, SLOT(invalidateFilter()));
}
void FeedsView::updateAllFeeds() {
emit feedsUpdateRequested(allFeeds());
}
@ -329,6 +337,9 @@ void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode,
else {
updateCountsOfSelectedFeeds(total_msg_count_changed);
}
// TODO: učechrat
invalidateReadFeedsFilter();
}
void FeedsView::editSelectedItem() {
@ -510,6 +521,9 @@ void FeedsView::updateCountsOfParticularFeed(FeedsModelFeed *feed, bool update_t
m_sourceModel->reloadChangedLayout(QModelIndexList() << index);
}
// TODO: učechrat
invalidateReadFeedsFilter();
notifyWithCounts();
}
@ -609,9 +623,14 @@ void FeedsView::setupAppearance() {
}
void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
// TODO: učechrat
FeedsModelRootItem *selected_item = selectedItem();
m_proxyModel->setSelectedItem(selected_item);
QTreeView::selectionChanged(selected, deselected);
emit feedsSelected(FeedsSelection(selectedItem()));
emit feedsSelected(FeedsSelection(selected_item));
invalidateReadFeedsFilter();
}
void FeedsView::keyPressEvent(QKeyEvent *event) {

View File

@ -75,6 +75,8 @@ class FeedsView : public QTreeView {
void loadExpandedStates();
public slots:
void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false);
// Feed updating.
void updateAllFeeds();
void updateAllFeedsOnStartup();

View File

@ -34,6 +34,7 @@
#define DVALUE(x) const x
#define NON_CONST_DVALUE(x) x
#define SETTING(x) x, x##Def
#define DEFAULT_VALUE(x) x##Def
#define GROUP(x) x::ID
// Feeds.