282 lines
9.4 KiB
C++
Executable File
282 lines
9.4 KiB
C++
Executable File
#include "core/feedsmodelstandardfeed.h"
|
|
|
|
#include "core/defs.h"
|
|
#include "core/settings.h"
|
|
#include "core/parsingfactory.h"
|
|
#include "core/databasefactory.h"
|
|
#include "core/networkfactory.h"
|
|
#include "core/textfactory.h"
|
|
#include "gui/iconfactory.h"
|
|
#include "gui/iconthemefactory.h"
|
|
|
|
#include <QVariant>
|
|
#include <QTextCodec>
|
|
#include <QSqlQuery>
|
|
|
|
|
|
FeedsModelStandardFeed::FeedsModelStandardFeed(FeedsModelRootItem *parent_item)
|
|
: FeedsModelFeed(parent_item) {
|
|
}
|
|
|
|
FeedsModelStandardFeed::~FeedsModelStandardFeed() {
|
|
qDebug("Destroying FeedsModelStandardFeed instance.");
|
|
}
|
|
|
|
FeedsModelStandardFeed *FeedsModelStandardFeed::loadFromRecord(const QSqlRecord &record) {
|
|
FeedsModelStandardFeed *feed = new FeedsModelStandardFeed(NULL);
|
|
|
|
feed->setTitle(record.value(FDS_DB_TITLE_INDEX).toString());
|
|
feed->setId(record.value(FDS_DB_ID_INDEX).toInt());
|
|
feed->setDescription(record.value(FDS_DB_DESCRIPTION_INDEX).toString());
|
|
feed->setCreationDate(TextFactory::parseDateTime(record.value(FDS_DB_DCREATED_INDEX).value<qint64>()).toLocalTime());
|
|
feed->setIcon(IconFactory::fromByteArray(record.value(FDS_DB_ICON_INDEX).toByteArray()));
|
|
feed->setEncoding(record.value(FDS_DB_ENCODING_INDEX).toString());
|
|
feed->setUrl(record.value(FDS_DB_URL_INDEX).toString());
|
|
feed->updateCounts();
|
|
|
|
return feed;
|
|
}
|
|
|
|
QVariant FeedsModelStandardFeed::data(int column, int role) const {
|
|
switch (role) {
|
|
case Qt::DisplayRole:
|
|
if (column == FDS_MODEL_TITLE_INDEX) {
|
|
return m_title;
|
|
}
|
|
else if (column == FDS_MODEL_COUNTS_INDEX) {
|
|
return QString("(%1)").arg(QString::number(countOfUnreadMessages()));
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
|
|
case Qt::EditRole:
|
|
if (column == FDS_MODEL_TITLE_INDEX) {
|
|
return m_title;
|
|
}
|
|
else if (column == FDS_MODEL_COUNTS_INDEX) {
|
|
return countOfUnreadMessages();
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
|
|
case Qt::DecorationRole:
|
|
if (column == FDS_MODEL_TITLE_INDEX) {
|
|
return m_icon;
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
|
|
case Qt::ToolTipRole:
|
|
if (column == FDS_MODEL_TITLE_INDEX) {
|
|
return QObject::tr("%1 (%2)\n"
|
|
"%3\n\n"
|
|
"Encoding: %4").arg(m_title,
|
|
FeedsModelFeed::typeToString(m_type),
|
|
m_description,
|
|
m_encoding);
|
|
}
|
|
else if (column == FDS_MODEL_COUNTS_INDEX) {
|
|
return QObject::tr("%n unread message(s).", "", countOfUnreadMessages());
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
|
|
case Qt::TextAlignmentRole:
|
|
if (column == FDS_MODEL_COUNTS_INDEX) {
|
|
return Qt::AlignCenter;
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
|
|
void FeedsModelStandardFeed::update() {
|
|
QByteArray feed_contents;
|
|
int download_timeout = Settings::instance()->value(APP_CFG_FEEDS,
|
|
"download_timeout",
|
|
DOWNLOAD_TIMEOUT).toInt();
|
|
|
|
// TODO: Provide download time-measures debugging
|
|
// outputs here.
|
|
QNetworkReply::NetworkError download_result = NetworkFactory::downloadFeedFile(url(),
|
|
download_timeout,
|
|
feed_contents,
|
|
this);
|
|
|
|
if (download_result != QNetworkReply::NoError) {
|
|
qWarning("Error during fetching of new messages for feed '%s' (id %d).",
|
|
qPrintable(url()),
|
|
id());
|
|
return;
|
|
}
|
|
|
|
// Encode downloaded data for further parsing.
|
|
QTextCodec *codec = QTextCodec::codecForName(encoding().toLocal8Bit());
|
|
QString formatted_feed_contents;
|
|
|
|
if (codec == NULL) {
|
|
// No suitable codec for this encoding was found.
|
|
// Use non-converted data.
|
|
formatted_feed_contents = feed_contents;
|
|
}
|
|
else {
|
|
formatted_feed_contents = codec->toUnicode(feed_contents);
|
|
}
|
|
|
|
// Feed data are downloaded and encoded.
|
|
// Parse data and obtain messages.
|
|
QList<Message> messages;
|
|
|
|
switch (type()) {
|
|
case FeedsModelFeed::StandardRss0X:
|
|
case FeedsModelFeed::StandardRss2X:
|
|
messages = ParsingFactory::parseAsRSS20(formatted_feed_contents);
|
|
break;
|
|
|
|
case FeedsModelFeed::StandardRdf:
|
|
messages = ParsingFactory::parseAsRDF(formatted_feed_contents);
|
|
break;
|
|
|
|
case FeedsModelFeed::StandardAtom10:
|
|
messages = ParsingFactory::parseAsATOM10(formatted_feed_contents);
|
|
|
|
// TODO: Add support for other standard formats.
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
updateMessages(messages);
|
|
}
|
|
|
|
bool FeedsModelStandardFeed::removeItself() {
|
|
QSqlDatabase database = DatabaseFactory::instance()->connection("FeedsModelStandardFeed",
|
|
DatabaseFactory::FromSettings);
|
|
QSqlQuery query_remove(database);
|
|
|
|
query_remove.setForwardOnly(true);
|
|
|
|
// Remove all messages from this standard feed.
|
|
query_remove.prepare("DELETE FROM Messages WHERE feed = :feed;");
|
|
query_remove.bindValue(":feed", id());
|
|
|
|
if (!query_remove.exec()) {
|
|
return false;
|
|
}
|
|
|
|
// Remove feed itself.
|
|
query_remove.prepare("DELETE FROM Feeds WHERE id = :feed;");
|
|
query_remove.bindValue(":feed", id());
|
|
|
|
return query_remove.exec();
|
|
}
|
|
|
|
void FeedsModelStandardFeed::updateMessages(const QList<Message> &messages) {
|
|
int feed_id = id(), message_id;
|
|
qint64 message_creation_date;
|
|
QSqlDatabase database = DatabaseFactory::instance()->connection("FeedsModelStandardFeed",
|
|
DatabaseFactory::FromSettings);
|
|
|
|
// Prepare queries.
|
|
QSqlQuery query_select(database);
|
|
QSqlQuery query_insert(database);
|
|
QSqlQuery query_update(database);
|
|
|
|
// Used to check if give feed contains with message with given
|
|
// title and url.
|
|
query_select.setForwardOnly(true);
|
|
query_select.prepare("SELECT id, feed, date_created FROM Messages "
|
|
"WHERE feed = :feed AND title = :title AND url = :url;");
|
|
|
|
// Used to insert new messages.
|
|
query_insert.setForwardOnly(true);
|
|
query_insert.prepare("INSERT INTO Messages "
|
|
"(feed, title, url, author, date_created, contents) "
|
|
"VALUES (:feed, :title, :url, :author, :date_created, :contents);");
|
|
|
|
// Used to update existing messages of given feed.
|
|
// NOTE: Messages are updated if its creation date
|
|
// is changed.
|
|
query_update.setForwardOnly(true);
|
|
query_update.prepare("UPDATE Messages "
|
|
"SET title = :title, url = :url, author = :author, "
|
|
"date_created = :date_created, contents = :contents, "
|
|
"read = 0, important = 0, deleted = 0 "
|
|
"WHERE id = :id");
|
|
|
|
if (!database.transaction()) {
|
|
database.rollback();
|
|
|
|
qDebug("Transaction start for message downloader failed.");
|
|
return;
|
|
}
|
|
|
|
foreach (const Message &message, messages) {
|
|
query_select.bindValue(":feed", feed_id);
|
|
query_select.bindValue(":title", message.m_title);
|
|
query_select.bindValue(":url", message.m_url);
|
|
query_select.exec();
|
|
|
|
if (query_select.next()) {
|
|
// Message with this title & url probably exists in current feed.
|
|
message_id = query_select.value(0).toInt();
|
|
message_creation_date = query_select.value(2).value<qint64>();
|
|
}
|
|
else {
|
|
message_id = -1;
|
|
}
|
|
|
|
query_select.finish();
|
|
|
|
if (message_id == -1) {
|
|
// Message is not fetched in this feed yet. Add it.
|
|
query_insert.bindValue(":feed", feed_id);
|
|
query_insert.bindValue(":title", message.m_title);
|
|
query_insert.bindValue(":url", message.m_url);
|
|
query_insert.bindValue(":author", message.m_author);
|
|
query_insert.bindValue(":date_created", message.m_created.toMSecsSinceEpoch());
|
|
query_insert.bindValue(":contents", message.m_contents);
|
|
|
|
query_insert.exec();
|
|
query_insert.finish();
|
|
}
|
|
else if (message.m_createdFromFeed &&
|
|
message_creation_date != 0 &&
|
|
message_creation_date > message.m_created.toMSecsSinceEpoch()) {
|
|
qDebug("Message '%s' (id %d) was updated in the feed, updating too.",
|
|
qPrintable(message.m_title),
|
|
message_id);
|
|
|
|
// TODO: Check if this is actually working.
|
|
|
|
// Message with given title/url is already persistently
|
|
// stored in given feed.
|
|
// Creation data of the message was obtained from
|
|
// feed itself. We can update this message.
|
|
query_update.bindValue(":title", message.m_title);
|
|
query_update.bindValue(":url", message.m_url);
|
|
query_update.bindValue(":author", message.m_author);
|
|
query_update.bindValue(":date_created", message.m_created.toMSecsSinceEpoch());
|
|
query_update.bindValue(":contents", message.m_contents);
|
|
query_update.bindValue(":id", message_id);
|
|
|
|
query_update.exec();
|
|
query_update.finish();
|
|
}
|
|
}
|
|
|
|
if (!database.commit()) {
|
|
database.rollback();
|
|
|
|
qDebug("Transaction commit for message downloader failed.");
|
|
}
|
|
}
|