Many refactorings in model/items, some tiny preparations for messages operation - they moved into feed classes.
This commit is contained in:
parent
d0b00915f3
commit
d5ff059543
@ -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);
|
||||
bool FeedsModel::markItemRead(RootItem *item, RootItem::ReadStatus read) {
|
||||
if (item->canBeMarkedAsReadUnread(read)) {
|
||||
return item->markAsReadUnread(read);
|
||||
}
|
||||
|
||||
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(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();
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user