From 63d4b934338698c42dc9d6fa9bace93cb2fe8b3d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 2 May 2015 19:32:23 +0200 Subject: [PATCH] Experimental FeedsSelection implementation. --- CMakeLists.txt | 2 + src/core/feedsmodel.cpp | 64 ++----------------------------- src/core/feedsmodelrootitem.cpp | 33 ++++++++++++++++ src/core/feedsmodelrootitem.h | 4 +- src/core/feedsselection.cpp | 68 +++++++++++++++++++++++++++++++++ src/core/feedsselection.h | 32 ++++++++++++++++ src/core/messagesmodel.cpp | 40 ++++++++----------- src/core/messagesmodel.h | 29 ++++---------- src/gui/feedmessageviewer.cpp | 6 +-- src/gui/feedsview.cpp | 10 ++--- src/gui/feedsview.h | 5 ++- src/gui/messagesview.cpp | 6 +-- src/gui/messagesview.h | 4 +- 13 files changed, 181 insertions(+), 122 deletions(-) create mode 100644 src/core/feedsselection.cpp create mode 100644 src/core/feedsselection.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a25ab45f4..8e6806875 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index f926e4d05..2705f14bb 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -620,42 +620,6 @@ QModelIndex FeedsModel::indexForItem(FeedsModelRootItem *item) const { } return target_index; - - /* - QList 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 FeedsModel::allFeeds() { } QList FeedsModel::feedsForItem(FeedsModelRootItem *root) { + QList children = root->getRecursiveChildren(); QList 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 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()); } } diff --git a/src/core/feedsmodelrootitem.cpp b/src/core/feedsmodelrootitem.cpp index 4c3b8d795..7cc108aa9 100755 --- a/src/core/feedsmodelrootitem.cpp +++ b/src/core/feedsmodelrootitem.cpp @@ -77,6 +77,39 @@ int FeedsModelRootItem::countOfAllMessages() const { return total_count; } +QList FeedsModelRootItem::getRecursiveChildren() { + QList children; + + if (kind() == FeedsModelRootItem::Feed) { + // Root itself is a FEED. + children.append(this); + } + else { + // Root itself is a CATEGORY or ROOT item. + QList 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); } diff --git a/src/core/feedsmodelrootitem.h b/src/core/feedsmodelrootitem.h index cd406e652..8edd8d0ce 100755 --- a/src/core/feedsmodelrootitem.h +++ b/src/core/feedsmodelrootitem.h @@ -114,6 +114,8 @@ class FeedsModelRootItem { m_childItems.clear(); } + QList 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; } diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp new file mode 100644 index 000000000..0497db6b4 --- /dev/null +++ b/src/core/feedsselection.cpp @@ -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 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"; + } +} diff --git a/src/core/feedsselection.h b/src/core/feedsselection.h new file mode 100644 index 000000000..c5ef85b4d --- /dev/null +++ b/src/core/feedsselection.h @@ -0,0 +1,32 @@ +#ifndef FEEDSSELECTION_H +#define FEEDSSELECTION_H + +#include +#include + + +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 diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index fe14b20ae..8861857d8 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -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()); + 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 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 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 { diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index 4375b5ddd..2d3ca864b 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -20,6 +20,8 @@ #include "definitions/definitions.h" +#include "core/feedsselection.h" + #include #include #include @@ -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 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 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 m_currentFeeds; + FeedsSelection m_currentFeeds; QList m_headerData; QList 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 diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index e2f251ec9..0002a3555 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -197,11 +197,11 @@ void FeedMessageViewer::createConnections() { connect(m_messagesView, SIGNAL(currentMessagesChanged(QList)), m_messagesBrowser, SLOT(navigateToMessages(QList))); // If user selects feeds, load their messages. - connect(m_feedsView, SIGNAL(feedsSelected(QList)), m_messagesView, SLOT(loadFeeds(QList))); + 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. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 0ed072921..879b7944d 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -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 selected_feeds = selectedFeeds(); QList 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) { diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 9a84a68a2..7887bd8ba 100644 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -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 &feed_ids); + void feedsSelected(const FeedsSelection &selection); // Requests opening of given messages in newspaper mode. void openMessagesInNewspaperView(const QList &messages); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index eabd52090..d504837ba 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -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 &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(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderMessages)).toInt()); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index d8a5f44ed..1e6acc7bd 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -20,6 +20,8 @@ #include "core/messagesmodel.h" +#include "core/feedsselection.h" + #include #include @@ -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 &feed_ids); + void loadFeeds(const FeedsSelection &selection); // Message manipulators. void openSelectedSourceArticlesExternally();