VERY initial and f*cking buggy implementation of some messages-realted operations - right now, there is added ability to display messages according to selection.

This commit is contained in:
Martin Rotter 2015-11-19 13:21:38 +01:00
parent 1633150e67
commit ebea3e0029
13 changed files with 92 additions and 171 deletions

View file

@ -412,7 +412,6 @@ set(APP_SOURCES
src/core/rootitem.cpp src/core/rootitem.cpp
src/core/parsingfactory.cpp src/core/parsingfactory.cpp
src/core/feeddownloader.cpp src/core/feeddownloader.cpp
src/core/feedsselection.cpp
src/core/message.cpp src/core/message.cpp
# ABSTRACT service sources. # ABSTRACT service sources.

View file

@ -1,73 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2015 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "core/feedsselection.h"
#include "core/rootitem.h"
#include "services/standard/standardcategory.h"
#include "services/standard/standardfeed.h"
#include "definitions/definitions.h"
FeedsSelection::FeedsSelection(RootItem *root_of_selection) : m_selectedItem(root_of_selection) {
}
FeedsSelection::FeedsSelection(const FeedsSelection &other) {
m_selectedItem = other.selectedItem();
}
FeedsSelection::~FeedsSelection() {
}
FeedsSelection::SelectionMode FeedsSelection::mode() {
if (m_selectedItem == NULL) {
return FeedsSelection::NoMode;
}
switch (m_selectedItem->kind()) {
case RootItemKind::Bin:
return FeedsSelection::MessagesFromRecycleBin;
case RootItemKind::Category:
case RootItemKind::Feed:
return FeedsSelection::MessagesFromFeeds;
default:
return FeedsSelection::NoMode;
}
}
RootItem *FeedsSelection::selectedItem() const {
return m_selectedItem;
}
QString FeedsSelection::generateListOfIds() {
if (m_selectedItem != NULL &&
(m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) {
QList<Feed*> children = m_selectedItem->getSubTreeFeeds();
QStringList stringy_ids;
foreach (Feed *child, children) {
stringy_ids.append(QString::number(child->id()));
}
return stringy_ids.join(QSL(", "));
}
else {
return QString();
}
}

View file

@ -1,50 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2015 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef FEEDSSELECTION_H
#define FEEDSSELECTION_H
#include <QString>
#include <QMetaType>
class RootItem;
class StandardFeed;
class FeedsSelection {
public:
enum SelectionMode {
NoMode,
MessagesFromFeeds,
MessagesFromRecycleBin
};
explicit FeedsSelection(RootItem *root_of_selection = NULL);
FeedsSelection(const FeedsSelection &other);
virtual ~FeedsSelection();
SelectionMode mode();
RootItem *selectedItem() const;
QString generateListOfIds();
private:
RootItem *m_selectedItem;
};
Q_DECLARE_METATYPE(FeedsSelection::SelectionMode)
#endif // FEEDSSELECTION_H

View file

@ -22,6 +22,8 @@
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "gui/dialogs/formmain.h"
#include "services/abstract/serviceroot.h"
#include <QSqlRecord> #include <QSqlRecord>
#include <QSqlError> #include <QSqlError>
@ -42,7 +44,7 @@ MessagesModel::MessagesModel(QObject *parent)
// via model, but via DIRECT SQL calls are used to do persistent messages. // via model, but via DIRECT SQL calls are used to do persistent messages.
setEditStrategy(QSqlTableModel::OnManualSubmit); setEditStrategy(QSqlTableModel::OnManualSubmit);
setTable(QSL("Messages")); setTable(QSL("Messages"));
loadMessages(FeedsSelection()); loadMessages(NULL);
} }
MessagesModel::~MessagesModel() { MessagesModel::~MessagesModel() {
@ -69,17 +71,21 @@ void MessagesModel::setupFonts() {
m_boldFont.setBold(true); m_boldFont.setBold(true);
} }
void MessagesModel::loadMessages(const FeedsSelection &selection) { void MessagesModel::loadMessages(RootItem *item) {
m_currentSelection = selection; m_selectedItem = item;
if (m_currentSelection.mode() == FeedsSelection::MessagesFromRecycleBin) { if (item == NULL) {
setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0")); setFilter("true != true");
} }
else { else {
QString assembled_ids = m_currentSelection.generateListOfIds(); if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) {
qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title()));
setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0")).arg(assembled_ids)); qApp->showGuiMessage(tr("Loading of messages from item '%s' failed.").arg(item->title()),
qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids)); tr("Loading of messages failed, maybe messages could not be downloaded."),
QSystemTrayIcon::Critical,
qApp->mainForm(),
true);
}
} }
fetchAllData(); fetchAllData();
@ -276,7 +282,10 @@ bool MessagesModel::setMessageRead(int row_index, int read) {
// If commit succeeded, then emit changes, so that view // If commit succeeded, then emit changes, so that view
// can reflect. // can reflect.
emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1));
emit messageCountsChanged(m_currentSelection.mode(), false, false); emit messageCountsChanged();
// TODO: counts changed
//emit messageCountsChanged(m_selectedItem.mode(), false, false);
return true; return true;
} }
else { else {
@ -374,7 +383,9 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int
QString sql_delete_query; QString sql_delete_query;
if (m_currentSelection.mode() == FeedsSelection::MessagesFromFeeds) { // TODO: todo
/*
if (m_selectedItem.mode() == FeedsSelection::MessagesFromFeeds) {
sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")),
QString::number(deleted)); QString::number(deleted));
} }
@ -382,11 +393,14 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int
sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")),
QString::number(deleted)); QString::number(deleted));
} }
*/
if (query_read_msg.exec(sql_delete_query)) { if (query_read_msg.exec(sql_delete_query)) {
fetchAllData(); fetchAllData();
emit messageCountsChanged();
emit messageCountsChanged(m_currentSelection.mode(), true, false); // TODO: counts changed
//emit messageCountsChanged(m_selectedItem.mode(), true, false);
return true; return true;
} }
else { else {
@ -411,7 +425,10 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt
read == RootItem::Read ? QSL("1") : QSL("0")))) { read == RootItem::Read ? QSL("1") : QSL("0")))) {
fetchAllData(); fetchAllData();
emit messageCountsChanged(m_currentSelection.mode(), false, false); emit messageCountsChanged();
// TODO: counts changed
//emit messageCountsChanged(m_selectedItem.mode(), false, false);
return true; return true;
} }
else { else {
@ -420,11 +437,6 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt
} }
bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
if (m_currentSelection.mode() == FeedsSelection::MessagesFromFeeds) {
qDebug("Cannot restore non-deleted messages.");
return false;
}
QSqlDatabase db_handle = database(); QSqlDatabase db_handle = database();
QSqlQuery query_read_msg(db_handle); QSqlQuery query_read_msg(db_handle);
QStringList message_ids; QStringList message_ids;
@ -441,7 +453,10 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
if (query_read_msg.exec(sql_delete_query)) { if (query_read_msg.exec(sql_delete_query)) {
fetchAllData(); fetchAllData();
emit messageCountsChanged(m_currentSelection.mode(), true, true); emit messageCountsChanged();
// TODO: counts changed
//emit messageCountsChanged(m_selectedItem.mode(), true, true);
return true; return true;
} }
else { else {

View file

@ -20,7 +20,6 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "core/feedsselection.h"
#include "core/message.h" #include "core/message.h"
#include "core/rootitem.h" #include "core/rootitem.h"
@ -81,13 +80,12 @@ class MessagesModel : public QSqlTableModel {
// Filters messages // Filters messages
void highlightMessages(MessageHighlighter highlight); void highlightMessages(MessageHighlighter highlight);
public slots:
// Loads messages of given feeds. // Loads messages of given feeds.
void loadMessages(const FeedsSelection &selection); void loadMessages(RootItem *item);
signals: signals:
// Emitted if some persistent change is made which affects count of "unread/all" messages. // Emitted if some persistent change is made which affects count of "unread/all" messages.
void messageCountsChanged(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); void messageCountsChanged();
private slots: private slots:
// To disable persistent changes submissions. // To disable persistent changes submissions.
@ -106,7 +104,7 @@ class MessagesModel : public QSqlTableModel {
MessageHighlighter m_messageHighlighter; MessageHighlighter m_messageHighlighter;
QString m_customDateFormat; QString m_customDateFormat;
FeedsSelection m_currentSelection; RootItem *m_selectedItem;
QList<QString> m_headerData; QList<QString> m_headerData;
QList<QString> m_tooltipData; QList<QString> m_tooltipData;

View file

@ -25,7 +25,6 @@
#include "miscellaneous/databasecleaner.h" #include "miscellaneous/databasecleaner.h"
#include "core/messagesproxymodel.h" #include "core/messagesproxymodel.h"
#include "core/feeddownloader.h" #include "core/feeddownloader.h"
#include "core/feedsselection.h"
#include "services/standard/standardserviceroot.h" #include "services/standard/standardserviceroot.h"
#include "services/standard/standardfeed.h" #include "services/standard/standardfeed.h"
#include "services/standard/standardfeedsimportexportmodel.h" #include "services/standard/standardfeedsimportexportmodel.h"
@ -321,16 +320,16 @@ void FeedMessageViewer::createConnections() {
connect(m_messagesView, SIGNAL(currentMessagesRemoved()), this, SLOT(updateMessageButtonsAvailability())); connect(m_messagesView, SIGNAL(currentMessagesRemoved()), this, SLOT(updateMessageButtonsAvailability()));
connect(m_messagesView, SIGNAL(currentMessagesChanged(QList<Message>)), this, SLOT(updateMessageButtonsAvailability())); connect(m_messagesView, SIGNAL(currentMessagesChanged(QList<Message>)), this, SLOT(updateMessageButtonsAvailability()));
connect(m_feedsView, SIGNAL(feedsSelected(FeedsSelection)), this, SLOT(updateFeedButtonsAvailability())); connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), this, SLOT(updateFeedButtonsAvailability()));
connect(qApp->feedUpdateLock(), SIGNAL(locked()), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(locked()), this, SLOT(updateFeedButtonsAvailability()));
connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability()));
// If user selects feeds, load their messages. // If user selects feeds, load their messages.
connect(m_feedsView, SIGNAL(feedsSelected(FeedsSelection)), m_messagesView, SLOT(loadFeeds(FeedsSelection))); connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*)));
// If user changes status of some messages, recalculate message counts. // If user changes status of some messages, recalculate message counts.
connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged(FeedsSelection::SelectionMode,bool,bool)), connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged()),
m_feedsView, SLOT(receiveMessageCountsChange(FeedsSelection::SelectionMode,bool,bool))); m_feedsView, SLOT(receiveMessageCountsChange()));
// State of many messages is changed, then we need // State of many messages is changed, then we need
// to reload selections. // to reload selections.

