mirror of
https://github.com/martinrotter/rssguard.git
synced 2024-12-31 18:37:30 +01:00
Start to work in "starred" node in feed list.
This commit is contained in:
parent
1fcc0b1f29
commit
0cd6e1c9a3
@ -233,10 +233,13 @@ nl_before_c_comment = 2 # unsigned number
|
||||
nl_before_cpp_comment = 2 # unsigned number
|
||||
|
||||
# The number of newlines before a class definition
|
||||
nl_before_class = 2 # unsigned number
|
||||
nl_before_class = 0 # unsigned number
|
||||
|
||||
# The number of newlines after '}' or ';' of a class definition
|
||||
nl_after_class = 2 # unsigned number
|
||||
nl_after_class = 0 # unsigned number
|
||||
|
||||
# The number of newlines after '}' or ';' of a struct/enum/union definition.
|
||||
nl_after_struct = 0 # unsigned number
|
||||
|
||||
# The number of newlines after '}' of a multi-line function body
|
||||
nl_after_func_body = 2 # unsigned number
|
||||
@ -265,7 +268,7 @@ nl_remove_extra_newlines = 0 # unsigned number
|
||||
## Splitting.
|
||||
|
||||
# Try to limit code width to N number of columns
|
||||
code_width = 140 # unsigned number
|
||||
code_width = 160 # unsigned number
|
||||
|
||||
# Whether to fully split long function protos/calls at commas
|
||||
ls_func_split_full = true # false/true
|
||||
@ -288,4 +291,4 @@ cmt_c_group = true # false/true
|
||||
|
||||
# If True, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C]
|
||||
# This is generally a bad idea, as it may break your code.
|
||||
mod_sort_include = true # false/true
|
||||
mod_sort_include = true # false/true
|
||||
|
@ -20,6 +20,18 @@ FeedsProxyModel::FeedsProxyModel(FeedsModel* source_model, QObject* parent)
|
||||
setFilterRole(Qt::EditRole);
|
||||
setDynamicSortFilter(true);
|
||||
setSourceModel(m_sourceModel);
|
||||
|
||||
// Describes priorities of node types for sorting.
|
||||
// Smaller index means that item is "smaller" which
|
||||
// means it should be more on top when sorting
|
||||
// in ascending order.
|
||||
m_priorities = {
|
||||
RootItemKind::Kind::Category,
|
||||
RootItemKind::Kind::Feed,
|
||||
RootItemKind::Kind::Labels,
|
||||
RootItemKind::Kind::Important,
|
||||
RootItemKind::Kind::Bin
|
||||
};
|
||||
}
|
||||
|
||||
FeedsProxyModel::~FeedsProxyModel() {
|
||||
@ -65,7 +77,7 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex& start, int role, const
|
||||
QString item_text = item_value.toString();
|
||||
|
||||
switch (match_type) {
|
||||
case Qt::MatchRegExp:
|
||||
case Qt::MatchRegularExpression:
|
||||
if (QRegularExpression(entered_text,
|
||||
QRegularExpression::PatternOption::CaseInsensitiveOption |
|
||||
QRegularExpression::PatternOption::UseUnicodePropertiesOption).match(item_text).hasMatch()) {
|
||||
@ -141,13 +153,13 @@ bool FeedsProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right
|
||||
// by item counts, depending on the sort column.
|
||||
|
||||
if (left_item->keepOnTop()) {
|
||||
return sortOrder() == Qt::AscendingOrder;
|
||||
return sortOrder() == Qt::SortOrder::AscendingOrder;
|
||||
}
|
||||
else if (right_item->keepOnTop()) {
|
||||
return sortOrder() == Qt::DescendingOrder;
|
||||
return sortOrder() == Qt::SortOrder::DescendingOrder;
|
||||
}
|
||||
else if (left_item->kind() == right_item->kind()) {
|
||||
// Both items are feeds or both items are categories.
|
||||
// Both items are of the same type.
|
||||
if (left.column() == FDS_MODEL_COUNTS_INDEX) {
|
||||
// User wants to sort according to counts.
|
||||
return left_item->countOfUnreadMessages() < right_item->countOfUnreadMessages();
|
||||
@ -157,24 +169,14 @@ bool FeedsProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right
|
||||
return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0;
|
||||
}
|
||||
}
|
||||
else if (left_item->kind() == RootItemKind::Bin) {
|
||||
// Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order.
|
||||
return sortOrder() == Qt::DescendingOrder;
|
||||
}
|
||||
else if (right_item->kind() == RootItemKind::Bin) {
|
||||
// Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order.
|
||||
return sortOrder() == Qt::AscendingOrder;
|
||||
}
|
||||
else if (left_item->kind() == RootItemKind::Feed) {
|
||||
// Left item is feed, right item is category.
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Left item is category, right item is feed.
|
||||
// NOTE: Category is in fact "more" than feed but we consider it to be "less" because it should be "placed"
|
||||
// above the "smalles" feed when ascending sort is used.
|
||||
// NOTE: We need to keep recycle bin in first position.
|
||||
return true;
|
||||
// We sort using priorities.
|
||||
auto left_priority = m_priorities.indexOf(left_item->kind());
|
||||
auto right_priority = m_priorities.indexOf(right_item->kind());
|
||||
|
||||
return sortOrder() == Qt::SortOrder::AscendingOrder
|
||||
? left_priority < right_priority
|
||||
: right_priority < left_priority;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -5,16 +5,15 @@
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "services/abstract/rootitem.h"
|
||||
|
||||
class FeedsModel;
|
||||
class RootItem;
|
||||
|
||||
class FeedsProxyModel : public QSortFilterProxyModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
// Constructors and destructors.
|
||||
explicit FeedsProxyModel(FeedsModel* source_model, QObject* parent = 0);
|
||||
explicit FeedsProxyModel(FeedsModel* source_model, QObject* parent = nullptr);
|
||||
virtual ~FeedsProxyModel();
|
||||
|
||||
// Returns index list of items which "match" given value.
|
||||
@ -51,8 +50,8 @@ class FeedsProxyModel : public QSortFilterProxyModel {
|
||||
FeedsModel* m_sourceModel;
|
||||
const RootItem* m_selectedItem;
|
||||
bool m_showUnreadOnly;
|
||||
|
||||
QList<QPair<int, QModelIndex>> m_hiddenIndices;
|
||||
QList<RootItemKind::Kind> m_priorities;
|
||||
};
|
||||
|
||||
#endif // FEEDSPROXYMODEL_H
|
||||
|
@ -113,7 +113,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex& start, int role,
|
||||
QString item_text = item_value.toString();
|
||||
|
||||
switch (match_type) {
|
||||
case Qt::MatchRegExp:
|
||||
case Qt::MatchRegularExpression:
|
||||
if (QRegularExpression(entered_text,
|
||||
QRegularExpression::PatternOption::CaseInsensitiveOption |
|
||||
QRegularExpression::PatternOption::UseUnicodePropertiesOption).match(item_text).hasMatch()) {
|
||||
|
@ -11,7 +11,7 @@ LabelWithStatus::LabelWithStatus(QWidget* parent)
|
||||
m_wdgInput = new QLabel(this);
|
||||
|
||||
// Set correct size for the tool button.
|
||||
int label_height = m_wdgInput->sizeHint().height();
|
||||
int label_height = m_wdgInput->sizeHint().height() * 1.2;
|
||||
|
||||
m_btnStatus->setFixedSize(label_height, label_height);
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_tabIconSkin">
|
||||
<attribute name="title">
|
||||
|
@ -123,6 +123,7 @@ HEADERS += core/feeddownloader.h \
|
||||
services/abstract/category.h \
|
||||
services/abstract/feed.h \
|
||||
services/abstract/gui/formfeeddetails.h \
|
||||
services/abstract/importantnode.h \
|
||||
services/abstract/recyclebin.h \
|
||||
services/abstract/rootitem.h \
|
||||
services/abstract/serviceentrypoint.h \
|
||||
@ -263,6 +264,7 @@ SOURCES += core/feeddownloader.cpp \
|
||||
services/abstract/category.cpp \
|
||||
services/abstract/feed.cpp \
|
||||
services/abstract/gui/formfeeddetails.cpp \
|
||||
services/abstract/importantnode.cpp \
|
||||
services/abstract/recyclebin.cpp \
|
||||
services/abstract/rootitem.cpp \
|
||||
services/abstract/serviceentrypoint.cpp \
|
||||
|
@ -171,14 +171,14 @@ bool DatabaseQueries::purgeRecycleBin(const QSqlDatabase& db) {
|
||||
QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForCategory(const QSqlDatabase& db,
|
||||
const QString& custom_id,
|
||||
int account_id,
|
||||
bool including_total_counts,
|
||||
bool only_total_counts,
|
||||
bool* ok) {
|
||||
QMap<QString, QPair<int, int>> counts;
|
||||
QSqlQuery q(db);
|
||||
|
||||
q.setForwardOnly(true);
|
||||
|
||||
if (including_total_counts) {
|
||||
if (only_total_counts) {
|
||||
q.prepare("SELECT feed, sum((is_read + 1) % 2), count(*) FROM Messages "
|
||||
"WHERE feed IN (SELECT custom_id FROM Feeds WHERE category = :category AND account_id = :account_id) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
|
||||
"GROUP BY feed;");
|
||||
@ -197,7 +197,7 @@ QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForCategory(cons
|
||||
QString feed_custom_id = q.value(0).toString();
|
||||
int unread_count = q.value(1).toInt();
|
||||
|
||||
if (including_total_counts) {
|
||||
if (only_total_counts) {
|
||||
int total_count = q.value(2).toInt();
|
||||
|
||||
counts.insert(feed_custom_id, QPair<int, int>(unread_count, total_count));
|
||||
@ -221,13 +221,13 @@ QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForCategory(cons
|
||||
}
|
||||
|
||||
QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForAccount(const QSqlDatabase& db, int account_id,
|
||||
bool including_total_counts, bool* ok) {
|
||||
bool only_total_counts, bool* ok) {
|
||||
QMap<QString, QPair<int, int>> counts;
|
||||
QSqlQuery q(db);
|
||||
|
||||
q.setForwardOnly(true);
|
||||
|
||||
if (including_total_counts) {
|
||||
if (only_total_counts) {
|
||||
q.prepare("SELECT feed, sum((is_read + 1) % 2), count(*) FROM Messages "
|
||||
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
|
||||
"GROUP BY feed;");
|
||||
@ -245,7 +245,7 @@ QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForAccount(const
|
||||
QString feed_id = q.value(0).toString();
|
||||
int unread_count = q.value(1).toInt();
|
||||
|
||||
if (including_total_counts) {
|
||||
if (only_total_counts) {
|
||||
int total_count = q.value(2).toInt();
|
||||
|
||||
counts.insert(feed_id, QPair<int, int>(unread_count, total_count));
|
||||
@ -269,12 +269,12 @@ QMap<QString, QPair<int, int>> DatabaseQueries::getMessageCountsForAccount(const
|
||||
}
|
||||
|
||||
int DatabaseQueries::getMessageCountsForFeed(const QSqlDatabase& db, const QString& feed_custom_id,
|
||||
int account_id, bool including_total_counts, bool* ok) {
|
||||
int account_id, bool only_total_counts, bool* ok) {
|
||||
QSqlQuery q(db);
|
||||
|
||||
q.setForwardOnly(true);
|
||||
|
||||
if (including_total_counts) {
|
||||
if (only_total_counts) {
|
||||
q.prepare("SELECT count(*) FROM Messages "
|
||||
"WHERE feed = :feed AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
|
||||
}
|
||||
@ -302,6 +302,38 @@ int DatabaseQueries::getMessageCountsForFeed(const QSqlDatabase& db, const QStri
|
||||
}
|
||||
}
|
||||
|
||||
int DatabaseQueries::getImportantMessageCounts(const QSqlDatabase& db, int account_id, bool only_total_counts, bool* ok) {
|
||||
QSqlQuery q(db);
|
||||
|
||||
q.setForwardOnly(true);
|
||||
|
||||
if (only_total_counts) {
|
||||
q.prepare("SELECT count(*) FROM Messages "
|
||||
"WHERE is_important = 1 AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
|
||||
}
|
||||
else {
|
||||
q.prepare("SELECT count(*) FROM Messages "
|
||||
"WHERE is_read = 0 AND is_important = 1 AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
|
||||
}
|
||||
|
||||
q.bindValue(QSL(":account_id"), account_id);
|
||||
|
||||
if (q.exec() && q.next()) {
|
||||
if (ok != nullptr) {
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
return q.value(0).toInt();
|
||||
}
|
||||
else {
|
||||
if (ok != nullptr) {
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int DatabaseQueries::getMessageCountsForBin(const QSqlDatabase& db, int account_id, bool including_total_counts, bool* ok) {
|
||||
QSqlQuery q(db);
|
||||
|
||||
|
@ -33,12 +33,15 @@ class DatabaseQueries {
|
||||
static bool purgeLeftoverMessages(const QSqlDatabase& db, int account_id);
|
||||
|
||||
// Obtain counts of unread/all messages.
|
||||
static QMap<QString, QPair<int, int>> getMessageCountsForCategory(const QSqlDatabase& db, const QString& custom_id, int account_id,
|
||||
bool including_total_counts, bool* ok = nullptr);
|
||||
static QMap<QString, QPair<int, int>> getMessageCountsForCategory(const QSqlDatabase& db, const QString& custom_id,
|
||||
int account_id, bool only_total_counts,
|
||||
bool* ok = nullptr);
|
||||
static QMap<QString, QPair<int, int>> getMessageCountsForAccount(const QSqlDatabase& db, int account_id,
|
||||
bool including_total_counts, bool* ok = nullptr);
|
||||
bool only_total_counts, bool* ok = nullptr);
|
||||
static int getMessageCountsForFeed(const QSqlDatabase& db, const QString& feed_custom_id, int account_id,
|
||||
bool including_total_counts, bool* ok = nullptr);
|
||||
bool only_total_counts, bool* ok = nullptr);
|
||||
static int getImportantMessageCounts(const QSqlDatabase& db, int account_id,
|
||||
bool only_total_counts, bool* ok = nullptr);
|
||||
static int getMessageCountsForBin(const QSqlDatabase& db, int account_id, bool including_total_counts, bool* ok = nullptr);
|
||||
|
||||
// Get messages (for newspaper view for example).
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "network-web/downloader.h"
|
||||
|
||||
class LocationLineEdit;
|
||||
|
||||
class QTimer;
|
||||
|
||||
class GoogleSuggest : public QObject {
|
||||
|
41
src/librssguard/services/abstract/importantnode.cpp
Executable file
41
src/librssguard/services/abstract/importantnode.cpp
Executable file
@ -0,0 +1,41 @@
|
||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||
|
||||
#include "services/abstract/importantnode.h"
|
||||
|
||||
#include "miscellaneous/application.h"
|
||||
#include "miscellaneous/databasequeries.h"
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
#include "services/abstract/serviceroot.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
ImportantNode::ImportantNode(RootItem* parent_item) : RootItem(parent_item) {
|
||||
setKind(RootItemKind::Important);
|
||||
setId(ID_RECYCLE_BIN);
|
||||
setIcon(qApp->icons()->fromTheme(QSL("mail-mark-important")));
|
||||
setTitle(tr("Important messages"));
|
||||
setDescription(tr("You can find all important messages here."));
|
||||
setCreationDate(QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
void ImportantNode::updateCounts(bool including_total_count) {
|
||||
bool is_main_thread = QThread::currentThread() == qApp->thread();
|
||||
QSqlDatabase database = is_main_thread ?
|
||||
qApp->database()->connection(metaObject()->className()) :
|
||||
qApp->database()->connection(QSL("feed_upd"));
|
||||
int account_id = getParentServiceRoot()->accountId();
|
||||
|
||||
if (including_total_count) {
|
||||
m_totalCount = DatabaseQueries::getImportantMessageCounts(database, account_id, true);
|
||||
}
|
||||
|
||||
m_unreadCount = DatabaseQueries::getImportantMessageCounts(database, account_id, false);
|
||||
}
|
||||
|
||||
int ImportantNode::countOfUnreadMessages() const {
|
||||
return m_unreadCount;
|
||||
}
|
||||
|
||||
int ImportantNode::countOfAllMessages() const {
|
||||
return m_totalCount;
|
||||
}
|
24
src/librssguard/services/abstract/importantnode.h
Executable file
24
src/librssguard/services/abstract/importantnode.h
Executable file
@ -0,0 +1,24 @@
|
||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||
|
||||
#ifndef IMPORTANTNODE_H
|
||||
#define IMPORTANTNODE_H
|
||||
|
||||
#include "services/abstract/rootitem.h"
|
||||
|
||||
class ImportantNode : public RootItem {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ImportantNode(RootItem* parent_item = nullptr);
|
||||
virtual ~ImportantNode() = default;
|
||||
|
||||
void updateCounts(bool including_total_count);
|
||||
int countOfUnreadMessages() const;
|
||||
int countOfAllMessages() const;
|
||||
|
||||
private:
|
||||
int m_totalCount{};
|
||||
int m_unreadCount{};
|
||||
};
|
||||
|
||||
#endif // IMPORTANTNODE_H
|
@ -21,8 +21,6 @@ RecycleBin::RecycleBin(RootItem* parent_item) : RootItem(parent_item), m_totalCo
|
||||
setCreationDate(QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
RecycleBin::~RecycleBin() = default;
|
||||
|
||||
QString RecycleBin::additionalTooltip() const {
|
||||
return tr("%n deleted message(s).", nullptr, countOfAllMessages());
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class RecycleBin : public RootItem {
|
||||
|
||||
public:
|
||||
explicit RecycleBin(RootItem* parent_item = nullptr);
|
||||
virtual ~RecycleBin();
|
||||
virtual ~RecycleBin() = default;
|
||||
|
||||
QString additionalTooltip() const;
|
||||
|
||||
@ -32,7 +32,6 @@ class RecycleBin : public RootItem {
|
||||
private:
|
||||
int m_totalCount;
|
||||
int m_unreadCount;
|
||||
|
||||
QList<QAction*> m_contextMenu;
|
||||
};
|
||||
|
||||
|
@ -209,11 +209,25 @@ bool RootItem::performDragDropChange(RootItem* target_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int RootItem::countOfUnreadMessages() const {
|
||||
int total_count = 0;
|
||||
|
||||
for (RootItem* child_item : m_childItems) {
|
||||
if (child_item->kind() != RootItemKind::Kind::Important) {
|
||||
total_count += child_item->countOfUnreadMessages();
|
||||
}
|
||||
}
|
||||
|
||||
return total_count;
|
||||
}
|
||||
|
||||
int RootItem::countOfAllMessages() const {
|
||||
int total_count = 0;
|
||||
|
||||
for (RootItem* child_item : m_childItems) {
|
||||
total_count += child_item->countOfAllMessages();
|
||||
if (child_item->kind() != RootItemKind::Kind::Important) {
|
||||
total_count += child_item->countOfAllMessages();
|
||||
}
|
||||
}
|
||||
|
||||
return total_count;
|
||||
@ -250,6 +264,7 @@ bool RootItem::isParentOf(const RootItem* child) const {
|
||||
QList<RootItem*> RootItem::getSubTree() const {
|
||||
QList<RootItem*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -266,6 +281,7 @@ QList<RootItem*> RootItem::getSubTree() const {
|
||||
QList<RootItem*> RootItem::getSubTree(RootItemKind::Kind kind_of_item) const {
|
||||
QList<RootItem*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -285,6 +301,7 @@ QList<RootItem*> RootItem::getSubTree(RootItemKind::Kind kind_of_item) const {
|
||||
QList<Category*> RootItem::getSubTreeCategories() const {
|
||||
QList<Category*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -304,6 +321,7 @@ QList<Category*> RootItem::getSubTreeCategories() const {
|
||||
QHash<int, Category*> RootItem::getHashedSubTreeCategories() const {
|
||||
QHash<int, Category*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -323,6 +341,7 @@ QHash<int, Category*> RootItem::getHashedSubTreeCategories() const {
|
||||
QHash<QString, Feed*> RootItem::getHashedSubTreeFeeds() const {
|
||||
QHash<QString, Feed*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -342,6 +361,7 @@ QHash<QString, Feed*> RootItem::getHashedSubTreeFeeds() const {
|
||||
QList<Feed*> RootItem::getSubTreeFeeds() const {
|
||||
QList<Feed*> children;
|
||||
QList<RootItem*> traversable_items;
|
||||
|
||||
traversable_items.append(const_cast<RootItem* const>(this));
|
||||
|
||||
// Iterate all nested items.
|
||||
@ -457,16 +477,6 @@ void RootItem::setKeepOnTop(bool keep_on_top) {
|
||||
m_keepOnTop = keep_on_top;
|
||||
}
|
||||
|
||||
int RootItem::countOfUnreadMessages() const {
|
||||
int total_count = 0;
|
||||
|
||||
for (RootItem* child_item : m_childItems) {
|
||||
total_count += child_item->countOfUnreadMessages();
|
||||
}
|
||||
|
||||
return total_count;
|
||||
}
|
||||
|
||||
bool RootItem::removeChild(int index) {
|
||||
if (index >= 0 && index < m_childItems.size()) {
|
||||
m_childItems.removeAt(index);
|
||||
|
@ -22,8 +22,10 @@ namespace RootItemKind {
|
||||
Feed = 4,
|
||||
Category = 8,
|
||||
ServiceRoot = 16,
|
||||
LabelsRoot = 32
|
||||
Labels = 32,
|
||||
Important = 64
|
||||
};
|
||||
|
||||
inline Kind operator|(Kind a, Kind b) {
|
||||
return static_cast<Kind>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
@ -92,8 +94,6 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||
// If this method is called on "recycle bin" instance of your
|
||||
// service account, it should "empty" the recycle bin.
|
||||
virtual bool cleanMessages(bool clear_only_read);
|
||||
|
||||
// Updates counts of all/unread messages for this feed.
|
||||
virtual void updateCounts(bool including_total_count);
|
||||
virtual int row() const;
|
||||
virtual QVariant data(int column, int role) const;
|
||||
@ -104,6 +104,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||
// Returns counts of messages of all child items summed up.
|
||||
virtual int countOfUnreadMessages() const;
|
||||
virtual int countOfAllMessages() const;
|
||||
|
||||
inline RootItem* parent() const {
|
||||
return m_parentItem;
|
||||
}
|
||||
@ -215,7 +216,6 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||
QIcon m_icon;
|
||||
QDateTime m_creationDate;
|
||||
bool m_keepOnTop;
|
||||
|
||||
QList<RootItem*> m_childItems;
|
||||
RootItem* m_parentItem;
|
||||
};
|
||||
|
@ -11,9 +11,11 @@
|
||||
#include "services/abstract/cacheforserviceroot.h"
|
||||
#include "services/abstract/category.h"
|
||||
#include "services/abstract/feed.h"
|
||||
#include "services/abstract/importantnode.h"
|
||||
#include "services/abstract/recyclebin.h"
|
||||
|
||||
ServiceRoot::ServiceRoot(RootItem* parent) : RootItem(parent), m_recycleBin(new RecycleBin(this)), m_accountId(NO_PARENT_CATEGORY) {
|
||||
ServiceRoot::ServiceRoot(RootItem* parent)
|
||||
: RootItem(parent), m_recycleBin(new RecycleBin(this)), m_importantNode(new ImportantNode(this)), m_accountId(NO_PARENT_CATEGORY) {
|
||||
setKind(RootItemKind::ServiceRoot);
|
||||
setCreationDate(QDateTime::currentDateTime());
|
||||
}
|
||||
@ -98,7 +100,6 @@ void ServiceRoot::updateCounts(bool including_total_count) {
|
||||
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
||||
bool ok;
|
||||
|
||||
QMap<QString, QPair<int, int>> counts = DatabaseQueries::getMessageCountsForAccount(database, accountId(), including_total_count, &ok);
|
||||
|
||||
if (ok) {
|
||||
@ -163,6 +164,13 @@ bool ServiceRoot::cleanFeeds(QList<Feed*> items, bool clean_read_only) {
|
||||
itemss.append(bin);
|
||||
}
|
||||
|
||||
ImportantNode* imp = importantNode();
|
||||
|
||||
if (imp != nullptr) {
|
||||
imp->updateCounts(true);
|
||||
itemss << imp;
|
||||
}
|
||||
|
||||
itemChanged(itemss);
|
||||
requestReloadMessageList(true);
|
||||
return true;
|
||||
@ -267,6 +275,10 @@ void ServiceRoot::restoreCustomFeedsData(const QMap<QString, QVariant>& data, co
|
||||
}
|
||||
}
|
||||
|
||||
ImportantNode* ServiceRoot::importantNode() const {
|
||||
return m_importantNode;
|
||||
}
|
||||
|
||||
void ServiceRoot::setRecycleBin(RecycleBin* recycle_bin) {
|
||||
m_recycleBin = recycle_bin;
|
||||
}
|
||||
@ -282,6 +294,7 @@ void ServiceRoot::syncIn() {
|
||||
// Purge old data from SQL and clean all model items.
|
||||
requestItemExpandStateSave(this);
|
||||
QMap<QString, QVariant> feed_custom_data = storeCustomFeedsData();
|
||||
|
||||
removeOldFeedTree(false);
|
||||
cleanAllItems();
|
||||
restoreCustomFeedsData(feed_custom_data, new_tree->getHashedSubTreeFeeds());
|
||||
@ -303,6 +316,7 @@ void ServiceRoot::syncIn() {
|
||||
new_tree->clearChildren();
|
||||
new_tree->deleteLater();
|
||||
QList<RootItem*> all_items = getSubTree();
|
||||
|
||||
itemChanged(all_items);
|
||||
requestReloadMessageList(true);
|
||||
|
||||
@ -388,6 +402,13 @@ bool ServiceRoot::markFeedsReadUnread(QList<Feed*> items, RootItem::ReadStatus r
|
||||
itemss.append(feed);
|
||||
}
|
||||
|
||||
ImportantNode* imp = importantNode();
|
||||
|
||||
if (imp != nullptr) {
|
||||
imp->updateCounts(true);
|
||||
itemss << imp;
|
||||
}
|
||||
|
||||
itemChanged(itemss);
|
||||
requestReloadMessageList(read == RootItem::Read);
|
||||
return true;
|
||||
@ -424,7 +445,7 @@ QStringList ServiceRoot::textualFeedIds(const QList<Feed*>& feeds) const {
|
||||
QStringList ServiceRoot::customIDsOfMessages(const QList<ImportanceChange>& changes) {
|
||||
QStringList list;
|
||||
|
||||
for (const auto & change : changes) {
|
||||
for (const auto& change : changes) {
|
||||
list.append(change.first.m_customId);
|
||||
}
|
||||
|
||||
@ -454,6 +475,10 @@ bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) {
|
||||
model->setFilter(QString("Messages.is_deleted = 1 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
||||
.arg(QString::number(accountId())));
|
||||
}
|
||||
else if (item->kind() == RootItemKind::Kind::Important) {
|
||||
model->setFilter(QString("Messages.is_important = 1 AND Messages.is_deleted = 0 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
||||
.arg(QString::number(accountId())));
|
||||
}
|
||||
else {
|
||||
QList<Feed*> children = item->getSubTreeFeeds();
|
||||
QString filter_clause = textualFeedIds(children).join(QSL(", "));
|
||||
@ -485,8 +510,25 @@ bool ServiceRoot::onBeforeSetMessagesRead(RootItem* selected_item, const QList<M
|
||||
bool ServiceRoot::onAfterSetMessagesRead(RootItem* selected_item, const QList<Message>& messages, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(messages)
|
||||
Q_UNUSED(read)
|
||||
selected_item->updateCounts(false);
|
||||
itemChanged(QList<RootItem*>() << selected_item);
|
||||
|
||||
QList<RootItem*> items_to_reload;
|
||||
ImportantNode* imp = importantNode();
|
||||
|
||||
if (imp == selected_item) {
|
||||
updateCounts(true);
|
||||
items_to_reload << getSubTree();
|
||||
}
|
||||
else {
|
||||
selected_item->updateCounts(false);
|
||||
items_to_reload << selected_item;
|
||||
}
|
||||
|
||||
if (imp != nullptr && imp != selected_item) {
|
||||
imp->updateCounts(true);
|
||||
items_to_reload << imp;
|
||||
}
|
||||
|
||||
itemChanged(items_to_reload);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -524,6 +566,16 @@ bool ServiceRoot::onBeforeSwitchMessageImportance(RootItem* selected_item, const
|
||||
bool ServiceRoot::onAfterSwitchMessageImportance(RootItem* selected_item, const QList<ImportanceChange>& changes) {
|
||||
Q_UNUSED(selected_item)
|
||||
Q_UNUSED(changes)
|
||||
|
||||
QList<RootItem*> items_to_reload;
|
||||
ImportantNode* imp = importantNode();
|
||||
|
||||
if (imp != nullptr) {
|
||||
imp->updateCounts(true);
|
||||
items_to_reload << imp;
|
||||
}
|
||||
|
||||
itemChanged(items_to_reload);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -536,24 +588,26 @@ bool ServiceRoot::onBeforeMessagesDelete(RootItem* selected_item, const QList<Me
|
||||
bool ServiceRoot::onAfterMessagesDelete(RootItem* selected_item, const QList<Message>& messages) {
|
||||
Q_UNUSED(messages)
|
||||
|
||||
// User deleted some messages he selected in message list.
|
||||
QList<RootItem*> items_to_reload;
|
||||
|
||||
selected_item->updateCounts(true);
|
||||
items_to_reload << selected_item;
|
||||
|
||||
if (selected_item->kind() == RootItemKind::Bin) {
|
||||
itemChanged(QList<RootItem*>() << selected_item);
|
||||
}
|
||||
else {
|
||||
RecycleBin* bin = recycleBin();
|
||||
RecycleBin* bin = recycleBin();
|
||||
|
||||
if (bin != nullptr) {
|
||||
bin->updateCounts(true);
|
||||
itemChanged(QList<RootItem*>() << selected_item << bin);
|
||||
}
|
||||
else {
|
||||
itemChanged(QList<RootItem*>() << selected_item);
|
||||
}
|
||||
if (bin != nullptr && bin != selected_item) {
|
||||
bin->updateCounts(true);
|
||||
items_to_reload << bin;
|
||||
}
|
||||
|
||||
ImportantNode* imp = importantNode();
|
||||
|
||||
if (imp != nullptr && imp != selected_item) {
|
||||
imp->updateCounts(true);
|
||||
items_to_reload << imp;
|
||||
}
|
||||
|
||||
itemChanged(items_to_reload);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -591,6 +645,7 @@ void ServiceRoot::assembleFeeds(Assignment feeds) {
|
||||
|
||||
void ServiceRoot::assembleCategories(Assignment categories) {
|
||||
QHash<int, RootItem*> assignments;
|
||||
|
||||
assignments.insert(NO_PARENT_CATEGORY, this);
|
||||
|
||||
// Add top-level categories.
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
class FeedsModel;
|
||||
class RecycleBin;
|
||||
class ImportantNode;
|
||||
class QAction;
|
||||
class MessagesModel;
|
||||
|
||||
@ -37,6 +38,7 @@ class ServiceRoot : public RootItem {
|
||||
|
||||
void setRecycleBin(RecycleBin* recycle_bin);
|
||||
|
||||
virtual ImportantNode* importantNode() const;
|
||||
virtual bool downloadAttachmentOnMyOwn(const QUrl& url) const;
|
||||
|
||||
QList<Message> undeletedMessages() const;
|
||||
@ -80,6 +82,18 @@ class ServiceRoot : public RootItem {
|
||||
// Removes all/read only messages from given underlying feeds.
|
||||
bool cleanFeeds(QList<Feed*> items, bool clean_read_only);
|
||||
|
||||
void completelyRemoveAllData();
|
||||
QStringList customIDSOfMessagesForItem(RootItem* item);
|
||||
bool markFeedsReadUnread(QList<Feed*> items, ReadStatus read);
|
||||
|
||||
// Obvious methods to wrap signals.
|
||||
void itemChanged(const QList<RootItem*>& items);
|
||||
void requestReloadMessageList(bool mark_selected_messages_read);
|
||||
void requestItemExpand(const QList<RootItem*>& items, bool expand);
|
||||
void requestItemExpandStateSave(RootItem* subtree_root);
|
||||
void requestItemReassignment(RootItem* item, RootItem* new_parent);
|
||||
void requestItemRemoval(RootItem* item);
|
||||
|
||||
// This method should prepare messages for given "item" (download them maybe?)
|
||||
// into predefined "Messages" table
|
||||
// and then use method QSqlTableModel::setFilter(....).
|
||||
@ -137,18 +151,6 @@ class ServiceRoot : public RootItem {
|
||||
// Selected item is naturally recycle bin.
|
||||
virtual bool onAfterMessagesRestoredFromBin(RootItem* selected_item, const QList<Message>& messages);
|
||||
|
||||
void completelyRemoveAllData();
|
||||
QStringList customIDSOfMessagesForItem(RootItem* item);
|
||||
bool markFeedsReadUnread(QList<Feed*> items, ReadStatus read);
|
||||
|
||||
// Obvious methods to wrap signals.
|
||||
void itemChanged(const QList<RootItem*>& items);
|
||||
void requestReloadMessageList(bool mark_selected_messages_read);
|
||||
void requestItemExpand(const QList<RootItem*>& items, bool expand);
|
||||
void requestItemExpandStateSave(RootItem* subtree_root);
|
||||
void requestItemReassignment(RootItem* item, RootItem* new_parent);
|
||||
void requestItemRemoval(RootItem* item);
|
||||
|
||||
public slots:
|
||||
virtual void addNewFeed(const QString& url = QString());
|
||||
virtual void addNewCategory();
|
||||
@ -197,6 +199,7 @@ class ServiceRoot : public RootItem {
|
||||
|
||||
private:
|
||||
RecycleBin* m_recycleBin;
|
||||
ImportantNode* m_importantNode;
|
||||
int m_accountId;
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
#include "miscellaneous/mutex.h"
|
||||
#include "miscellaneous/settings.h"
|
||||
#include "services/abstract/importantnode.h"
|
||||
#include "services/abstract/recyclebin.h"
|
||||
#include "services/standard/gui/formstandardcategorydetails.h"
|
||||
#include "services/standard/gui/formstandardfeeddetails.h"
|
||||
@ -120,6 +121,7 @@ void StandardServiceRoot::addNewFeed(const QString& url) {
|
||||
}
|
||||
|
||||
QScopedPointer<FormStandardFeedDetails> form_pointer(new FormStandardFeedDetails(this, qApp->mainFormWidget()));
|
||||
|
||||
form_pointer.data()->addEditFeed(nullptr, nullptr, url);
|
||||
qApp->feedUpdateLock()->unlock();
|
||||
}
|
||||
@ -139,6 +141,7 @@ void StandardServiceRoot::loadFromDatabase() {
|
||||
|
||||
// As the last item, add recycle bin, which is needed.
|
||||
appendChild(recycleBin());
|
||||
appendChild(importantNode());
|
||||
updateCounts(true);
|
||||
}
|
||||
|
||||
@ -185,8 +188,10 @@ QList<QAction*> StandardServiceRoot::getContextMenuForFeed(StandardFeed* feed) {
|
||||
|
||||
bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, RootItem* target_root_node, QString& output_message) {
|
||||
QStack<RootItem*> original_parents;
|
||||
|
||||
original_parents.push(target_root_node);
|
||||
QStack<RootItem*> new_parents;
|
||||
|
||||
new_parents.push(model->rootItem());
|
||||
bool some_feed_category_error = false;
|
||||
|
||||
@ -280,18 +285,21 @@ void StandardServiceRoot::addNewCategory() {
|
||||
}
|
||||
|
||||
QScopedPointer<FormStandardCategoryDetails> form_pointer(new FormStandardCategoryDetails(this, qApp->mainFormWidget()));
|
||||
|
||||
form_pointer.data()->addEditCategory(nullptr, nullptr);
|
||||
qApp->feedUpdateLock()->unlock();
|
||||
}
|
||||
|
||||
void StandardServiceRoot::importFeeds() {
|
||||
QScopedPointer<FormStandardImportExport> form(new FormStandardImportExport(this, qApp->mainFormWidget()));
|
||||
|
||||
form.data()->setMode(FeedsImportExportModel::Import);
|
||||
form.data()->exec();
|
||||
}
|
||||
|
||||
void StandardServiceRoot::exportFeeds() {
|
||||
QScopedPointer<FormStandardImportExport> form(new FormStandardImportExport(this, qApp->mainFormWidget()));
|
||||
|
||||
form.data()->setMode(FeedsImportExportModel::Export);
|
||||
form.data()->exec();
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>604</width>
|
||||
<height>442</height>
|
||||
<height>517</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -192,21 +192,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="m_buttonBox">
|
||||
<property name="orientation">
|
||||
|
Loading…
Reference in New Issue
Block a user