From c4a8497471315608e80e98b22048a25c4c06bc63 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 10:55:03 +0100 Subject: [PATCH] Refactored assembling methods, TT-RSS is now able to load stored feeds. --- src/core/rootitem.cpp | 20 +++++++ src/core/rootitem.h | 1 + src/gui/dialogs/formmain.ui | 3 ++ src/services/abstract/serviceroot.cpp | 45 ++++++++++++++++ src/services/abstract/serviceroot.h | 9 ++++ src/services/standard/standardfeed.cpp | 3 +- src/services/standard/standardserviceroot.cpp | 54 +++---------------- src/services/standard/standardserviceroot.h | 11 ---- src/services/tt-rss/ttrsscategory.cpp | 11 ++++ src/services/tt-rss/ttrsscategory.h | 3 ++ src/services/tt-rss/ttrssfeed.cpp | 10 ++++ src/services/tt-rss/ttrssfeed.h | 3 ++ src/services/tt-rss/ttrssserviceroot.cpp | 43 +++++++++++++++ src/services/tt-rss/ttrssserviceroot.h | 2 + 14 files changed, 157 insertions(+), 61 deletions(-) mode change 100644 => 100755 src/services/tt-rss/ttrsscategory.cpp mode change 100644 => 100755 src/services/tt-rss/ttrsscategory.h diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 879ad8839..60f7482ed 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -281,6 +281,26 @@ QList RootItem::getSubTreeCategories() { return children; } +QHash RootItem::getHashedSubTreeCategories() { + QHash children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) { + children.insert(active_item->id(), active_item->toCategory()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + QList RootItem::getSubTreeFeeds() { QList children; QList traversable_items; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 800bbc3cf..9ad382c32 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -177,6 +177,7 @@ class RootItem : public QObject { QList getSubTree(); QList getSubTree(RootItemKind::Kind kind_of_item); QList getSubTreeCategories(); + QHash getHashedSubTreeCategories(); QList getSubTreeFeeds(); // Returns the service root node which is direct or indirect parent of current item. diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index b392a808b..7e9a1ef3c 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -753,6 +753,9 @@ Status bar + + + diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index cd25632b1..c3c9413a3 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -19,6 +19,7 @@ #include "core/feedsmodel.h" #include "miscellaneous/application.h" +#include "services/abstract/category.h" #include @@ -89,3 +90,47 @@ int ServiceRoot::accountId() const { void ServiceRoot::setAccountId(int account_id) { m_accountId = account_id; } + +void ServiceRoot::assembleFeeds(Assignment feeds) { + QHash categories = getHashedSubTreeCategories(); + + foreach (const AssignmentItem &feed, feeds) { + if (feed.first == NO_PARENT_CATEGORY) { + // This is top-level feed, add it to the root item. + appendChild(feed.second); + feed.second->updateCounts(true); + } + else if (categories.contains(feed.first)) { + // This feed belongs to this category. + categories.value(feed.first)->appendChild(feed.second); + feed.second->updateCounts(true); + } + else { + qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); + } + } +} + +void ServiceRoot::assembleCategories(Assignment categories) { + QHash assignments; + assignments.insert(NO_PARENT_CATEGORY, this); + + // Add top-level categories. + while (!categories.isEmpty()) { + for (int i = 0; i < categories.size(); i++) { + if (assignments.contains(categories.at(i).first)) { + // Parent category of this category is already added. + assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); + + // Now, added category can be parent for another categories, add it. + assignments.insert(categories.at(i).second->id(), categories.at(i).second); + + // Remove the category from the list, because it was + // added to the final collection. + categories.removeAt(i); + i--; + } + } + } +} + diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index ed0295daa..aca550619 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -30,6 +30,10 @@ class RecycleBin; class QAction; class QSqlTableModel; +// Car here represents ID of the item. +typedef QList > Assignment; +typedef QPair AssignmentItem; + // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. @@ -149,6 +153,11 @@ class ServiceRoot : public RootItem { int accountId() const; void setAccountId(int account_id); + protected: + // Takes lists of feeds/categories and assembles them into the tree structure. + void assembleCategories(Assignment categories); + void assembleFeeds(Assignment feeds); + signals: // Emitted if data in any item belonging to this root are changed. void dataChanged(QList items); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index a0f4332f3..0b22d15a9 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -763,7 +763,6 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { } StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { - setKind(RootItemKind::Feed); setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); setId(record.value(FDS_DB_ID_INDEX).toInt()); setDescription(record.value(FDS_DB_DESCRIPTION_INDEX).toString()); @@ -782,6 +781,6 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { } - setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index e86be599b..6a6c44884 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -331,8 +331,8 @@ bool StandardServiceRoot::emptyBin() { void StandardServiceRoot::loadFromDatabase(){ QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - CategoryAssignment categories; - FeedAssignment feeds; + Assignment categories; + Assignment feeds; // Obtain data for categories from the database. QSqlQuery query_categories(database); @@ -344,7 +344,7 @@ void StandardServiceRoot::loadFromDatabase(){ } while (query_categories.next()) { - CategoryAssignmentItem pair; + AssignmentItem pair; pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); pair.second = new StandardCategory(query_categories.record()); @@ -369,10 +369,10 @@ void StandardServiceRoot::loadFromDatabase(){ case StandardFeed::Rdf: case StandardFeed::Rss0X: case StandardFeed::Rss2X: { - FeedAssignmentItem pair; + AssignmentItem pair; pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); pair.second = new StandardFeed(query_feeds.record()); - pair.second->setType(type); + qobject_cast(pair.second)->setType(type); feeds << pair; break; @@ -419,6 +419,7 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *ro } QHash StandardServiceRoot::allCategories() { + // TODO: změnit na qlist, použít getsubtree možná return categoriesForItem(this); } @@ -436,26 +437,6 @@ QList StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) { return m_feedContextMenu; } -void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { - QHash categories = categoriesForItem(this); - - foreach (const FeedAssignmentItem &feed, feeds) { - if (feed.first == NO_PARENT_CATEGORY) { - // This is top-level feed, add it to the root item. - appendChild(feed.second); - feed.second->updateCounts(true); - } - else if (categories.contains(feed.first)) { - // This feed belongs to this category. - categories.value(feed.first)->appendChild(feed.second); - feed.second->updateCounts(true); - } - else { - qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); - } - } -} - bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) { QStack original_parents; original_parents.push(this); QStack new_parents; new_parents.push(model->rootItem()); @@ -696,26 +677,3 @@ bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item requestFeedReadFilterReload(); return true; } - -void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { - QHash assignments; - assignments.insert(NO_PARENT_CATEGORY, this); - - // Add top-level categories. - while (!categories.isEmpty()) { - for (int i = 0; i < categories.size(); i++) { - if (assignments.contains(categories.at(i).first)) { - // Parent category of this category is already added. - assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); - - // Now, added category can be parent for another categories, add it. - assignments.insert(categories.at(i).second->id(), categories.at(i).second); - - // Remove the category from the list, because it was - // added to the final collection. - categories.removeAt(i); - i--; - } - } - } -} diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 1a54f7b02..55552ff54 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -30,12 +30,6 @@ class StandardFeed; class FeedsImportExportModel; class QMenu; -typedef QList > CategoryAssignment; -typedef QPair CategoryAssignmentItem; - -typedef QList > FeedAssignment; -typedef QPair FeedAssignmentItem; - class StandardServiceRoot : public ServiceRoot { Q_OBJECT @@ -117,11 +111,6 @@ class StandardServiceRoot : public ServiceRoot { // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); - // Takes lists of feeds/categories and assembles - // them into the tree structure. - void assembleCategories(CategoryAssignment categories); - void assembleFeeds(FeedAssignment feeds); - StandardRecycleBin *m_recycleBin; // Menus. diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp old mode 100644 new mode 100755 index 7b485288e..9334a347d --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -18,11 +18,22 @@ #include "services/tt-rss/ttrsscategory.h" #include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" + +#include TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent), m_customId(NO_PARENT_CATEGORY) { } +TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) { + setId(record.value(CAT_DB_ID_INDEX).toInt()); + setTitle(record.value(CAT_DB_TITLE_INDEX).toString()); + setIcon(qApp->icons()->fromByteArray(record.value(CAT_DB_ICON_INDEX).toByteArray())); + setCustomId(record.value(CAT_DB_CUSTOM_ID_INDEX).toInt()); +} + TtRssCategory::~TtRssCategory() { } diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h old mode 100644 new mode 100755 index fb7df9a24..c029d3435 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -20,10 +20,13 @@ #include "services/abstract/category.h" +#include + class TtRssCategory : public Category { public: explicit TtRssCategory(RootItem *parent = NULL); + explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); int customId() const; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 5c8dc0810..f45cd427f 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/databasefactory.h" +#include "miscellaneous/iconfactory.h" #include "services/tt-rss/ttrssserviceroot.h" #include @@ -29,6 +30,15 @@ TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent), m_customId(NO_PARENT_CATEGORY), m_totalCount(0), m_unreadCount(0) { } +TtRssFeed::TtRssFeed(const QSqlRecord &record) : Feed(NULL), m_totalCount(0), m_unreadCount(0) { + setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); + setId(record.value(FDS_DB_ID_INDEX).toInt()); + setIcon(qApp->icons()->fromByteArray(record.value(FDS_DB_ICON_INDEX).toByteArray())); + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); + setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); + setCustomId(record.value(FDS_DB_CUSTOM_ID_INDEX).toInt()); +} + TtRssFeed::~TtRssFeed() { } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index a66335781..a934f9743 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -20,12 +20,15 @@ #include "services/abstract/feed.h" +#include + class TtRssServiceRoot; class TtRssFeed : public Feed { public: explicit TtRssFeed(RootItem *parent = NULL); + explicit TtRssFeed(const QSqlRecord &record); virtual ~TtRssFeed(); TtRssServiceRoot *serviceRoot(); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 50eeb2bd3..32882d7c6 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -30,6 +30,7 @@ #include #include #include +#include TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) @@ -220,6 +221,48 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { void TtRssServiceRoot::loadFromDatabase() { // TODO: Load feeds/categories from DB. + + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + Assignment categories; + Assignment feeds; + + // Obtain data for categories from the database. + QSqlQuery query_categories(database); + query_categories.setForwardOnly(true); + + if (!query_categories.exec(QString("SELECT * FROM Categories WHERE account_id = %1;").arg(accountId())) || query_categories.lastError().isValid()) { + qFatal("Query for obtaining categories failed. Error message: '%s'.", + qPrintable(query_categories.lastError().text())); + } + + while (query_categories.next()) { + AssignmentItem pair; + pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); + pair.second = new TtRssCategory(query_categories.record()); + + categories << pair; + } + + // All categories are now loaded. + QSqlQuery query_feeds(database); + query_feeds.setForwardOnly(true); + + if (!query_feeds.exec(QString("SELECT * FROM Feeds WHERE account_id = %1;").arg(accountId())) || query_feeds.lastError().isValid()) { + qFatal("Query for obtaining feeds failed. Error message: '%s'.", + qPrintable(query_feeds.lastError().text())); + } + + while (query_feeds.next()) { + AssignmentItem pair; + pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); + pair.second = new TtRssFeed(query_feeds.record()); + + feeds << pair; + } + + // All data are now obtained, lets create the hierarchy. + assembleCategories(categories); + assembleFeeds(feeds); } void TtRssServiceRoot::updateTitle() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index a549d1374..5ff7cffb6 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -23,6 +23,8 @@ #include +class TtRssCategory; +class TtRssFeed; class TtRssNetworkFactory; class TtRssServiceRoot : public ServiceRoot {