View file

@ -189,9 +189,12 @@ void FeedsView::clearAllFeeds() {
emit feedsNeedToBeReloaded(true); emit feedsNeedToBeReloaded(true);
} }
void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, void FeedsView::receiveMessageCountsChange() {
bool total_msg_count_changed,
bool any_msg_restored) { // TODO: toto vymazat, prepocitani cisel unread/all
// a upozorneni na zmenu itemu provede ten item
// zde jen nechat tu invalidaci read filteru
// If the change came from recycle bin mode, then: // If the change came from recycle bin mode, then:
// a) total count of message was changed AND no message was restored - some messages // a) total count of message was changed AND no message was restored - some messages
// were permanently deleted from recycle bin --> we need to update counts of // were permanently deleted from recycle bin --> we need to update counts of
@ -207,7 +210,7 @@ void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode,
// total counts. // total counts.
// b) total count of message was not changed - some messages switched state --> we need to update // b) total count of message was not changed - some messages switched state --> we need to update
// counts of just selected feeds. // counts of just selected feeds.
if (mode == FeedsSelection::MessagesFromRecycleBin) { /*if (mode == FeedsSelection::MessagesFromRecycleBin) {
if (total_msg_count_changed) { if (total_msg_count_changed) {
if (any_msg_restored) { if (any_msg_restored) {
updateCountsOfAllFeeds(true); updateCountsOfAllFeeds(true);
@ -222,7 +225,7 @@ void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode,
} }
else { else {
updateCountsOfSelectedFeeds(total_msg_count_changed); updateCountsOfSelectedFeeds(total_msg_count_changed);
} }*/
invalidateReadFeedsFilter(); invalidateReadFeedsFilter();
} }
@ -582,7 +585,7 @@ void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSele
m_proxyModel->setSelectedItem(selected_item); m_proxyModel->setSelectedItem(selected_item);
QTreeView::selectionChanged(selected, deselected); QTreeView::selectionChanged(selected, deselected);
emit feedsSelected(FeedsSelection(selected_item)); emit itemSelected(selected_item);
invalidateReadFeedsFilter(); invalidateReadFeedsFilter();
} }
@ -610,8 +613,6 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) {
initializeContextMenuFeeds(clicked_item)->exec(event->globalPos()); initializeContextMenuFeeds(clicked_item)->exec(event->globalPos());
} }
else { else {
// TODO: volaz specificke menu polozky? zobrazovat menu pro dalsi typy
// polozek jako odpadkovy kos atp.
initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos()); initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos());
} }
} }

