Refactored assembling methods, TT-RSS is now able to load stored feeds.

This commit is contained in:
Martin Rotter 2015-12-08 10:55:03 +01:00
parent cac3aee503
commit c4a8497471
14 changed files with 157 additions and 61 deletions

View File

@ -281,6 +281,26 @@ QList<Category*> RootItem::getSubTreeCategories() {
return children;
}
QHash<int,Category*> RootItem::getHashedSubTreeCategories() {
QHash<int,Category*> children;
QList<RootItem*> 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<Feed*> RootItem::getSubTreeFeeds() {
QList<Feed*> children;
QList<RootItem*> traversable_items;

View File

@ -177,6 +177,7 @@ class RootItem : public QObject {
QList<RootItem*> getSubTree();
QList<RootItem*> getSubTree(RootItemKind::Kind kind_of_item);
QList<Category*> getSubTreeCategories();
QHash<int,Category*> getHashedSubTreeCategories();
QList<Feed*> getSubTreeFeeds();
// Returns the service root node which is direct or indirect parent of current item.

View File

@ -753,6 +753,9 @@
<property name="text">
<string>Status bar</string>
</property>
<property name="shortcut">
<string notr="true"/>
</property>
</action>
</widget>
<customwidgets>

View File

@ -19,6 +19,7 @@
#include "core/feedsmodel.h"
#include "miscellaneous/application.h"
#include "services/abstract/category.h"
#include <QSqlQuery>
@ -89,3 +90,47 @@ int ServiceRoot::accountId() const {
void ServiceRoot::setAccountId(int account_id) {
m_accountId = account_id;
}
void ServiceRoot::assembleFeeds(Assignment feeds) {
QHash<int,Category*> 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<int,RootItem*> 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--;
}
}
}
}

View File

@ -30,6 +30,10 @@ class RecycleBin;
class QAction;
class QSqlTableModel;
// Car here represents ID of the item.
typedef QList<QPair<int,RootItem*> > Assignment;
typedef QPair<int,RootItem*> 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<RootItem*> items);

View File

@ -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<StandardFeed::AutoUpdateType>(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt()));
setAutoUpdateType(static_cast<Feed::AutoUpdateType>(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt()));
setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt());
}

View File

@ -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<StandardFeed*>(pair.second)->setType(type);
feeds << pair;
break;
@ -419,6 +419,7 @@ QHash<int,StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *ro
}
QHash<int,StandardCategory*> StandardServiceRoot::allCategories() {
// TODO: změnit na qlist, použít getsubtree možná
return categoriesForItem(this);
}
@ -436,26 +437,6 @@ QList<QAction*> StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) {
return m_feedContextMenu;
}
void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) {
QHash<int,StandardCategory*> 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<RootItem*> original_parents; original_parents.push(this);
QStack<RootItem*> 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<int,RootItem*> 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--;
}
}
}
}

View File

@ -30,12 +30,6 @@ class StandardFeed;
class FeedsImportExportModel;
class QMenu;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
typedef QList<QPair<int, StandardFeed*> > FeedAssignment;
typedef QPair<int, StandardFeed*> 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<Feed *> &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.

11
src/services/tt-rss/ttrsscategory.cpp Normal file → Executable file
View File

@ -18,11 +18,22 @@
#include "services/tt-rss/ttrsscategory.h"
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include <QVariant>
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() {
}

3
src/services/tt-rss/ttrsscategory.h Normal file → Executable file
View File

@ -20,10 +20,13 @@
#include "services/abstract/category.h"
#include <QSqlRecord>
class TtRssCategory : public Category {
public:
explicit TtRssCategory(RootItem *parent = NULL);
explicit TtRssCategory(const QSqlRecord &record);
virtual ~TtRssCategory();
int customId() const;

View File

@ -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 <QSqlQuery>
@ -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<Feed::AutoUpdateType>(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() {
}

View File

@ -20,12 +20,15 @@
#include "services/abstract/feed.h"
#include <QSqlRecord>
class TtRssServiceRoot;
class TtRssFeed : public Feed {
public:
explicit TtRssFeed(RootItem *parent = NULL);
explicit TtRssFeed(const QSqlRecord &record);
virtual ~TtRssFeed();
TtRssServiceRoot *serviceRoot();

View File

@ -30,6 +30,7 @@
#include <QSqlQuery>
#include <QSqlError>
#include <QPointer>
#include <QPair>
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() {

View File

@ -23,6 +23,8 @@
#include <QCoreApplication>
class TtRssCategory;
class TtRssFeed;
class TtRssNetworkFactory;
class TtRssServiceRoot : public ServiceRoot {