diff --git a/Larss.pro b/Larss.pro
index 5c684a3..74bcf7e 100644
--- a/Larss.pro
+++ b/Larss.pro
@@ -13,10 +13,12 @@ TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
feedmodel.cpp \
- rssparser.cpp
+ rssparser.cpp \
+ feedpoller.cpp
HEADERS += mainwindow.h \
feedmodel.h \
- rssparser.h
+ rssparser.h \
+ feedpoller.h
FORMS += mainwindow.ui
diff --git a/feedmodel.h b/feedmodel.h
index 232c771..0e6923d 100644
--- a/feedmodel.h
+++ b/feedmodel.h
@@ -4,6 +4,7 @@
#include <QObject>
#include <QAbstractItemModel>
#include <QSqlDatabase>
+#include <QtXml>
namespace Larss {
@@ -70,8 +71,6 @@ public:
*/
bool addFeed (QString name, QString url, quint32 category_id);
-
-
signals:
public slots:
diff --git a/feedpoller.cpp b/feedpoller.cpp
new file mode 100644
index 0000000..94f40a5
--- /dev/null
+++ b/feedpoller.cpp
@@ -0,0 +1,134 @@
+#include "feedpoller.h"
+#include <QtXml>
+#include "feedmodel.h"
+
+using namespace Larss;
+
+FeedPoller::FeedPoller(QObject *parent, RssParser *parser, FeedModel *model) :
+ QThread(parent)
+{
+ this->parser = parser;
+ this->model = model;
+
+ workQueue = new QList<QModelIndex> ();
+ nowLoading = 0;
+
+ rssContent = new QHash<quint32, QString>();
+ poll_active = true;
+
+ // Create the QNetworkAccessManager and connect the loaded signal
+ // with our handler.
+ manager = new QNetworkAccessManager ();
+ manager->connect(manager, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(networkManagerReplyFinished(QNetworkReply*)));
+}
+
+void
+FeedPoller::run()
+{
+
+ // Create the timer that will call the function every second.
+ QTimer *timer = new QTimer ();
+ timer->setInterval(800);
+ timer->connect(timer, SIGNAL(timeout()),
+ this, SLOT(poll()));
+ timer->start();
+
+ QThread::exec();
+}
+
+bool
+FeedPoller::poll()
+{
+ // Poll indefinitely until we are requested to exit.
+ if (nowLoading == 0)
+ {
+ if (workQueue->isEmpty())
+ return false;
+ else
+ {
+ QModelIndex next_item = workQueue->takeFirst();
+ nowLoading = next_item.internalId();
+ manager->get(QNetworkRequest(QUrl(model->getUrl(next_item))));
+ return true;
+ }
+ }
+}
+
+void
+FeedPoller::stopPolling ()
+{
+ poll_active = false;
+}
+
+void
+FeedPoller::queueWork(const QModelIndex &index)
+{
+ workQueue->append(index);
+}
+
+void
+FeedPoller::networkManagerReplyFinished(QNetworkReply *reply)
+{
+ rssContent->insert (nowLoading, reply->readAll());
+
+ // Now update the database with the new data obtained.
+ QDomDocument doc;
+ if (doc.setContent(rssContent->value(nowLoading)))
+ {
+ QDomElement doc_el = doc.documentElement();
+ QDomNodeList items = doc_el.elementsByTagName("item");
+
+ for (quint32 i = 0; i < items.length(); i++)
+ {
+ // Get the i-th news
+ QDomNode item = items.item(i);
+ QDomElement element = item.toElement();
+
+ // Get the data in it
+ QString link = element.elementsByTagName("link").item(0).firstChild().nodeValue();
+ QString title = element.elementsByTagName("title").item(0).firstChild().nodeValue();
+ QString description = element.elementsByTagName("description").item(0).firstChild().nodeValue();
+
+ // We should enable this for RSS 2.0
+ // QString guid = element.elementsByTagName("guid").item(0).firstChild().nodeValue();
+ // QString pubDate = element.elementsByTagName("pubDate").item(0).firstChild().nodeValue();
+
+ // Try to catch other news_feed with the same link
+ QSqlQuery query(parser->db);
+ query.prepare ("SELECT id from news WHERE feed=:feed AND link=:link;");
+ query.bindValue("feed", nowLoading);
+ query.bindValue("link", link);
+ if (query.exec())
+ {
+ if (!query.first())
+ {
+ // That means that no results were found, so let's insert this one.
+ QSqlRecord record = parser->record();
+ record.setValue("time", 0);
+ record.setValue("read", 0);
+ record.setValue("title", title);
+ record.setValue("link", link);
+ record.setValue("description", description);
+ record.setValue("feed", nowLoading - FEEDMODEL_MAX_CATEGORIES);
+
+ if (!parser->insertRecord(-1, record))
+ qDebug () << "Error inserting record";
+ }
+ }
+ }
+ }
+ else
+ qDebug () << "Error parsing the document";
+
+ nowLoading = 0;
+ return;
+
+ // Check if there is work in the queue
+ if (!workQueue->isEmpty())
+ {
+ QModelIndex next_item = workQueue->takeFirst();
+ nowLoading = next_item.internalId();
+ manager->get(QNetworkRequest(QUrl(model->getUrl(next_item))));
+ }
+}
diff --git a/feedpoller.h b/feedpoller.h
new file mode 100644
index 0000000..4494249
--- /dev/null
+++ b/feedpoller.h
@@ -0,0 +1,74 @@
+#ifndef FEEDPOLLER_H
+#define FEEDPOLLER_H
+
+#include <QObject>
+#include <QThread>
+#include <QtSql>
+#include <QtNetwork>
+#include "rssparser.h"
+#include "feedmodel.h"
+
+namespace Larss {
+
+ class FeedPoller : public QThread
+ {
+ Q_OBJECT
+ public:
+ explicit FeedPoller(QObject *parent, RssParser* parser, FeedModel *model);
+ void queueWork (const QModelIndex& index);
+ void stopPolling ();
+
+ signals:
+
+ public slots:
+ void networkManagerReplyFinished(QNetworkReply* reply);
+ bool poll();
+
+ private:
+ /**
+ * @brief The parser of this instance of Larss.
+ */
+ RssParser *parser;
+
+ /**
+ * @brief The FeedModel of this instance of Larss.
+ */
+ FeedModel *model;
+
+ /**
+ * @brief The content of the rss loaded from the various
+ * items in the feedmodel.
+ */
+ QHash<quint32, QString> *rssContent;
+
+ /**
+ * @brief The NetworkAccessManager that will be used to retrieve
+ * the data from sourceUrl.
+ */
+ QNetworkAccessManager *manager;
+
+ /**
+ * @brief An index of the RSS that is currently being loaded, or 0
+ * if there is nothing in the queue.
+ */
+ quint32 nowLoading;
+
+ /**
+ * @brief Queue of item that needs to be refreshed.
+ */
+ QList<QModelIndex> *workQueue;
+
+ /**
+ * @brief If the thread is requested to polling or not.
+ */
+ bool poll_active;
+
+ /**
+ * @brief Real work of the thread.
+ */
+ void run();
+
+ };
+}
+
+#endif // FEEDPOLLER_H
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 3174d4a..86878b6 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -30,6 +30,9 @@ MainWindow::MainWindow(QWidget *parent) :
ui->newsTableView->setColumnHidden(4, true); // Description
ui->newsTableView->setColumnHidden(6, true); // Read state
ui->newsTableView->verticalHeader()->setHidden(true);
+
+ poller = new FeedPoller (this, rssParser, feedModel);
+ poller->start();
}
MainWindow::~MainWindow()
@@ -40,7 +43,7 @@ MainWindow::~MainWindow()
void MainWindow::do_exit()
{
- // Some cleanup will be need here in the future
+ poller->stopPolling();
QApplication::exit();
}
@@ -53,7 +56,7 @@ void MainWindow::on_actionExit_activated()
void Larss::MainWindow::on_feedTreeView_clicked(const QModelIndex &index)
{
// Trigger refresh of selected item
- rssParser->loadItem(index);
+ poller->queueWork(index);
// Set the active filter
quint64 feed_id;
diff --git a/mainwindow.h b/mainwindow.h
index 40338d0..11d1003 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -4,6 +4,7 @@
#include <QMainWindow>
#include "rssparser.h"
#include "feedmodel.h"
+#include "feedpoller.h"
#include <QSqlDatabase>
namespace Ui {
@@ -34,6 +35,7 @@ private:
QSqlDatabase db;
FeedModel *feedModel;
RssParser *rssParser;
+ FeedPoller *poller;
};
}
diff --git a/rssparser.cpp b/rssparser.cpp
index 04630c5..a9a1cbf 100644
--- a/rssparser.cpp
+++ b/rssparser.cpp
@@ -26,20 +26,7 @@ Larss::RssParser::RssParser(QSqlDatabase db, FeedModel *model, QObject *parent)
// Select manual submit so user cannot modify content directly
setEditStrategy(QSqlTableModel::OnRowChange);
-
- // Set the source to an empty string, that means no source
- rssContent = new QHash<quint32, QString>();
- workQueue = new QList<QModelIndex> ();
this->model = model;
- nowLoading = 0;
- activeItem = 0;
-
- // Create the QNetworkAccessManager and connect the loaded signal
- // with our handler.
- manager = new QNetworkAccessManager (this);
- manager->connect(manager, SIGNAL(finished(QNetworkReply*)),
- this, SLOT(networkManagerReplyFinished(QNetworkReply*)));
-
select();
}
@@ -81,10 +68,6 @@ Larss::RssParser::headerData(int section, Qt::Orientation orientation, int role)
Larss::RssParser::~RssParser()
{
- db.close();
- delete manager;
- delete rssContent;
- delete workQueue;
}
QVariant
@@ -105,95 +88,6 @@ Larss::RssParser::data(const QModelIndex &idx, int role) const
return QSqlTableModel::data(idx, role);
}
-void
-Larss::RssParser::loadItem(const QModelIndex &index)
-{
- if (index.internalId() < FEEDMODEL_MAX_CATEGORIES)
- return;
-
- if (nowLoading != 0)
- {
- // We should queue this work and wait till there is
- // the networkmanager free to do it.
- workQueue->append(index);
- }
- else
- {
- nowLoading = index.internalId();
- manager->get(QNetworkRequest(QUrl(model->getUrl(index))));
- }
-}
-
-void
-Larss::RssParser::networkManagerReplyFinished(QNetworkReply *reply)
-{
- rssContent->insert (nowLoading, reply->readAll());
-
- // Now update the database with the new data obtained.
- QDomDocument doc;
- if (doc.setContent(rssContent->value(nowLoading)))
- {
- QDomElement doc_el = doc.documentElement();
- QDomNodeList items = doc_el.elementsByTagName("item");
-
- for (quint32 i = 0; i < items.length(); i++)
- {
- // Get the i-th news
- QDomNode item = items.item(i);
- QDomElement element = item.toElement();
-
- // Get the data in it
- QString link = element.elementsByTagName("link").item(0).firstChild().nodeValue();
- QString title = element.elementsByTagName("title").item(0).firstChild().nodeValue();
- QString description = element.elementsByTagName("description").item(0).firstChild().nodeValue();
-
- // We should enable this for RSS 2.0
- // QString guid = element.elementsByTagName("guid").item(0).firstChild().nodeValue();
- // QString pubDate = element.elementsByTagName("pubDate").item(0).firstChild().nodeValue();
-
- // Try to catch other news_feed with the same link
- QSqlQuery query(db);
- query.prepare ("SELECT id from news WHERE feed=:feed AND link=:link;");
- query.bindValue("feed", nowLoading);
- query.bindValue("link", link);
- if (query.exec())
- {
- if (!query.first())
- {
- // That means that no results were found, so let's insert this one.
- QSqlRecord record = this->record();
- record.setValue("time", 0);
- record.setValue("read", 0);
- record.setValue("title", title);
- record.setValue("link", link);
- record.setValue("description", description);
- record.setValue("feed", nowLoading - FEEDMODEL_MAX_CATEGORIES);
-
- if (!insertRecord(-1, record))
- qDebug () << "Error inserting record";
- }
- }
- }
- }
- else
- qDebug () << "Error parsing the document";
-
-
- if (activeItem == nowLoading)
- {
- // We shall call something like dataChanged in here
- }
- nowLoading = 0;
-
- // Check if there is work in the queue
- if (!workQueue->isEmpty())
- {
- QModelIndex next_item = workQueue->takeFirst();
- nowLoading = next_item.internalId();
- manager->get(QNetworkRequest(QUrl(model->getUrl(next_item))));
- }
-}
-
QString
Larss::RssParser::getLink(const QModelIndex &index)
{
diff --git a/rssparser.h b/rssparser.h
index 1a2a732..4b42c93 100644
--- a/rssparser.h
+++ b/rssparser.h
@@ -24,11 +24,6 @@ namespace Larss {
~RssParser();
/**
- * @brief Reload the feed from a given NewsFeed.
- */
- void loadItem (const QModelIndex& index);
-
- /**
* @brief Function that tells the views that use this model
* what to display in the title of the columns.
*/
@@ -61,50 +56,21 @@ namespace Larss {
*/
void selectActiveFeed (quint64 feed_id);
-
- signals:
-
- public slots:
- void networkManagerReplyFinished (QNetworkReply* reply);
-
- private:
/**
* @brief Database where all the news will be loaded and saved.
*/
QSqlDatabase db;
- /**
- * @brief The url of the current rss feed.
- */
- FeedModel *model;
-
- /**
- * @brief The content of the rss loaded from the various
- * items in the feedmodel.
- */
- QHash<quint32, QString> *rssContent;
-
- /**
- * @brief The NetworkAccessManager that will be used to retrieve
- * the data from sourceUrl.
- */
- QNetworkAccessManager *manager;
+ signals:
- /**
- * @brief An index of the RSS that is currently being loaded, or 0
- * if there is nothing in the queue.
- */
- quint32 nowLoading;
+ public slots:
- /**
- * @brie A pointer to the active news feed.
- */
- quint32 activeItem;
+ private:
/**
- * @brief Queue of item that needs to be refreshed.
+ * @brief The FeedModel
*/
- QList<QModelIndex> *workQueue;
+ FeedModel *model;
};
}