View file

@ -18,13 +18,11 @@
#ifndef FEEDSVIEW_H #ifndef FEEDSVIEW_H
#define FEEDSVIEW_H #define FEEDSVIEW_H
#include <QStyledItemDelegate>
#include <QTreeView> #include <QTreeView>
#include "core/messagesmodel.h"
#include "core/feedsmodel.h" #include "core/feedsmodel.h"
#include "core/feedsselection.h"
#include "miscellaneous/settings.h" #include <QStyledItemDelegate>
class FeedsProxyModel; class FeedsProxyModel;
@ -98,7 +96,7 @@ class FeedsView : public QTreeView {
// Is called when counts of messages are changed externally, // Is called when counts of messages are changed externally,
// typically from message view. // typically from message view.
void receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); void receiveMessageCountsChange();
// Reloads counts for selected feeds. // Reloads counts for selected feeds.
void updateCountsOfSelectedFeeds(bool update_total_too); void updateCountsOfSelectedFeeds(bool update_total_too);
@ -155,7 +153,7 @@ class FeedsView : public QTreeView {
void feedsNeedToBeReloaded(bool mark_current_index_read); void feedsNeedToBeReloaded(bool mark_current_index_read);
// Emitted if user selects new feeds. // Emitted if user selects new feeds.
void feedsSelected(const FeedsSelection &selection); void itemSelected(RootItem *item);
// Requests opening of given messages in newspaper mode. // Requests opening of given messages in newspaper mode.
void openMessagesInNewspaperView(const QList<Message> &messages); void openMessagesInNewspaperView(const QList<Message> &messages);

View file

@ -225,8 +225,8 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS
QTreeView::selectionChanged(selected, deselected); QTreeView::selectionChanged(selected, deselected);
} }
void MessagesView::loadFeeds(const FeedsSelection &selection) { void MessagesView::loadFeeds(RootItem *item) {
m_sourceModel->loadMessages(selection); m_sourceModel->loadMessages(item);
int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt(); int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt();
Qt::SortOrder ord = static_cast<Qt::SortOrder>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderMessages)).toInt()); Qt::SortOrder ord = static_cast<Qt::SortOrder>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderMessages)).toInt());

