diff --git a/Larss.pro b/Larss.pro index 95761ad..437cd54 100644 --- a/Larss.pro +++ b/Larss.pro @@ -17,7 +17,7 @@ SOURCES += larss/main.cpp\ larss/feedpoller.cpp \ larss/editfeeddialog.cpp \ larss/editcategorydialog.cpp \ - larss/feedproxymodel.cpp + larss/feednode.cpp HEADERS += include/mainwindow.h \ include/feedmodel.h \ @@ -25,7 +25,7 @@ HEADERS += include/mainwindow.h \ include/feedpoller.h \ include/editfeeddialog.h \ include/editcategorydialog.h \ - include/feedproxymodel.h + include/feednode.h FORMS += ui/mainwindow.ui \ ui/editfeeddialog.ui \ diff --git a/include/feedmodel.h b/include/feedmodel.h index 6ead440..2c4334d 100644 --- a/include/feedmodel.h +++ b/include/feedmodel.h @@ -2,15 +2,16 @@ #define FEEDMODEL_H #include <QObject> -#include <QAbstractItemModel> +#include <QStandardItemModel> #include <QSqlDatabase> #include <QtXml> +#include "feednode.h" namespace Larss { #define FEEDMODEL_MAX_CATEGORIES 1024 -class FeedModel : public QAbstractItemModel { +class FeedModel : public QStandardItemModel { Q_OBJECT public: @@ -22,36 +23,6 @@ public: ~FeedModel(); /** - * @brief Get the ModelIndex associated with a given row and column. - */ - QModelIndex index(int row, int column, const QModelIndex &parent) const; - - /** - * @brief Get the number of rows in the list. - */ - int rowCount(const QModelIndex &parent) const; - - /** - * @brief Get the number of column - */ - int columnCount(const QModelIndex &parent) const; - - /** - * @brief Get the data associated to a given node. - */ - QVariant data(const QModelIndex &index, int role) const; - - /** - * @brief Get the parent of a given node. - */ - QModelIndex parent(const QModelIndex &child) const; - - /** - * @brief Return the flags for the given item. - */ - Qt::ItemFlags flags(const QModelIndex &index) const; - - /** * @brief Return the data to be inserted in the column header of the treeview. */ QVariant headerData(int section, Qt::Orientation orientation, int role) const; @@ -76,6 +47,13 @@ public: */ bool addFeed (QString name, QString url, quint32 category_id); + /** + * @brief Select data from the database. + */ + void select(); + + FeedNode * itemFromIndex (const QModelIndex& index); + signals: public slots: @@ -86,6 +64,8 @@ private: */ QSqlDatabase db; + FeedNode *rootNode; + }; diff --git a/include/feednode.h b/include/feednode.h new file mode 100644 index 0000000..5120491 --- /dev/null +++ b/include/feednode.h @@ -0,0 +1,54 @@ +#ifndef FEEDNODE_H +#define FEEDNODE_H + +#include <QObject> +#include <QStandardItem> + +namespace Larss { + + class FeedNode : public QStandardItem + { + + public: + explicit FeedNode(quint64 id, QString name, QString url = ""); + + enum ItemType { + Root = 1001, + Category = 1002, + Feed = 1003 + }; + + /** + * @brief Return the type of this element. + */ + ItemType type (); + + quint64 id(); + QString name(); + QString url(); + + private: + + /** + * @brief The id of the item in the database. + */ + quint64 nodeId; + + /** + * @brief The name of the item. + */ + QString nodeName; + + /** + * @brief The Url associated with the feed, if any + * (Category do not have this one). + */ + QString nodeUrl; + + private: + + }; + +} + +#endif // FEEDNODE_H diff --git a/include/feedproxymodel.h b/include/feedproxymodel.h deleted file mode 100644 index ee4b5f4..0000000 --- a/include/feedproxymodel.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FEEDPROXYMODEL_H -#define FEEDPROXYMODEL_H - -#include <QObject> -#include <QProxyModel> -#include "rssparser.h" - -namespace Larss { - - class FeedProxyModel : public QProxyModel - { - Q_OBJECT - public: - explicit FeedProxyModel(QObject *parent = 0); - QVariant data (const QModelIndex &index, int role) const; - void setParser (RssParser * parser); - - private: - RssParser *parser; - - signals: - - public slots: - void onRssParserDataChanged (QModelIndex index, QModelIndex index2); - - }; - -} - -#endif // FEEDPROXYMODEL_H diff --git a/larss/feedmodel.cpp b/larss/feedmodel.cpp index 104e010..81048dd 100644 --- a/larss/feedmodel.cpp +++ b/larss/feedmodel.cpp @@ -1,5 +1,5 @@ #include "feedmodel.h" -#include <QAbstractItemModel> +#include "feednode.h" #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> @@ -9,7 +9,7 @@ using namespace Larss; -FeedModel::FeedModel(QSqlDatabase db, QObject *parent) : QAbstractItemModel (parent) +FeedModel::FeedModel(QSqlDatabase db, QObject *parent) : QStandardItemModel (parent) { this->db = db; @@ -29,141 +29,58 @@ FeedModel::FeedModel(QSqlDatabase db, QObject *parent) : QAbstractItemModel (par if (!query.exec()) qDebug() << "Error while creating the feeds table in the db"; } + + select(); } FeedModel::~FeedModel() { } - -QModelIndex -FeedModel::index(int row, int column, const QModelIndex &parent) const +void +FeedModel::select() { - if (parent.internalId() == 0) - { - QSqlQuery query (db); - query.prepare("SELECT id from categories ORDER by id;"); - if (query.exec()) - { - if (!query.first()) - return QModelIndex(); - for (int i = 0; i < row; i++) - { - if (!query.next ()) - return QModelIndex(); - } - return createIndex(row, column, query.value(0).toInt()); - } - else - return QModelIndex(); - } - else + // Clear the content of the model + clear(); + + // Get the root of the tree + QStandardItem *root = invisibleRootItem(); + + // Set the fake rootNode + rootNode = new FeedNode (0, ""); + + QSqlQuery query(db); + query.prepare("SELECT id, name from categories;"); + if (query.exec() && query.first()) { - QSqlQuery query(db); - query.prepare ("SELECT id from feeds WHERE category=:category ORDER BY id;"); - query.bindValue("category", parent.internalId()); - if (query.exec()) - { - if (!query.first()) - return QModelIndex(); - else + do { + // Insert the new category in the tree + FeedNode* node = new FeedNode(query.value(0).toInt(), query.value(1).toString()); + root->appendRow(node); + + // Find the feeds associated with this category and add the as childs. + QSqlQuery feedQuery(db); + feedQuery.prepare("SELECT id, name, url FROM feeds WHERE category=:category"); + feedQuery.bindValue("category", node->id()); + + if (feedQuery.exec() && feedQuery.first()) { - for(int i = 0; i < row; i++) + do { - if (!query.next()) - return QModelIndex(); - } - return createIndex(row, column, query.value(0).toInt() + FEEDMODEL_MAX_CATEGORIES); + FeedNode *feedNode = new FeedNode(feedQuery.value(0).toInt(), + feedQuery.value(1).toString(), + feedQuery.value(2).toString()); + node->appendRow(feedNode); + } while (feedQuery.next()); } - } - else - return QModelIndex(); + } while (query.next()); } } bool FeedModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role != Qt::EditRole) - return false; - - QSqlQuery query(db); - - if (index.internalId() < FEEDMODEL_MAX_CATEGORIES && index.internalId() != 0) - { - // We are trying to modify a category - query.prepare("UPDATE categories SET name=:value WHERE id=:id;"); - query.bindValue("value", value.toString()); - query.bindValue("id", index.internalId()); - } - else - { - // We are trying to modify a feed - query.prepare("UPDATE feeds SET name=:value WHERE id=:id;"); - query.bindValue("value", value.toString()); - query.bindValue("id", index.internalId() - FEEDMODEL_MAX_CATEGORIES); - } - - if (!query.exec()) - { - qDebug() << "Query failed" << query.lastError() << query.executedQuery(); - return false; - } - else - { - // Emit the datachanged signal - dataChanged(index, index); - return true; - } -} - -Qt::ItemFlags -FeedModel::flags(const QModelIndex &index) const -{ - Q_UNUSED(index); - return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); -} - -int -FeedModel::rowCount(const QModelIndex &parent) const -{ - if (!parent.isValid()) - { - // Categories count - QSqlQuery query(db); - query.prepare ("SELECT id from categories ORDER by id;"); - if (query.exec()) - { - int row_count = 1; - if (!query.first()) - return 0; - else - while (query.next()) - row_count++; - return row_count; - } - else - return 0; - } - else - { - int category_id = parent.internalId(); - QSqlQuery query(db); - query.prepare("SELECT id from feeds where category=:category;"); - query.bindValue("category", category_id); - if (query.exec()) - { - int row_count = 1; - if (!query.first()) - return 0; - else - while (query.next()) - row_count++; - return row_count; - } - else - return 0; - } + return QStandardItemModel::setData(index, value, role); } bool @@ -199,132 +116,6 @@ FeedModel::addFeed(QString name, QString url, quint32 category_id) return successful; } -int -FeedModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return 1; -} - -QVariant -FeedModel::data(const QModelIndex &index, int role) const -{ - if (role == Qt::DisplayRole) - { - if (index.internalId() == 0) - return QString ("Root"); - if (index.internalId() < FEEDMODEL_MAX_CATEGORIES) - { - QSqlQuery query(db); - query.prepare ("SELECT id, name from categories WHERE id=:category;"); - query.bindValue("category", index.internalId()); - if (query.exec()) - { - if (!query.first()) - return QVariant(QVariant::Invalid); - else - { - return query.value(1).toString(); - } - } - else - return QVariant(QVariant::Invalid); - } - else - { - QSqlQuery query(db); - query.prepare ("SELECT id, category, name, url from feeds WHERE id=:feed;"); - query.bindValue("feed", index.internalId() - FEEDMODEL_MAX_CATEGORIES); - if (query.exec()) - { - if (query.first()) - return query.value(2).toString(); - else - return QVariant(QVariant::Invalid); - } - else - return QVariant(QVariant::Invalid); - } - } - else - return QVariant (QVariant::Invalid); -} - -QModelIndex -FeedModel::parent(const QModelIndex &child) const -{ - if (!child.isValid()) - return QModelIndex (); - - quint32 row; - quint32 id = child.internalId(); - - if (id == 0) - return QModelIndex(); - else if (id < FEEDMODEL_MAX_CATEGORIES) - { - // Get the position of the category - QSqlQuery query (db); - query.prepare ("SELECT id from category;"); - if (query.exec ()) - { - if (query.first ()) - row = 1; - else - return QModelIndex (); - while (query.next ()) - { - row++; - if ((quint64) query.value(0).toInt() == id) - break; - } - - return createIndex (row, 1, 0); - } - else - return QModelIndex(); - } - else - { - quint32 category_id; - // We have a feed here, that actually has a real parent. - // We need to get the ID of the category - id -= FEEDMODEL_MAX_CATEGORIES; - QSqlQuery query (db); - query.prepare ("SELECT category from feeds WHERE id=:id;"); - query.bindValue("id", id); - if (query.exec()) - { - if (!query.first ()) - return QModelIndex(); - else - { - category_id = query.value(0).toInt(); - - // We need to get the position of the feed in the category - query.prepare("SELECT id from feeds WHERE category=:category;"); - query.bindValue("category", category_id); - if (query.exec()) - { - row = 1; - if (!query.first()) - return QModelIndex(); - else - { - while (query.next()) - row++; - return createIndex(row, 1, category_id); - } - } - else - return QModelIndex(); - } - } - else - return QModelIndex(); - } -} - QVariant FeedModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -338,23 +129,16 @@ FeedModel::headerData(int section, Qt::Orientation orientation, int role) const QString FeedModel::getUrl(const QModelIndex &index) { - quint64 id = index.internalId(); - if (id < FEEDMODEL_MAX_CATEGORIES) - return ""; + FeedNode *node = itemFromIndex(index); + return node->url(); +} + +FeedNode* +FeedModel::itemFromIndex(const QModelIndex &index) +{ + if (index.isValid()) + return (FeedNode*) QStandardItemModel::itemFromIndex(index); else - { - QSqlQuery query(db); - query.prepare("SELECT url from feeds WHERE id=:id;"); - query.bindValue("id", id - FEEDMODEL_MAX_CATEGORIES); - if (query.exec()) - { - if (query.first()) - return query.value(0).toString(); - else - return ""; - } - else - return ""; - } + return rootNode; } diff --git a/larss/feednode.cpp b/larss/feednode.cpp new file mode 100644 index 0000000..670c050 --- /dev/null +++ b/larss/feednode.cpp @@ -0,0 +1,40 @@ +#include "include/feednode.h" +#include <QDebug> + +using namespace Larss; + +FeedNode::FeedNode(quint64 id, QString name, QString url) : + nodeId(id), nodeName(name), nodeUrl(url) +{ + setText (name); + qDebug() << "Created node, ID: " << id << " Name: " << name << " Url: " << url; +} + +FeedNode::ItemType +FeedNode::type() +{ + if (nodeId == 0) + return Root; + if (nodeUrl != "") + return Feed; + else + return Category; +} + +quint64 +FeedNode::id() +{ + return nodeId; +} + +QString +FeedNode::name() +{ + return nodeName; +} + +QString +FeedNode::url() +{ + return nodeUrl; +} diff --git a/larss/feedpoller.cpp b/larss/feedpoller.cpp index d25ff93..b6f56f1 100644 --- a/larss/feedpoller.cpp +++ b/larss/feedpoller.cpp @@ -1,6 +1,7 @@ #include "feedpoller.h" #include <QtXml> #include "feedmodel.h" +#include "feednode.h" using namespace Larss; @@ -48,7 +49,8 @@ FeedPoller::poll() else { QModelIndex next_item = workQueue->takeFirst(); - nowLoading = next_item.internalId(); + FeedNode *node = (FeedNode*) next_item.internalPointer(); + nowLoading = node->id(); manager->get(QNetworkRequest(QUrl(model->getUrl(next_item)))); return true; } @@ -67,7 +69,11 @@ FeedPoller::stopPolling () void FeedPoller::queueWork(const QModelIndex &index) { - if (index.internalId() < FEEDMODEL_MAX_CATEGORIES) + qDebug() << index; + if (!index.isValid()) + return; + FeedNode *node = model->itemFromIndex(index); + if (node->type() != FeedNode::Feed) return; workQueue->append(index); } @@ -86,7 +92,7 @@ FeedPoller::networkManagerReplyFinished(QNetworkReply *reply) // Try to catch other news_feed with the same link, so preload all of them. QSqlQuery query(parser->db); query.prepare ("SELECT link from news WHERE feed=:feed"); - query.bindValue("feed", nowLoading - FEEDMODEL_MAX_CATEGORIES); + query.bindValue("feed", nowLoading); if (!query.exec ()) return; @@ -142,7 +148,7 @@ FeedPoller::networkManagerReplyFinished(QNetworkReply *reply) record.setValue("link", link); record.setValue("description", description); record.setValue("content", content); - record.setValue("feed", nowLoading - FEEDMODEL_MAX_CATEGORIES); + record.setValue("feed", nowLoading); if (!parser->insertRecord(-1, record)) qDebug () << "Error inserting record"; @@ -162,7 +168,8 @@ FeedPoller::networkManagerReplyFinished(QNetworkReply *reply) if (!workQueue->isEmpty()) { QModelIndex next_item = workQueue->takeFirst(); - nowLoading = next_item.internalId(); + FeedNode *node = (FeedNode*) next_item.internalPointer(); + nowLoading = node->id(); manager->get(QNetworkRequest(QUrl(model->getUrl(next_item)))); } } diff --git a/larss/feedproxymodel.cpp b/larss/feedproxymodel.cpp deleted file mode 100644 index db8f21e..0000000 --- a/larss/feedproxymodel.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "include/feedproxymodel.h" -#include <QFont> -#include <QSqlRecord> - -using namespace Larss; - -FeedProxyModel::FeedProxyModel(QObject *parent) : - QProxyModel(parent) -{ - -} - -QVariant -FeedProxyModel::data(const QModelIndex &index, int role) const -{ - // Check if this is a feed, and in that case check the number of unread items. - if (index.internalId() > FEEDMODEL_MAX_CATEGORIES) - { - if (role == Qt::DisplayRole) - { - QString feedName = this->model()->data(index, role).toString(); - quint32 unreadCount = parser->getUnreadCount(index); - if (unreadCount > 0) - return QString("%1 (%2)").arg(feedName).arg(unreadCount); - else - return feedName; - } - else if (role == Qt::FontRole) - { - quint32 unreadCount = parser->getUnreadCount(index); - QFont font = this->model()->data(index, role).toString(); - if (unreadCount > 0) - font.setBold(true); - return font; - } - - return this->model()->data(index, role); - } - else - return this->model()->data(index, role); -} - -void -FeedProxyModel::setParser(RssParser *parser) -{ - this->parser = parser; - parser->connect(parser, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(onRssParserDataChanged(QModelIndex,QModelIndex))); -} - -void -FeedProxyModel::onRssParserDataChanged(QModelIndex index, QModelIndex index2) -{ - Q_UNUSED(index); - Q_UNUSED(index2); - // We need to get the feed where the news is, so we can emit dataChanged - // for it. For now we simply propagate the change. - QModelIndex rootIndex = this->model()->index(1, 1, QModelIndex()); - dataChanged(rootIndex, rootIndex); -} diff --git a/larss/mainwindow.cpp b/larss/mainwindow.cpp index 5ad4a06..579993c 100644 --- a/larss/mainwindow.cpp +++ b/larss/mainwindow.cpp @@ -2,7 +2,6 @@ #include "ui_mainwindow.h" #include "editfeeddialog.h" #include "editcategorydialog.h" -#include "feedproxymodel.h" #include <QDebug> #include <QtGui> @@ -27,11 +26,7 @@ MainWindow::MainWindow(QWidget *parent) : feedModel = new FeedModel(db, this); rssParser = new RssParser(db, feedModel, this); - FeedProxyModel *proxyModel = new FeedProxyModel(this); - proxyModel->setModel(feedModel); - proxyModel->setParser(rssParser); - - ui->feedTreeView->setModel(proxyModel); + ui->feedTreeView->setModel(feedModel); // Load the RSSParser, hiding the unnecessary columns ui->newsTableView->setModel(rssParser); @@ -90,6 +85,7 @@ void Larss::MainWindow::on_feedTreeView_clicked(const QModelIndex &index) ui->webViewTitleLabel->setText(""); } + } void Larss::MainWindow::on_newsTableView_clicked(const QModelIndex &index) diff --git a/larss/rssparser.cpp b/larss/rssparser.cpp index f6f84ac..e6ede52 100644 --- a/larss/rssparser.cpp +++ b/larss/rssparser.cpp @@ -1,4 +1,5 @@ #include "rssparser.h" +#include "feednode.h" #include <QDebug> #include <QtXml> #include <QtSql> @@ -121,11 +122,11 @@ Larss::RssParser::setReadStatus(const QModelIndex& index, bool read) quint64 Larss::RssParser::getFeed(const QModelIndex &index) { - quint64 id = index.internalId(); - if (id < FEEDMODEL_MAX_CATEGORIES) + FeedNode *node = model->itemFromIndex (index); + if (node->type() == FeedNode::Category) return 0; else - return (id - FEEDMODEL_MAX_CATEGORIES); + return node->id(); } QString