Experimental FeedsSelection implementation.

This commit is contained in:
Martin Rotter 2015-05-02 19:32:23 +02:00
parent 9417dd404b
commit 63d4b93433
13 changed files with 181 additions and 122 deletions

View File

@ -394,6 +394,7 @@ set(APP_SOURCES
src/core/feeddownloader.cpp
src/core/feedsimportexportmodel.cpp
src/core/feedsmodelrecyclebin.cpp
src/core/feedsselection.cpp
# NETWORK-WEB sources.
src/network-web/basenetworkaccessmanager.cpp
@ -477,6 +478,7 @@ set(APP_HEADERS
src/core/feedsproxymodel.h
src/core/feeddownloader.h
src/core/feedsimportexportmodel.h
src/core/feedsselection.h
# NETWORK-WEB headers.
src/network-web/webpage.h

View File

@ -620,42 +620,6 @@ QModelIndex FeedsModel::indexForItem(FeedsModelRootItem *item) const {
}
return target_index;
/*
QList<QModelIndex> parents;
// Start with root item (which obviously has invalid index).
parents << indexForItem(m_rootItem);
while (!parents.isEmpty()) {
QModelIndex active_index = parents.takeFirst();
int row_count = rowCount(active_index);
if (row_count > 0) {
// This index has children.
// Lets take a look if our target item is among them.
FeedsModelRootItem *active_item = itemForIndex(active_index);
int candidate_index = active_item->childItems().indexOf(item);
if (candidate_index >= 0) {
// We found our item.
return index(candidate_index, 0, active_index);
}
else {
// Item is not found, add all "categories" from active_item.
for (int i = 0; i < row_count; i++) {
FeedsModelRootItem *possible_category = active_item->child(i);
if (possible_category->kind() == FeedsModelRootItem::Category) {
parents << index(i, 0, active_index);
}
}
}
}
}
return QModelIndex();
*/
}
bool FeedsModel::hasAnyFeedNewMessages() {
@ -989,32 +953,12 @@ QList<FeedsModelFeed*> FeedsModel::allFeeds() {
}
QList<FeedsModelFeed*> FeedsModel::feedsForItem(FeedsModelRootItem *root) {
QList<FeedsModelRootItem*> children = root->getRecursiveChildren();
QList<FeedsModelFeed*> feeds;
if (root->kind() == FeedsModelRootItem::Feed) {
// Root itself is a FEED.
feeds.append(root->toFeed());
}
else {
// Root itself is a CATEGORY or ROOT item.
QList<FeedsModelRootItem*> traversable_items;
traversable_items.append(root);
// Iterate all nested categories.
while (!traversable_items.isEmpty()) {
FeedsModelRootItem *active_category = traversable_items.takeFirst();
foreach (FeedsModelRootItem *child, active_category->childItems()) {
if (child->kind() == FeedsModelRootItem::Feed) {
// This child is feed.
feeds.append(child->toFeed());
}
else if (child->kind() == FeedsModelRootItem::Category) {
// This child is category, add its child feeds too.
traversable_items.append(child->toCategory());
}
}
foreach (FeedsModelRootItem *child, children) {
if (child->kind() == FeedsModelRootItem::Feed) {
feeds.append(child->toFeed());
}
}

View File

@ -77,6 +77,39 @@ int FeedsModelRootItem::countOfAllMessages() const {
return total_count;
}
QList<FeedsModelRootItem*> FeedsModelRootItem::getRecursiveChildren() {
QList<FeedsModelRootItem*> children;
if (kind() == FeedsModelRootItem::Feed) {
// Root itself is a FEED.
children.append(this);
}
else {
// Root itself is a CATEGORY or ROOT item.
QList<FeedsModelRootItem*> traversable_items;
traversable_items.append(this);
// Iterate all nested categories.
while (!traversable_items.isEmpty()) {
FeedsModelRootItem *active_category = traversable_items.takeFirst();
foreach (FeedsModelRootItem *child, active_category->childItems()) {
if (child->kind() == FeedsModelRootItem::Feed) {
// This child is feed.
children.append(child);
}
else if (child->kind() == FeedsModelRootItem::Category) {
// This child is category, add its child feeds too.
traversable_items.append(child);
}
}
}
}
return children;
}
bool FeedsModelRootItem::removeChild(FeedsModelRootItem *child) {
return m_childItems.removeOne(child);
}

View File

@ -114,6 +114,8 @@ class FeedsModelRootItem {
m_childItems.clear();
}
QList<FeedsModelRootItem*> getRecursiveChildren();
// Removes particular child at given index.
// NOTE: Child is NOT freed from the memory.
bool removeChild(int index);
@ -132,7 +134,7 @@ class FeedsModelRootItem {
m_icon = icon;
}
// Each item has some kind of id.
// Each item has some kind of id. Usually taken from primary key attribute from DB.
inline int id() const {
return m_id;
}

View File

@ -0,0 +1,68 @@
#include "core/feedsselection.h"
#include "core/feedsmodelrootitem.h"
#include "core/feedsmodelcategory.h"
#include "core/feedsmodelfeed.h"
FeedsSelection::FeedsSelection(FeedsModelRootItem *root_of_selection) : m_selectedItem(root_of_selection) {
}
FeedsSelection::FeedsSelection(const FeedsSelection &other) {
m_selectedItem = other.selectedItem();
}
FeedsSelection::~FeedsSelection() {
}
FeedsSelection::MessageMode FeedsSelection::mode() {
if (m_selectedItem == NULL) {
return MessageMode::NoMode;
}
switch (m_selectedItem->kind()) {
case FeedsModelRootItem::RecycleBin:
return MessageMode::MessagesFromRecycleBin;
case FeedsModelRootItem::Category:
case FeedsModelRootItem::Feed:
return MessageMode::MessagesFromFeeds;
default:
return MessageMode::NoMode;
}
}
FeedsModelRootItem *FeedsSelection::selectedItem() const {
return m_selectedItem;
}
QString FeedsSelection::generateDatabaseFilter() {
if (m_selectedItem == NULL) {
return "feed IN () AND is_deleted = 0";
}
switch (m_selectedItem->kind()) {
case FeedsModelRootItem::RecycleBin:
return "is_deleted = 1 AND is_pdeleted = 0";
case FeedsModelRootItem::Category:
case FeedsModelRootItem::Feed: {
QList<FeedsModelRootItem*> children = m_selectedItem->getRecursiveChildren();
QStringList stringy_ids;
children.append(m_selectedItem);
foreach (FeedsModelRootItem *child, children) {
if (child->kind() == FeedsModelRootItem::Feed) {
stringy_ids.append(QString::number(child->id()));
}
}
return QString("feed IN (%1) AND is_deleted = 0").arg(stringy_ids.join(", "));
}
default:
return "feed IN () AND is_deleted = 0";
}
}

32
src/core/feedsselection.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef FEEDSSELECTION_H
#define FEEDSSELECTION_H
#include <QString>
#include <QObject>
class FeedsModelRootItem;
class FeedsSelection {
public:
enum MessageMode {
NoMode,
MessagesFromFeeds,
MessagesFromRecycleBin
};
explicit FeedsSelection(FeedsModelRootItem *root_of_selection = NULL);
FeedsSelection(const FeedsSelection &other);
virtual ~FeedsSelection();
MessageMode mode();
FeedsModelRootItem *selectedItem() const;
QString generateDatabaseFilter();
private:
FeedsModelRootItem *m_selectedItem;
};
Q_DECLARE_METATYPE(FeedsSelection::MessageMode)
#endif // FEEDSSELECTION_H

View File

@ -30,7 +30,7 @@
MessagesModel::MessagesModel(QObject *parent)
: QSqlTableModel(parent, qApp->database()->connection("MessagesModel", DatabaseFactory::FromSettings)),
m_messageMode(MessagesFromFeeds), m_messageFilter(NoHighlighting), m_customDateFormat(QString()) {
m_messageFilter(NoHighlighting), m_customDateFormat(QString()) {
setObjectName("MessagesModel");
setupFonts();
setupIcons();
@ -42,7 +42,7 @@ MessagesModel::MessagesModel(QObject *parent)
// via model, but via DIRECT SQL calls are used to do persistent messages.
setEditStrategy(QSqlTableModel::OnManualSubmit);
setTable("Messages");
loadMessages(QList<int>());
loadMessages(FeedsSelection());
}
MessagesModel::~MessagesModel() {
@ -55,8 +55,8 @@ void MessagesModel::setupIcons() {
m_unreadIcon = qApp->icons()->fromTheme("mail-mark-unread");
}
MessagesModel::MessageMode MessagesModel::messageMode() const {
return m_messageMode;
FeedsSelection MessagesModel::currentFeeds() const {
return m_currentFeeds;
}
void MessagesModel::fetchAll() {
@ -71,10 +71,10 @@ void MessagesModel::setupFonts() {
m_boldFont.setBold(true);
}
void MessagesModel::loadMessages(const QList<int> feed_ids) {
m_currentFeeds = feed_ids;
void MessagesModel::loadMessages(const FeedsSelection &selection) {
m_currentFeeds = selection;
if (feed_ids.size() == 1 && feed_ids[0] == ID_RECYCLE_BIN) {
/* if (selection.size() == 1 && selection[0] == ID_RECYCLE_BIN) {
m_messageMode = MessagesFromRecycleBin;
setFilter("is_deleted = 1 AND is_pdeleted = 0");
}
@ -84,8 +84,9 @@ void MessagesModel::loadMessages(const QList<int> feed_ids) {
setFilter(QString("feed IN (%1) AND is_deleted = 0").arg(assembled_ids));
qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids));
}
}*/
setFilter(m_currentFeeds.generateDatabaseFilter());
select();
fetchAll();
}
@ -96,17 +97,6 @@ void MessagesModel::filterMessages(MessagesModel::MessageFilter filter) {
emit layoutChanged();
}
QStringList MessagesModel::textualFeeds() const {
QStringList stringy_ids;
stringy_ids.reserve(m_currentFeeds.size());
foreach (int feed_id, m_currentFeeds) {
stringy_ids.append(QString::number(feed_id));
}
return stringy_ids;
}
int MessagesModel::messageId(int row_index) const {
return data(row_index, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
}
@ -292,7 +282,7 @@ bool MessagesModel::setMessageRead(int row_index, int read) {
// If commit succeeded, then emit changes, so that view
// can reflect.
emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1));
emit messageCountsChanged(m_messageMode, false, false);
emit messageCountsChanged(m_currentFeeds.mode(), false, false);
return true;
}
else {
@ -391,7 +381,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int
QString sql_delete_query;
if (m_messageMode == MessagesFromFeeds) {
if (m_currentFeeds.mode() == FeedsSelection::MessagesFromFeeds) {
sql_delete_query = QString("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);").arg(message_ids.join(", "),
QString::number(deleted));
}
@ -404,7 +394,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int
select();
fetchAll();
emit messageCountsChanged(m_messageMode, true, false);
emit messageCountsChanged(m_currentFeeds.mode(), true, false);
return true;
}
else {
@ -429,7 +419,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, int re
select();
fetchAll();
emit messageCountsChanged(m_messageMode, false, false);
emit messageCountsChanged(m_currentFeeds.mode(), false, false);
return true;
}
else {
@ -438,7 +428,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, int re
}
bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
if (m_messageMode == MessagesFromFeeds) {
if (m_currentFeeds.mode() == FeedsSelection::MessagesFromFeeds) {
qDebug("Cannot restore non-deleted messages.");
return false;
}
@ -460,7 +450,7 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
select();
fetchAll();
emit messageCountsChanged(m_messageMode, true, true);
emit messageCountsChanged(m_currentFeeds.mode(), true, true);
return true;
}
else {

View File

@ -20,6 +20,8 @@
#include "definitions/definitions.h"
#include "core/feedsselection.h"
#include <QSqlTableModel>
#include <QFont>
#include <QIcon>
@ -83,11 +85,6 @@ class MessagesModel : public QSqlTableModel {
HighlightImportant = 102
};
enum MessageMode {
MessagesFromFeeds,
MessagesFromRecycleBin
};
// Constructors and destructors.
explicit MessagesModel(QObject *parent = 0);
virtual ~MessagesModel();
@ -102,13 +99,9 @@ class MessagesModel : public QSqlTableModel {
Message messageAt(int row_index) const;
int messageId(int row_index) const;
// Access to list of currently loaded feed IDs.
inline QList<int> currentFeeds() const {
return m_currentFeeds;
}
void updateDateFormat();
MessageMode messageMode() const;
FeedsSelection currentFeeds() const;
public slots:
// To disable persistent changes submissions.
@ -140,21 +133,15 @@ class MessagesModel : public QSqlTableModel {
void fetchAll();
// Loads messages of given feeds.
void loadMessages(const QList<int> feed_ids);
void loadMessages(const FeedsSelection &selection);
void filterMessages(MessageFilter filter);
signals:
// Emitted if some persistent change is made which affects count of "unread/all" messages.
void messageCountsChanged(MessagesModel::MessageMode mode,
bool total_msg_count_changed,
bool any_msg_restored);
void messageCountsChanged(FeedsSelection::MessageMode mode, bool total_msg_count_changed, bool any_msg_restored);
protected:
// Returns selected feed ids in concatenated textual form,
// which is used for SQL queries.
QStringList textualFeeds() const;
// Sets up header data.
void setupHeaderData();
@ -165,11 +152,10 @@ class MessagesModel : public QSqlTableModel {
void setupIcons();
private:
MessageMode m_messageMode;
MessageFilter m_messageFilter;
QString m_customDateFormat;
QList<int> m_currentFeeds;
FeedsSelection m_currentFeeds;
QList<QString> m_headerData;
QList<QString> m_tooltipData;
@ -181,7 +167,6 @@ class MessagesModel : public QSqlTableModel {
QIcon m_unreadIcon;
};
Q_DECLARE_METATYPE(MessagesModel::MessageMode)
Q_DECLARE_METATYPE(MessagesModel::MessageFilter)
#endif // MESSAGESMODEL_H

View File

@ -197,11 +197,11 @@ void FeedMessageViewer::createConnections() {
connect(m_messagesView, SIGNAL(currentMessagesChanged(QList<Message>)), m_messagesBrowser, SLOT(navigateToMessages(QList<Message>)));
// If user selects feeds, load their messages.
connect(m_feedsView, SIGNAL(feedsSelected(QList<int>)), m_messagesView, SLOT(loadFeeds(QList<int>)));
connect(m_feedsView, SIGNAL(feedsSelected(FeedsSelection)), m_messagesView, SLOT(loadFeeds(FeedsSelection)));
// If user changes status of some messages, recalculate message counts.
connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged(MessagesModel::MessageMode,bool,bool)),
m_feedsView, SLOT(receiveMessageCountsChange(MessagesModel::MessageMode,bool,bool)));
connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged(FeedsSelection::MessageMode,bool,bool)),
m_feedsView, SLOT(receiveMessageCountsChange(FeedsSelection::MessageMode,bool,bool)));
// State of many messages is changed, then we need
// to reload selections.

View File

@ -310,7 +310,7 @@ void FeedsView::editFeed(FeedsModelFeed *feed) {
delete form_pointer.data();
}
void FeedsView::receiveMessageCountsChange(MessagesModel::MessageMode mode,
void FeedsView::receiveMessageCountsChange(FeedsSelection::MessageMode mode,
bool total_msg_count_changed,
bool any_msg_restored) {
// If the change came from recycle bin mode, then:
@ -328,7 +328,7 @@ void FeedsView::receiveMessageCountsChange(MessagesModel::MessageMode mode,
// total counts.
// b) total count of message was not changed - some messages switched state --> we need to update
// counts of just selected feeds.
if (mode == MessagesModel::MessagesFromRecycleBin) {
if (mode == FeedsSelection::MessagesFromRecycleBin) {
if (total_msg_count_changed) {
if (any_msg_restored) {
updateCountsOfAllFeeds(true);
@ -624,7 +624,7 @@ void FeedsView::setupAppearance() {
}
void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
QTreeView::selectionChanged(selected, deselected);
/*QTreeView::selectionChanged(selected, deselected);
QList<FeedsModelFeed*> selected_feeds = selectedFeeds();
QList<int> selected_ids;
@ -641,9 +641,9 @@ void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSele
}
else if (selectedRecycleBin() != NULL) {
selected_ids << ID_RECYCLE_BIN;
}
}*/
emit feedsSelected(selected_ids);
emit feedsSelected(FeedsSelection(selectedItem()));
}
void FeedsView::keyPressEvent(QKeyEvent *event) {

View File

@ -22,6 +22,7 @@
#include "core/messagesmodel.h"
#include "core/feedsmodel.h"
#include "core/feedsselection.h"
#include "miscellaneous/settings.h"
@ -116,7 +117,7 @@ class FeedsView : public QTreeView {
// Is called when counts of messages are changed externally,
// typically from message view.
void receiveMessageCountsChange(MessagesModel::MessageMode mode, bool total_msg_count_changed, bool any_msg_restored);
void receiveMessageCountsChange(FeedsSelection::MessageMode mode, bool total_msg_count_changed, bool any_msg_restored);
// Reloads counts for selected feeds.
void updateCountsOfSelectedFeeds(bool update_total_too);
@ -178,7 +179,7 @@ class FeedsView : public QTreeView {
void feedsNeedToBeReloaded(int mark_current_index_read);
// Emitted if user selects new feeds.
void feedsSelected(const QList<int> &feed_ids);
void feedsSelected(const FeedsSelection &selection);
// Requests opening of given messages in newspaper mode.
void openMessagesInNewspaperView(const QList<Message> &messages);

View File

@ -148,7 +148,7 @@ void MessagesView::contextMenuEvent(QContextMenuEvent *event) {
initializeContextMenu();
}
if (sourceModel()->messageMode() != MessagesModel::MessagesFromRecycleBin) {
if (sourceModel()->currentFeeds().mode() != FeedsSelection::MessagesFromRecycleBin) {
m_contextMenu->removeAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin);
}
else {
@ -235,8 +235,8 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS
QTreeView::selectionChanged(selected, deselected);
}
void MessagesView::loadFeeds(const QList<int> &feed_ids) {
m_sourceModel->loadMessages(feed_ids);
void MessagesView::loadFeeds(const FeedsSelection &selection) {
m_sourceModel->loadMessages(selection);
int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt();
Qt::SortOrder ord = static_cast<Qt::SortOrder>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderMessages)).toInt());

View File

@ -20,6 +20,8 @@
#include "core/messagesmodel.h"
#include "core/feedsselection.h"
#include <QTreeView>
#include <QHeaderView>
@ -58,7 +60,7 @@ class MessagesView : public QTreeView {
void reloadSelections(int mark_current_index_read);
// Loads un-deleted messages from selected feeds.
void loadFeeds(const QList<int> &feed_ids);
void loadFeeds(const FeedsSelection &selection);
// Message manipulators.
void openSelectedSourceArticlesExternally();