View file

@ -20,7 +20,6 @@
#include "core/messagesmodel.h" #include "core/messagesmodel.h"
#include "core/feedsselection.h"
#include "core/rootitem.h" #include "core/rootitem.h"
#include <QTreeView> #include <QTreeView>
@ -58,7 +57,7 @@ class MessagesView : public QTreeView {
void reloadSelections(bool mark_current_index_read); void reloadSelections(bool mark_current_index_read);
// Loads un-deleted messages from selected feeds. // Loads un-deleted messages from selected feeds.
void loadFeeds(const FeedsSelection &selection); void loadFeeds(RootItem *item);
// Message manipulators. // Message manipulators.
void openSelectedSourceMessagesExternally(); void openSelectedSourceMessagesExternally();

View file

@ -23,6 +23,7 @@
class FeedsModel; class FeedsModel;
class QAction; class QAction;
class QSqlTableModel;
// THIS IS the root node of the service. // THIS IS the root node of the service.
// NOTE: The root usually contains some core functionality of the // NOTE: The root usually contains some core functionality of the
@ -55,6 +56,15 @@ class ServiceRoot : public RootItem {
virtual void start() = 0; virtual void start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
// This method should prepare messages for given "item" (download them maybe?)
// into predefined "Messages" table
// and then use method QSqlTableModel::setFilter(....).
// NOTE: It would be more preferable if all messages are downloaded
// right when feeds are updated.
// TODO: toto možná udělat asynchronně, zobrazit
// "loading" dialog přes view a toto zavolat, nasledně signalovat
virtual bool loadMessagesForItem(RootItem *item, QSqlTableModel *model) = 0;
// Access to feed model. // Access to feed model.
FeedsModel *feedsModel() const; FeedsModel *feedsModel() const;

View file

@ -40,6 +40,7 @@
#include <QStack> #include <QStack>
#include <QAction> #include <QAction>
#include <QPointer> #include <QPointer>
#include <QSqlTableModel>
StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent)
@ -518,6 +519,27 @@ QList<QAction*> StandardServiceRoot::serviceMenu() {
return m_serviceMenu; return m_serviceMenu;
} }
bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) {
if (item->kind() == RootItemKind::Bin) {
model->setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0"));
}
else {
QList<Feed*> children = item->getSubTreeFeeds();
QStringList stringy_ids;
foreach (Feed *child, children) {
stringy_ids.append(QString::number(child->id()));
}
QString filter_clause = stringy_ids.join(QSL(", "));
model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0")).arg(filter_clause));
qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause));
}
return true;
}
void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { void StandardServiceRoot::assembleCategories(CategoryAssignment categories) {
QHash<int, RootItem*> assignments; QHash<int, RootItem*> assignments;
assignments.insert(NO_PARENT_CATEGORY, this); assignments.insert(NO_PARENT_CATEGORY, this);

View file

@ -57,6 +57,9 @@ class StandardServiceRoot : public ServiceRoot {
// Return menu to be shown in "Services -> service" menu. // Return menu to be shown in "Services -> service" menu.
QList<QAction*> serviceMenu(); QList<QAction*> serviceMenu();
// Message stuff.
bool loadMessagesForItem(RootItem *item, QSqlTableModel *model);
// Returns all standard categories which are lying under given root node. // Returns all standard categories which are lying under given root node.
// This does NOT include the root node even if the node is category. // This does NOT include the root node even if the node is category.
QHash<int,StandardCategory*> categoriesForItem(RootItem *root); QHash<int,StandardCategory*> categoriesForItem(RootItem *root);