Many refactorings in model/items, some tiny preparations for messages operation - they moved into feed classes.

This commit is contained in:
Martin Rotter 2015-11-12 10:53:17 +01:00
parent d0b00915f3
commit d5ff059543
14 changed files with 259 additions and 200 deletions

View File

@ -439,85 +439,16 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) {
}
}
bool FeedsModel::markFeedsRead(const QList<Feed*> &feeds, int read) {
QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for feeds read change.");
return false;
bool FeedsModel::markItemRead(RootItem *item, RootItem::ReadStatus read) {
if (item->canBeMarkedAsReadUnread(read)) {
return item->markAsReadUnread(read);
}
QSqlQuery query_read_msg(db_handle);
query_read_msg.setForwardOnly(true);
if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read "
"WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(feeds).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds read change.");
db_handle.rollback();
return false;
}
query_read_msg.bindValue(QSL(":read"), read);
if (!query_read_msg.exec()) {
qDebug("Query execution for feeds read change failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
return true;
}
else {
return db_handle.rollback();
}
return false;
}
bool FeedsModel::markFeedsDeleted(const QList<Feed*> &feeds, int deleted, bool read_only) {
QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for feeds clearing.");
return false;
}
QSqlQuery query_delete_msg(db_handle);
query_delete_msg.setForwardOnly(true);
if (read_only) {
if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted "
"WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(feeds).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds clearing.");
db_handle.rollback();
return false;
}
}
else {
if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted "
"WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(feeds).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds clearing.");
db_handle.rollback();
return false;
}
}
query_delete_msg.bindValue(QSL(":deleted"), deleted);
if (!query_delete_msg.exec()) {
qDebug("Query execution for feeds clearing failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
return true;
}
else {
return db_handle.rollback();
}
bool FeedsModel::markItemCleared(RootItem *item, bool clean_read_only) {
return item->cleanMessages(clean_read_only);
}
QList<Feed*> FeedsModel::allFeeds() {

View File

@ -132,8 +132,8 @@ class FeedsModel : public QAbstractItemModel {
public slots:
// Feeds operations.
bool markFeedsRead(const QList<Feed*> &feeds, int read);
bool markFeedsDeleted(const QList<Feed*> &feeds, int deleted, bool read_only);
bool markItemRead(RootItem *item, RootItem::ReadStatus read);
bool markItemCleared(RootItem *item, bool clean_read_only);
// Signals that properties (probably counts)
// of ALL items have changed.
@ -147,6 +147,12 @@ class FeedsModel : public QAbstractItemModel {
// Invalidates data under index for the item.
void reloadChangedItem(RootItem *item);
// Notifies other components about messages
// counts.
inline void notifyWithCounts() {
emit messageCountsChanged(countOfUnreadMessages(), countOfAllMessages(), hasAnyFeedNewMessages());
}
private slots:
// Is executed when next auto-update round could be done.
void executeNextAutoUpdate();
@ -155,6 +161,9 @@ class FeedsModel : public QAbstractItemModel {
// Emitted when model requests update of some feeds.
void feedsUpdateRequested(const QList<Feed*> feeds);
// Emitted if counts of messages are changed.
void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages);
private:
// Returns converted ids of given feeds
// which are suitable as IN clause for SQL queries.

View File

@ -46,6 +46,48 @@ QList<QAction*> RootItem::contextMenuActions() {
return QList<QAction*>();
}
bool RootItem::canBeEdited() {
return false;
}
bool RootItem::editViaGui() {
return false;
}
bool RootItem::canBeDeleted() {
return false;
}
bool RootItem::deleteViaGui() {
return false;
}
bool RootItem::canBeMarkedAsReadUnread(ReadStatus status) {
return true;
}
bool RootItem::markAsReadUnread(ReadStatus status) {
bool result = true;
foreach (RootItem *child, m_childItems) {
if (child->canBeMarkedAsReadUnread(status)) {
result &= child->markAsReadUnread(status);
}
}
return result;
}
bool RootItem::cleanMessages(bool clear_only_read) {
bool result = true;
foreach (RootItem *child, m_childItems) {
result &= child->cleanMessages(clear_only_read);
}
return result;
}
void RootItem::setupFonts() {
m_normalFont = Application::font("FeedsView");
m_boldFont = m_normalFont;

View File

@ -50,6 +50,16 @@ class RootItem : public QObject {
Q_OBJECT
public:
enum ReadStatus {
Read,
Unread
};
enum CleanStatus {
Clean,
Unclean
};
// Constructors and destructors.
explicit RootItem(RootItem *parent_item = NULL);
virtual ~RootItem();
@ -82,39 +92,20 @@ class RootItem : public QObject {
// NOTE: Ownership of returned actions is not switched to caller, free them when needed.
virtual QList<QAction*> contextMenuActions();
// TODO: pracovat s těmito věcmi
virtual bool canBeEdited() {
return false;
}
virtual bool canBeEdited();
virtual bool editViaGui();
virtual bool canBeDeleted();
virtual bool deleteViaGui();
virtual bool editViaGui() {
return false;
}
virtual bool canBeDeleted() {
return false;
}
virtual bool deleteViaGui() {
return false;
}
virtual bool canBeMarkedAsRead() {
return true;
}
virtual bool markAsRead() {
return true;
}
virtual bool canBeMarkedAsUnread() {
return true;
}
virtual bool markAsUnread() {
return true;
}
virtual bool canBeMarkedAsReadUnread(ReadStatus status);
virtual bool markAsReadUnread(ReadStatus status);
// This method should "clean" all messages it contains.
// What "clean" means? It means delete message -> move them to recycle bin
// or eventually remove them completely if there is no recycle bin functionality.
// If this method is called on "recycle bin" instance of your
// service account, it should not do anything.
virtual bool cleanMessages(bool clear_only_read);
virtual int row() const;
virtual QVariant data(int column, int role) const;

View File

@ -75,7 +75,7 @@ FeedMessageViewer::FeedMessageViewer(QWidget *parent)
createConnections();
// Now, update all feeds if user has set it.
m_feedsView->updateAllFeedsOnStartup();
m_feedsView->updateAllItemsOnStartup();
}
FeedMessageViewer::~FeedMessageViewer() {
@ -337,7 +337,7 @@ void FeedMessageViewer::createConnections() {
connect(m_feedsView, SIGNAL(feedsNeedToBeReloaded(bool)), m_messagesView, SLOT(reloadSelections(bool)));
// If counts of unread/all messages change, update the tray icon.
connect(m_feedsView, SIGNAL(messageCountsChanged(int,int,bool)), this, SLOT(updateTrayIconStatus(int,int,bool)));
connect(m_feedsView->sourceModel(), SIGNAL(messageCountsChanged(int,int,bool)), this, SLOT(updateTrayIconStatus(int,int,bool)));
// Message openers.
connect(m_messagesView, SIGNAL(openLinkMiniBrowser(QString)), m_messagesBrowser, SLOT(navigateToUrl(QString)));
@ -371,25 +371,25 @@ void FeedMessageViewer::createConnections() {
connect(form_main->m_ui->m_actionSendMessageViaEmail,
SIGNAL(triggered()), m_messagesView, SLOT(sendSelectedMessageViaEmail()));
connect(form_main->m_ui->m_actionMarkAllItemsRead,
SIGNAL(triggered()), m_feedsView, SLOT(markAllFeedsRead()));
SIGNAL(triggered()), m_feedsView, SLOT(markAllItemsRead()));
connect(form_main->m_ui->m_actionMarkSelectedItemsAsRead,
SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsRead()));
SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsRead()));
connect(form_main->m_ui->m_actionExpandCollapseItem,
SIGNAL(triggered()), m_feedsView, SLOT(expandCollapseCurrentItem()));
connect(form_main->m_ui->m_actionMarkSelectedItemsAsUnread,
SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsUnread()));
SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsUnread()));
connect(form_main->m_ui->m_actionClearSelectedItems,
SIGNAL(triggered()), m_feedsView, SLOT(clearSelectedFeeds()));
connect(form_main->m_ui->m_actionClearAllItems,
SIGNAL(triggered()), m_feedsView, SLOT(clearAllFeeds()));
connect(form_main->m_ui->m_actionUpdateSelectedItems,
SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedFeeds()));
SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedItems()));
connect(form_main->m_ui->m_actionUpdateAllItems,
SIGNAL(triggered()), m_feedsView, SLOT(updateAllFeeds()));
SIGNAL(triggered()), m_feedsView, SLOT(updateAllItems()));
connect(form_main->m_ui->m_actionEditSelectedItem,
SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem()));
connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode,
SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode()));
SIGNAL(triggered()), m_feedsView, SLOT(openSelectedItemsInNewspaperMode()));
connect(form_main->m_ui->m_actionDeleteSelectedItem,
SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem()));
connect(form_main->m_ui->m_actionSwitchFeedsList,

View File

@ -159,43 +159,35 @@ void FeedsView::expandCollapseCurrentItem() {
}
}
void FeedsView::updateAllFeeds() {
void FeedsView::updateAllItems() {
emit feedsUpdateRequested(allFeeds());
}
void FeedsView::updateSelectedFeeds() {
void FeedsView::updateSelectedItems() {
emit feedsUpdateRequested(selectedFeeds());
}
void FeedsView::updateAllFeedsOnStartup() {
void FeedsView::updateAllItemsOnStartup() {
if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) {
qDebug("Requesting update for all feeds on application startup.");
QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllFeeds()));
QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllItems()));
}
}
void FeedsView::setSelectedFeedsClearStatus(int clear) {
m_sourceModel->markFeedsDeleted(selectedFeeds(), clear, 0);
void FeedsView::clearSelectedFeeds() {
m_sourceModel->markItemCleared(selectedItem(), false);
updateCountsOfSelectedFeeds(true);
emit feedsNeedToBeReloaded(true);
}
void FeedsView::setAllFeedsClearStatus(int clear) {
m_sourceModel->markFeedsDeleted(allFeeds(), clear, 0);
void FeedsView::clearAllFeeds() {
m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false);
updateCountsOfAllFeeds(true);
emit feedsNeedToBeReloaded(true);
}
void FeedsView::clearSelectedFeeds() {
setSelectedFeedsClearStatus(1);
}
void FeedsView::clearAllFeeds() {
setAllFeedsClearStatus(1);
}
void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode,
bool total_msg_count_changed,
bool any_msg_restored) {
@ -313,7 +305,7 @@ void FeedsView::deleteSelectedItem() {
// a delete selected_item jen volat tady, editViaGui taky obstará všechno,
// ale tam je to zas komplexnější.
m_sourceModel->removeItem(m_proxyModel->mapToSource(current_index));
notifyWithCounts();
m_sourceModel->notifyWithCounts();
}
}
else {
@ -329,42 +321,42 @@ void FeedsView::deleteSelectedItem() {
qApp->feedUpdateLock()->unlock();
}
void FeedsView::markSelectedFeedsReadStatus(int read) {
m_sourceModel->markFeedsRead(selectedFeeds(), read);
void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) {
m_sourceModel->markItemRead(selectedItem(), read);
updateCountsOfSelectedFeeds(false);
emit feedsNeedToBeReloaded(read == 1);
}
void FeedsView::markSelectedFeedsRead() {
markSelectedFeedsReadStatus(1);
void FeedsView::markSelectedItemsRead() {
markSelectedItemReadStatus(RootItem::Read);
}
void FeedsView::markSelectedFeedsUnread() {
markSelectedFeedsReadStatus(0);
void FeedsView::markSelectedItemsUnread() {
markSelectedItemReadStatus(RootItem::Unread);
}
void FeedsView::markAllFeedsReadStatus(int read) {
m_sourceModel->markFeedsRead(allFeeds(), read);
void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) {
m_sourceModel->markItemRead(m_sourceModel->rootItem(), read);
updateCountsOfAllFeeds(false);
emit feedsNeedToBeReloaded(read == 1);
}
void FeedsView::markAllFeedsRead() {
markAllFeedsReadStatus(1);
void FeedsView::markAllItemsRead() {
markAllItemsReadStatus(RootItem::Read);
}
void FeedsView::clearAllReadMessages() {
m_sourceModel->markFeedsDeleted(allFeeds(), 1, 1);
m_sourceModel->markItemCleared(m_sourceModel->rootItem(), true);
}
void FeedsView::openSelectedFeedsInNewspaperMode() {
void FeedsView::openSelectedItemsInNewspaperMode() {
QList<Message> messages = m_sourceModel->messagesForFeeds(selectedFeeds());
if (!messages.isEmpty()) {
emit openMessagesInNewspaperView(messages);
QTimer::singleShot(0, this, SLOT(markSelectedFeedsRead()));
QTimer::singleShot(0, this, SLOT(markSelectedItemsRead()));
}
}
@ -410,7 +402,7 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) {
// Make sure that selected view reloads changed indexes.
m_sourceModel->reloadChangedLayout(selected_indexes);
notifyWithCounts();
m_sourceModel->notifyWithCounts();
}
void FeedsView::updateCountsOfRecycleBin(bool update_total_too) {
@ -418,7 +410,7 @@ void FeedsView::updateCountsOfRecycleBin(bool update_total_too) {
// TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->updateCounts(update_total_too);
//m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin()));
notifyWithCounts();
m_sourceModel->notifyWithCounts();
}
void FeedsView::updateCountsOfAllFeeds(bool update_total_too) {
@ -435,29 +427,22 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) {
// Make sure that all views reloads its data.
m_sourceModel->reloadWholeLayout();
notifyWithCounts();
m_sourceModel->notifyWithCounts();
}
void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) {
QModelIndex index = m_sourceModel->indexForItem(feed);
if (index.isValid()) {
feed->updateCounts(update_total_too, false);
feed->updateCounts(update_total_too);
m_sourceModel->reloadChangedLayout(QModelIndexList() << index);
}
invalidateReadFeedsFilter();
notifyWithCounts();
m_sourceModel->notifyWithCounts();
}
void FeedsView::selectNextItem() {
// NOTE: Bug #122 requested to not expand in here.
/*
if (!isExpanded(currentIndex())) {
expand(currentIndex());
}
*/
QModelIndex index_next = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
if (index_next.isValid()) {
@ -469,14 +454,6 @@ void FeedsView::selectNextItem() {
void FeedsView::selectPreviousItem() {
QModelIndex index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier);
// NOTE: Bug #122 requested to not expand in here.
/*
if (!isExpanded(index_previous)) {
expand(index_previous);
index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier);
}
*/
if (index_previous.isValid()) {
setCurrentIndex(index_previous);
setFocus();

View File

@ -71,27 +71,23 @@ class FeedsView : public QTreeView {
void expandCollapseCurrentItem();
// Feed updating.
void updateAllFeeds();
void updateAllFeedsOnStartup();
void updateSelectedFeeds();
void updateAllItems();
void updateAllItemsOnStartup();
void updateSelectedItems();
// Feed read/unread manipulators.
void markSelectedFeedsReadStatus(int read);
void markSelectedFeedsRead();
void markSelectedFeedsUnread();
void markAllFeedsReadStatus(int read);
void markAllFeedsRead();
void markSelectedItemsRead();
void markSelectedItemsUnread();
void markAllItemsRead();
// Newspaper accessors.
void openSelectedFeedsInNewspaperMode();
void openSelectedItemsInNewspaperMode();
// Recycle bin operators.
void emptyRecycleBin();
void restoreRecycleBin();
// Feed clearers.
void setSelectedFeedsClearStatus(int clear);
void setAllFeedsClearStatus(int clear);
void clearSelectedFeeds();
void clearAllFeeds();
void clearAllReadMessages();
@ -116,14 +112,6 @@ class FeedsView : public QTreeView {
// Reloads counts for particular feed.
void updateCountsOfParticularFeed(Feed *feed, bool update_total_too);
// Notifies other components about messages
// counts.
inline void notifyWithCounts() {
emit messageCountsChanged(m_sourceModel->countOfUnreadMessages(),
m_sourceModel->countOfAllMessages(),
m_sourceModel->hasAnyFeedNewMessages());
}
// Selects next/previous item (feed/category) in the list.
void selectNextItem();
void selectPreviousItem();
@ -133,7 +121,14 @@ class FeedsView : public QTreeView {
setVisible(!isVisible());
}
protected:
private slots:
void markSelectedItemReadStatus(RootItem::ReadStatus read);
void markAllItemsReadStatus(RootItem::ReadStatus read);
void saveSortState(int column, Qt::SortOrder order);
void validateItemAfterDragDrop(const QModelIndex &source_index);
private:
// Initializes context menus.
void initializeContextMenuCategories(RootItem *clicked_item);
void initializeContextMenuFeeds(RootItem *clicked_item);
@ -151,17 +146,10 @@ class FeedsView : public QTreeView {
// Show custom context menu.
void contextMenuEvent(QContextMenuEvent *event);
private slots:
void saveSortState(int column, Qt::SortOrder order);
void validateItemAfterDragDrop(const QModelIndex &source_index);
signals:
// Emitted if user/application requested updating of some feeds.
void feedsUpdateRequested(const QList<Feed*> feeds);
// Emitted if counts of messages are changed.
void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages);
// Emitted if currently selected feeds needs to be reloaded.
void feedsNeedToBeReloaded(bool mark_current_index_read);

View File

@ -60,7 +60,7 @@ class Feed : public RootItem {
virtual int update() = 0;
// Updates counts of all/unread messages for this feed.
virtual void updateCounts(bool including_total_count = true, bool update_feed_statuses = true) = 0;
virtual void updateCounts(bool including_total_count) = 0;
// Get ALL undeleted messages from this feed in one single list.
virtual QList<Message> undeletedMessages() const = 0;

View File

@ -102,6 +102,14 @@ bool StandardCategory::deleteViaGui() {
return removeItself();
}
bool StandardCategory::markAsReadUnread(ReadStatus status) {
return serviceRoot()->markFeedsReadUnread(getSubTreeFeeds(), status);
}
bool StandardCategory::cleanMessages(bool clean_read_only) {
return serviceRoot()->cleanFeeds(getSubTreeFeeds(), clean_read_only);
}
bool StandardCategory::removeItself() {
bool children_removed = true;

View File

@ -56,6 +56,9 @@ class StandardCategory : public Category {
bool editViaGui();
bool deleteViaGui();
bool markAsReadUnread(ReadStatus status);
bool cleanMessages(bool clean_read_only);
// Removes category and all its children from persistent
// database.
bool removeItself();

View File

@ -118,6 +118,14 @@ bool StandardFeed::deleteViaGui() {
return removeItself();
}
bool StandardFeed::markAsReadUnread(ReadStatus status) {
return serviceRoot()->markFeedsReadUnread(QList<Feed*>() << this, status);
}
bool StandardFeed::cleanMessages(bool clean_read_only) {
return serviceRoot()->cleanFeeds(QList<Feed*>() << this, clean_read_only);
}
QList<Message> StandardFeed::undeletedMessages() const {
QList<Message> messages;
@ -165,7 +173,7 @@ QString StandardFeed::typeToString(StandardFeed::Type type) {
}
}
void StandardFeed::updateCounts(bool including_total_count, bool update_feed_statuses) {
void StandardFeed::updateCounts(bool including_total_count) {
QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings);
QSqlQuery query_all(database);
@ -181,7 +189,7 @@ void StandardFeed::updateCounts(bool including_total_count, bool update_feed_sta
if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0;").arg(id())) && query_all.next()) {
int new_unread_count = query_all.value(0).toInt();
if (update_feed_statuses && status() == NewMessages && new_unread_count < m_unreadCount) {
if (status() == NewMessages && new_unread_count < m_unreadCount) {
setStatus(Normal);
}
@ -433,7 +441,7 @@ int StandardFeed::update() {
setStatus(NetworkError);
return 0;
}
else {
else if (status() != NewMessages) {
setStatus(Normal);
}
@ -731,5 +739,5 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) {
setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString()));
setAutoUpdateType(static_cast<StandardFeed::AutoUpdateType>(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt()));
setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt());
updateCounts();
updateCounts(true);
}

View File

@ -74,6 +74,9 @@ class StandardFeed : public Feed {
bool editViaGui();
bool deleteViaGui();
bool markAsReadUnread(ReadStatus status);
bool cleanMessages(bool clean_read_only);
QList<Message> undeletedMessages() const;
// Obtains data related to this feed.
@ -83,7 +86,7 @@ class StandardFeed : public Feed {
int update();
// Updates counts of all/unread messages for this feed.
void updateCounts(bool including_total_count = true, bool update_feed_statuses = true);
void updateCounts(bool including_total_count);
// Removes this standard feed from persistent
// storage.
@ -156,7 +159,7 @@ class StandardFeed : public Feed {
// Fetches metadata for the feed.
void fetchMetadataForItself();
protected:
private:
// Persistently stores given messages into the database
// and updates existing messages if newer version is
// available.

View File

@ -128,6 +128,87 @@ QVariant StandardServiceRoot::data(int column, int role) const {
}
}
bool StandardServiceRoot::markFeedsReadUnread(QList<Feed*> items, ReadStatus read) {
QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for feeds read change.");
return false;
}
QSqlQuery query_read_msg(db_handle);
query_read_msg.setForwardOnly(true);
if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read "
"WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds read change.");
db_handle.rollback();
return false;
}
query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
if (!query_read_msg.exec()) {
qDebug("Query execution for feeds read change failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
return true;
}
else {
return db_handle.rollback();
}
}
bool StandardServiceRoot::cleanFeeds(QList<Feed*> items, bool clean_read_only) {
QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for feeds clearing.");
return false;
}
QSqlQuery query_delete_msg(db_handle);
query_delete_msg.setForwardOnly(true);
if (clean_read_only) {
if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted "
"WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds clearing.");
db_handle.rollback();
return false;
}
}
else {
if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted "
"WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) {
qWarning("Query preparation failed for feeds clearing.");
db_handle.rollback();
return false;
}
}
query_delete_msg.bindValue(QSL(":deleted"), 1);
if (!query_delete_msg.exec()) {
qDebug("Query execution for feeds clearing failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
return true;
}
else {
return db_handle.rollback();
}
}
void StandardServiceRoot::loadFromDatabase(){
QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings);
CategoryAssignment categories;
@ -362,6 +443,17 @@ void StandardServiceRoot::exportFeeds() {
delete form.data();
}
QStringList StandardServiceRoot::textualFeedIds(const QList<Feed*> &feeds) {
QStringList stringy_ids;
stringy_ids.reserve(feeds.size());
foreach (Feed *feed, feeds) {
stringy_ids.append(QString::number(feed->id()));
}
return stringy_ids;
}
QList<QAction*> StandardServiceRoot::addItemMenu() {
if (m_addItemMenu.isEmpty()) {
QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this);

View File

@ -74,6 +74,9 @@ class StandardServiceRoot : public ServiceRoot {
// NOTE: This is used for import/export of the model.
bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message);
bool markFeedsReadUnread(QList<Feed*> items, ReadStatus read);
bool cleanFeeds(QList<Feed*> items, bool clean_read_only);
public slots:
void addNewCategory();
void addNewFeed();
@ -81,6 +84,10 @@ class StandardServiceRoot : public ServiceRoot {
void exportFeeds();
private:
// Returns converted ids of given feeds
// which are suitable as IN clause for SQL queries.
QStringList textualFeedIds(const QList<Feed *> &feeds);
void loadFromDatabase();
// Takes lists of feeds/categories and assembles