rssguard/src/core/messagesmodel.cpp

450 lines
13 KiB
C++
Raw Normal View History

2013-12-21 21:08:52 +01:00
#include "core/messagesmodel.h"
2013-11-17 16:41:44 +01:00
#include "core/defs.h"
2013-11-24 21:00:40 +01:00
#include "core/textfactory.h"
2013-11-15 22:09:38 +01:00
#include "core/databasefactory.h"
2013-11-17 16:41:44 +01:00
#include "gui/iconthemefactory.h"
2013-12-21 21:08:52 +01:00
#include "qtsingleapplication/qtsingleapplication.h"
#include <QSqlRecord>
#include <QSqlError>
#include <QSqlQuery>
2013-11-09 19:04:00 +01:00
2013-11-15 22:09:38 +01:00
MessagesModel::MessagesModel(QObject *parent)
2013-11-24 14:44:45 +01:00
: QSqlTableModel(parent,
DatabaseFactory::instance()->connection("MessagesModel",
2014-01-21 07:55:10 +01:00
DatabaseFactory::FromSettings)) {
2013-11-13 21:49:47 +01:00
setObjectName("MessagesModel");
2013-11-17 16:41:44 +01:00
setupFonts();
2013-11-18 21:45:15 +01:00
setupIcons();
2013-11-17 16:41:44 +01:00
setupHeaderData();
2013-11-18 21:45:15 +01:00
// Set desired table and edit strategy.
// NOTE: Changes to the database are actually NOT submitted
2014-01-02 14:17:15 +01:00
// via model, but via DIRECT SQL calls are used to do persistent messages.
2013-11-20 21:54:30 +01:00
setEditStrategy(QSqlTableModel::OnManualSubmit);
2013-11-18 21:45:15 +01:00
setTable("Messages");
loadMessages(QList<int>());
2013-11-15 22:09:38 +01:00
}
MessagesModel::~MessagesModel() {
qDebug("Destroying MessagesModel instance.");
2013-11-13 21:49:47 +01:00
}
2014-01-14 14:42:20 +01:00
2013-11-18 21:45:15 +01:00
void MessagesModel::setupIcons() {
2014-02-02 10:27:11 +01:00
m_favoriteIcon = IconThemeFactory::instance()->fromTheme("mail-mark-favorite");
m_readIcon = IconThemeFactory::instance()->fromTheme("mail-mark-read");
m_unreadIcon = IconThemeFactory::instance()->fromTheme("mail-mark-unread");
2013-11-18 21:45:15 +01:00
}
void MessagesModel::fetchAll() {
while (canFetchMore()) {
fetchMore();
}
}
2013-11-17 16:41:44 +01:00
void MessagesModel::setupFonts() {
m_normalFont = QtSingleApplication::font("MessagesView");
m_boldFont = m_normalFont;
m_boldFont.setBold(true);
}
void MessagesModel::loadMessages(const QList<int> feed_ids) {
m_currentFeeds = feed_ids;
QString assembled_ids = textualFeeds().join(", ");
2014-02-07 16:57:16 +01:00
setFilter(QString("feed IN (%1) AND is_deleted = 0").arg(assembled_ids));
select();
fetchAll();
qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids));
}
QStringList MessagesModel::textualFeeds() const {
2013-11-18 21:45:15 +01:00
QStringList stringy_ids;
2014-01-10 09:18:29 +01:00
stringy_ids.reserve(m_currentFeeds.size());
2013-11-18 21:45:15 +01:00
foreach (int feed_id, m_currentFeeds) {
2013-11-18 21:45:15 +01:00
stringy_ids.append(QString::number(feed_id));
}
return stringy_ids;
2013-11-18 21:45:15 +01:00
}
2013-11-24 14:44:45 +01:00
int MessagesModel::messageId(int row_index) const {
return record(row_index).value(MSG_DB_ID_INDEX).toInt();
}
2013-11-19 21:25:55 +01:00
Message MessagesModel::messageAt(int row_index) const {
QSqlRecord rec = record(row_index);
Message message;
2013-11-20 21:54:30 +01:00
// Fill Message object with details.
2013-11-19 21:25:55 +01:00
message.m_author = rec.value(MSG_DB_AUTHOR_INDEX).toString();
message.m_contents = rec.value(MSG_DB_CONTENTS_INDEX).toString();
message.m_title = rec.value(MSG_DB_TITLE_INDEX).toString();
message.m_url = rec.value(MSG_DB_URL_INDEX).toString();
2014-01-02 19:24:40 +01:00
message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value<qint64>());
2013-11-19 21:25:55 +01:00
return message;
}
2013-11-13 21:49:47 +01:00
void MessagesModel::setupHeaderData() {
2013-11-18 21:45:15 +01:00
m_headerData << tr("Id") << tr("Read") << tr("Deleted") << tr("Important") <<
tr("Feed") << tr("Title") << tr("Url") << tr("Author") <<
2013-12-24 13:58:12 +01:00
tr("Created on") << tr("Contents");
2013-12-13 16:35:52 +01:00
m_tooltipData << tr("Id of the message.") << tr("Is message read?") <<
tr("Is message deleted?") << tr("Is message important?") <<
tr("Id of feed which this message belongs to.") <<
tr("Title of the message.") << tr("Url of the message.") <<
tr("Author of the message.") << tr("Creation date of the message.") <<
2013-12-24 13:58:12 +01:00
tr("Contents of the message.");
2013-11-15 22:09:38 +01:00
}
2013-12-14 15:45:47 +01:00
Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const {
Q_UNUSED(index)
2013-11-15 22:09:38 +01:00
2014-01-17 07:23:18 +01:00
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
2013-11-13 21:49:47 +01:00
}
2013-11-20 21:54:30 +01:00
QVariant MessagesModel::data(int row, int column, int role) const {
return data(index(row, column), role);
}
2013-12-14 15:45:47 +01:00
QVariant MessagesModel::data(const QModelIndex &index, int role) const {
2013-11-18 21:45:15 +01:00
switch (role) {
2013-11-29 22:00:08 +01:00
// Human readable data for viewing.
2013-11-19 21:25:55 +01:00
case Qt::DisplayRole: {
2013-12-14 15:45:47 +01:00
int index_column = index.column();
2013-12-24 13:58:12 +01:00
if (index_column == MSG_DB_DCREATED_INDEX) {
2014-01-02 12:11:50 +01:00
return TextFactory::parseDateTime(QSqlTableModel::data(index,
role).value<qint64>()).toLocalTime().toString(Qt::DefaultLocaleShortDate);
}
else if (index_column == MSG_DB_AUTHOR_INDEX) {
QString author_name = QSqlTableModel::data(index, role).toString();
return author_name.isEmpty() ? "-" : author_name;
}
else if (index_column != MSG_DB_IMPORTANT_INDEX &&
index_column != MSG_DB_READ_INDEX) {
2013-12-14 15:45:47 +01:00
return QSqlTableModel::data(index, role);
2013-11-19 21:25:55 +01:00
}
else {
return QVariant();
}
}
2013-11-18 21:45:15 +01:00
case Qt::EditRole:
2013-12-14 15:45:47 +01:00
return QSqlTableModel::data(index, role);
2013-11-17 16:41:44 +01:00
2013-11-18 21:45:15 +01:00
case Qt::FontRole:
2013-12-14 15:45:47 +01:00
return record(index.row()).value(MSG_DB_READ_INDEX).toInt() == 1 ?
2013-11-18 21:45:15 +01:00
m_normalFont :
m_boldFont;
2013-11-17 16:41:44 +01:00
2013-11-18 21:45:15 +01:00
case Qt::DecorationRole: {
2013-12-14 15:45:47 +01:00
int index_column = index.column();
2013-11-17 16:41:44 +01:00
2013-11-18 21:45:15 +01:00
if (index_column == MSG_DB_READ_INDEX) {
2013-12-14 15:45:47 +01:00
return record(index.row()).value(MSG_DB_READ_INDEX).toInt() == 1 ?
2013-11-18 21:45:15 +01:00
m_readIcon :
m_unreadIcon;
}
2013-11-19 21:25:55 +01:00
else if (index_column == MSG_DB_IMPORTANT_INDEX) {
2013-12-14 15:45:47 +01:00
return record(index.row()).value(MSG_DB_IMPORTANT_INDEX).toInt() == 1 ?
2013-11-19 21:25:55 +01:00
m_favoriteIcon :
QVariant();
}
2013-11-18 21:45:15 +01:00
else {
return QVariant();
}
}
2013-11-17 16:41:44 +01:00
2013-11-18 21:45:15 +01:00
default:
return QVariant();
}
2013-11-17 16:41:44 +01:00
}
2013-12-14 15:45:47 +01:00
bool MessagesModel::setMessageRead(int row_index, int read) {
if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) {
// Read status is the same is the one currently set.
// In that case, no extra work is needed.
return true;
}
QSqlDatabase db_handle = database();
if (!db_handle.transaction()) {
qWarning("Starting transaction for message read change.");
return false;
}
2013-11-20 21:54:30 +01:00
// Rewrite "visible" data in the model.
bool working_change = setData(index(row_index, MSG_DB_READ_INDEX),
read);
if (!working_change) {
// If rewriting in the model failed, then cancel all actions.
2013-12-14 15:45:47 +01:00
qDebug("Setting of new data to the model failed for message read change.");
db_handle.rollback();
return false;
}
int message_id;
2013-12-31 17:33:42 +01:00
QSqlQuery query_read_msg(db_handle);
query_read_msg.setForwardOnly(true);
2014-02-07 16:57:16 +01:00
if (!query_read_msg.prepare("UPDATE messages SET is_read = :read "
2013-12-31 17:33:42 +01:00
"WHERE id = :id")) {
qWarning("Query preparation failed for message read change.");
2013-12-14 15:45:47 +01:00
db_handle.rollback();
return false;
}
// Rewrite the actual data in the database itself.
message_id = messageId(row_index);
2013-12-31 17:33:42 +01:00
query_read_msg.bindValue(":id", message_id);
query_read_msg.bindValue(":read", read);
query_read_msg.exec();
// Commit changes.
if (db_handle.commit()) {
// If commit succeeded, then emit changes, so that view
// can reflect.
emit dataChanged(index(row_index, 0),
index(row_index, columnCount() - 1));
emit feedCountsChanged();
return true;
}
else {
return db_handle.rollback();;
}
2013-11-20 21:54:30 +01:00
}
2013-12-14 15:45:47 +01:00
bool MessagesModel::switchMessageImportance(int row_index) {
QSqlDatabase db_handle = database();
if (!db_handle.transaction()) {
qWarning("Starting transaction for message importance switch failed.");
return false;
}
2013-11-20 21:54:30 +01:00
QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX);
2013-12-03 21:39:26 +01:00
int current_importance = data(target_index, Qt::EditRole).toInt();
2013-11-20 21:54:30 +01:00
// Rewrite "visible" data in the model.
bool working_change = current_importance == 1 ?
setData(target_index, 0) :
setData(target_index, 1);
if (!working_change) {
// If rewriting in the model failed, then cancel all actions.
2013-12-14 15:45:47 +01:00
qDebug("Setting of new data to the model failed for message importance change.");
db_handle.rollback();
return false;
}
int message_id;
2013-12-31 17:33:42 +01:00
QSqlQuery query_importance_msg(db_handle);
query_importance_msg.setForwardOnly(true);
2014-02-07 16:57:16 +01:00
if (!query_importance_msg.prepare("UPDATE messages SET is_important = :important "
2013-12-31 17:33:42 +01:00
"WHERE id = :id")) {
qWarning("Query preparation failed for message importance switch.");
2013-12-14 15:45:47 +01:00
db_handle.rollback();
return false;
}
message_id = messageId(row_index);
2013-12-31 17:33:42 +01:00
query_importance_msg.bindValue(":id", message_id);
query_importance_msg.bindValue(":important",
current_importance == 1 ? 0 : 1);
query_importance_msg.exec();
// Commit changes.
if (db_handle.commit()) {
// If commit succeeded, then emit changes, so that view
// can reflect.
emit dataChanged(index(row_index, 0),
index(row_index, columnCount() - 1));
return true;
}
else {
return db_handle.rollback();
}
2013-11-20 21:54:30 +01:00
}
2013-11-24 14:44:45 +01:00
bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages) {
2013-12-14 15:45:47 +01:00
QSqlDatabase db_handle = database();
if (!db_handle.transaction()) {
2013-11-24 14:44:45 +01:00
qWarning("Starting transaction for batch message importance switch failed.");
return false;
}
int message_id, importance;
2013-12-31 17:33:42 +01:00
QSqlQuery query_importance_msg(db_handle);
query_importance_msg.setForwardOnly(true);
2014-02-07 16:57:16 +01:00
if (!query_importance_msg.prepare("UPDATE messages SET is_important = :important "
2013-12-31 17:33:42 +01:00
"WHERE id = :id")) {
2013-11-24 14:44:45 +01:00
qWarning("Query preparation failed for message importance switch.");
2013-12-14 15:45:47 +01:00
db_handle.rollback();
2013-11-24 14:44:45 +01:00
return false;
}
foreach (const QModelIndex &message, messages) {
message_id = messageId(message.row());
2013-12-03 21:39:26 +01:00
importance = data(message.row(), MSG_DB_IMPORTANT_INDEX, Qt::EditRole).toInt();
2013-11-24 14:44:45 +01:00
2013-12-31 17:33:42 +01:00
query_importance_msg.bindValue(":id", message_id);
query_importance_msg.bindValue(":important",
importance == 1 ? 0 : 1);
query_importance_msg.exec();
2013-11-24 14:44:45 +01:00
}
// Commit changes.
if (db_handle.commit()) {
2013-11-24 14:44:45 +01:00
// FULLY reload the model if underlying data is changed.
select();
fetchAll();
return true;
}
else {
return db_handle.rollback();
}
}
bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int deleted) {
2013-12-14 15:45:47 +01:00
QSqlDatabase db_handle = database();
if (!db_handle.transaction()) {
2013-12-08 14:02:28 +01:00
qWarning("Starting transaction for batch message deletion.");
return false;
}
int message_id;
QSqlQuery query_delete_msg(db_handle);
2013-12-31 17:33:42 +01:00
query_delete_msg.setForwardOnly(true);
2014-02-07 16:57:16 +01:00
if (!query_delete_msg.prepare("UPDATE messages SET is_deleted = :deleted "
2013-12-08 14:02:28 +01:00
"WHERE id = :id")) {
qWarning("Query preparation failed for message deletion.");
2013-12-14 15:45:47 +01:00
db_handle.rollback();
2013-12-08 14:02:28 +01:00
return false;
}
2013-11-24 14:44:45 +01:00
2013-12-08 14:02:28 +01:00
foreach (const QModelIndex &message, messages) {
message_id = messageId(message.row());
query_delete_msg.bindValue(":id", message_id);
query_delete_msg.bindValue(":deleted", deleted);
query_delete_msg.exec();
}
// Commit changes.
if (db_handle.commit()) {
// FULLY reload the model if underlying data is changed.
select();
fetchAll();
emit feedCountsChanged();
2013-12-08 14:02:28 +01:00
return true;
}
else {
return db_handle.rollback();
}
2013-11-24 14:44:45 +01:00
}
bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, int read) {
2013-12-14 15:45:47 +01:00
QSqlDatabase db_handle = database();
if (!db_handle.transaction()) {
2013-12-08 14:02:28 +01:00
qWarning("Starting transaction for batch message read change.");
return false;
}
int message_id;
2013-12-26 15:56:37 +01:00
QSqlQuery query_read_msg(db_handle);
2013-12-31 17:33:42 +01:00
query_read_msg.setForwardOnly(true);
2014-02-07 16:57:16 +01:00
if (!query_read_msg.prepare("UPDATE messages SET is_read = :read "
2013-12-31 17:33:42 +01:00
"WHERE id = :id")) {
2013-12-08 14:02:28 +01:00
qWarning("Query preparation failed for message read change.");
2013-12-14 15:45:47 +01:00
db_handle.rollback();
2013-12-08 14:02:28 +01:00
return false;
}
2013-11-24 14:44:45 +01:00
2013-12-08 14:02:28 +01:00
foreach (const QModelIndex &message, messages) {
message_id = messageId(message.row());
2013-12-26 15:56:37 +01:00
query_read_msg.bindValue(":id", message_id);
query_read_msg.bindValue(":read", read);
query_read_msg.exec();
2013-12-08 14:02:28 +01:00
}
// Commit changes.
if (db_handle.commit()) {
// FULLY reload the model if underlying data is changed.
select();
fetchAll();
emit feedCountsChanged();
return true;
}
else {
return db_handle.rollback();
}
2013-11-29 22:00:08 +01:00
}
2013-11-13 21:49:47 +01:00
QVariant MessagesModel::headerData(int section,
Qt::Orientation orientation,
int role) const {
2013-12-12 10:10:17 +01:00
Q_UNUSED(orientation)
2013-11-13 21:49:47 +01:00
switch (role) {
case Qt::DisplayRole:
2013-11-18 21:45:15 +01:00
// Display textual headers for all columns except "read" and
// "important" columns.
if (section != MSG_DB_READ_INDEX && section != MSG_DB_IMPORTANT_INDEX) {
2013-11-17 20:42:02 +01:00
return m_headerData.at(section);
}
else {
return QVariant();
}
2013-11-13 21:49:47 +01:00
case Qt::ToolTipRole:
2013-12-13 16:35:52 +01:00
return m_tooltipData.at(section);
2013-11-17 16:41:44 +01:00
case Qt::EditRole:
2013-11-13 21:49:47 +01:00
return m_headerData.at(section);
2013-11-18 21:45:15 +01:00
// Display icons for "read" and "important" columns.
2013-11-17 20:42:02 +01:00
case Qt::DecorationRole: {
switch (section) {
2013-11-18 21:45:15 +01:00
case MSG_DB_READ_INDEX:
2013-11-17 20:42:02 +01:00
return m_readIcon;
2013-11-18 21:45:15 +01:00
case MSG_DB_IMPORTANT_INDEX:
2013-11-17 20:42:02 +01:00
return m_favoriteIcon;
default:
return QVariant();
}
}
2013-11-13 21:49:47 +01:00
default:
return QVariant();
}
2013-11-09 19:04:00 +01:00
}