Auto-update code moved to model class.

This commit is contained in:
Martin Rotter 2015-07-29 07:59:00 +02:00
parent c2e6172d21
commit 17a558e47a
6 changed files with 99 additions and 92 deletions

View File

@ -25,6 +25,7 @@
#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 "miscellaneous/mutex.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include <QSqlError> #include <QSqlError>
@ -33,12 +34,13 @@
#include <QPair> #include <QPair>
#include <QStack> #include <QStack>
#include <QMimeData> #include <QMimeData>
#include <QTimer>
#include <algorithm> #include <algorithm>
FeedsModel::FeedsModel(QObject *parent) FeedsModel::FeedsModel(QObject *parent)
: QAbstractItemModel(parent), m_recycleBin(new RecycleBin()) { : QAbstractItemModel(parent), m_recycleBin(new RecycleBin()), m_autoUpdateTimer(new QTimer(this)) {
setObjectName(QSL("FeedsModel")); setObjectName(QSL("FeedsModel"));
// Create root item. // Create root item.
@ -58,7 +60,12 @@ FeedsModel::FeedsModel(QObject *parent)
m_tooltipData << /*: Feed list header "titles" column tooltip.*/ tr("Titles of feeds/categories.") << m_tooltipData << /*: Feed list header "titles" column tooltip.*/ tr("Titles of feeds/categories.") <<
/*: Feed list header "counts" column tooltip.*/ tr("Counts of unread/all meesages."); /*: Feed list header "counts" column tooltip.*/ tr("Counts of unread/all meesages.");
connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate()));
loadFromDatabase(); loadFromDatabase();
// Setup the timer.
updateAutoUpdateStatus();
} }
FeedsModel::~FeedsModel() { FeedsModel::~FeedsModel() {
@ -68,6 +75,68 @@ FeedsModel::~FeedsModel() {
delete m_rootItem; delete m_rootItem;
} }
void FeedsModel::quit() {
if (m_autoUpdateTimer->isActive()) {
m_autoUpdateTimer->stop();
}
}
void FeedsModel::executeNextAutoUpdate() {
if (!qApp->feedUpdateLock()->tryLock()) {
qDebug("Delaying scheduled feed auto-updates for one minute due to another running update.");
// Cannot update, quit.
return;
}
// If global auto-update is enabled and its interval counter reached zero,
// then we need to restore it.
if (m_globalAutoUpdateEnabled && --m_globalAutoUpdateRemainingInterval < 0) {
// We should start next auto-update interval.
m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval;
}
qDebug("Starting auto-update event, pass %d/%d.", m_globalAutoUpdateRemainingInterval, m_globalAutoUpdateInitialInterval);
// Pass needed interval data and lets the model decide which feeds
// should be updated in this pass.
QList<Feed*> feeds_for_update = feedsForScheduledUpdate(m_globalAutoUpdateEnabled && m_globalAutoUpdateRemainingInterval == 0);
qApp->feedUpdateLock()->unlock();
if (!feeds_for_update.isEmpty()) {
// Request update for given feeds.
emit feedsUpdateRequested(feeds_for_update);
// NOTE: OSD/bubble informing about performing
// of scheduled update can be shown now.
qApp->showGuiMessage(tr("Starting auto-update of some feeds"),
tr("I will auto-update %n feed(s).", 0, feeds_for_update.size()),
QSystemTrayIcon::Information);
}
}
void FeedsModel::updateAutoUpdateStatus() {
// Restore global intervals.
// NOTE: Specific per-feed interval are left intact.
m_globalAutoUpdateInitialInterval = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt();
m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval;
m_globalAutoUpdateEnabled = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool();
// Start global auto-update timer if it is not running yet.
// NOTE: The timer must run even if global auto-update
// is not enabled because user can still enable auto-update
// for individual feeds.
if (!m_autoUpdateTimer->isActive()) {
m_autoUpdateTimer->setInterval(AUTO_UPDATE_INTERVAL);
m_autoUpdateTimer->start();
qDebug("Auto-update timer started with interval %d.", m_autoUpdateTimer->interval());
}
else {
qDebug("Auto-update timer is already running.");
}
}
QMimeData *FeedsModel::mimeData(const QModelIndexList &indexes) const { QMimeData *FeedsModel::mimeData(const QModelIndexList &indexes) const {
QMimeData *mime_data = new QMimeData(); QMimeData *mime_data = new QMimeData();
QByteArray encoded_data; QByteArray encoded_data;
@ -158,7 +227,7 @@ Qt::DropActions FeedsModel::supportedDropActions() const {
return Qt::MoveAction; return Qt::MoveAction;
} }
Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const { Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const {
Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); Qt::ItemFlags base_flags = QAbstractItemModel::flags(index);
RootItem *item_for_index = itemForIndex(index); RootItem *item_for_index = itemForIndex(index);
@ -249,7 +318,7 @@ int FeedsModel::rowCount(const QModelIndex &parent) const {
} }
} }
bool FeedsModel::removeItem(const QModelIndex &index) { bool FeedsModel::removeItem(const QModelIndex &index) {
if (index.isValid()) { if (index.isValid()) {
QModelIndex parent_index = index.parent(); QModelIndex parent_index = index.parent();
RootItem *deleting_item = itemForIndex(index); RootItem *deleting_item = itemForIndex(index);
@ -472,7 +541,7 @@ RecycleBin *FeedsModel::recycleBinForIndex(const QModelIndex &index) const {
} }
} }
QModelIndex FeedsModel::indexForItem(RootItem *item) const { QModelIndex FeedsModel::indexForItem(RootItem *item) const {
if (item == NULL || item->kind() == RootItem::Root) { if (item == NULL || item->kind() == RootItem::Root) {
// Root item lies on invalid index. // Root item lies on invalid index.
return QModelIndex(); return QModelIndex();

View File

@ -30,6 +30,7 @@ class Category;
class Feed; class Feed;
class RecycleBin; class RecycleBin;
class FeedsImportExportModel; class FeedsImportExportModel;
class QTimer;
typedef QList<QPair<int, Category*> > CategoryAssignment; typedef QList<QPair<int, Category*> > CategoryAssignment;
typedef QPair<int, Category*> CategoryAssignmentItem; typedef QPair<int, Category*> CategoryAssignmentItem;
@ -155,6 +156,13 @@ class FeedsModel : public QAbstractItemModel {
// Access to recycle bin. // Access to recycle bin.
RecycleBin *recycleBin() const; RecycleBin *recycleBin() const;
// Resets global auto-update intervals according to settings
// and starts/stop the timer as needed.
void updateAutoUpdateStatus();
// Does necessary job before quitting this component.
void quit();
public slots: public slots:
// Feeds operations. // Feeds operations.
bool markFeedsRead(const QList<Feed*> &feeds, int read); bool markFeedsRead(const QList<Feed*> &feeds, int read);
@ -169,6 +177,10 @@ class FeedsModel : public QAbstractItemModel {
// NOTE: This reloads all parent valid indexes too. // NOTE: This reloads all parent valid indexes too.
void reloadChangedLayout(QModelIndexList list); void reloadChangedLayout(QModelIndexList list);
private slots:
// Is executed when next auto-update round could be done.
void executeNextAutoUpdate();
protected: protected:
// Returns converted ids of given feeds // Returns converted ids of given feeds
// which are suitable as IN clause for SQL queries. // which are suitable as IN clause for SQL queries.
@ -185,12 +197,21 @@ class FeedsModel : public QAbstractItemModel {
signals: signals:
void requireItemValidationAfterDragDrop(const QModelIndex &source_index); void requireItemValidationAfterDragDrop(const QModelIndex &source_index);
// Emitted when model requests update of some feeds.
void feedsUpdateRequested(const QList<Feed*> feeds);
private: private:
RootItem *m_rootItem; RootItem *m_rootItem;
RecycleBin *m_recycleBin; RecycleBin *m_recycleBin;
QList<QString> m_headerData; QList<QString> m_headerData;
QList<QString> m_tooltipData; QList<QString> m_tooltipData;
QIcon m_countsIcon; QIcon m_countsIcon;
// Auto-update stuff.
QTimer *m_autoUpdateTimer;
bool m_globalAutoUpdateEnabled;
int m_globalAutoUpdateInitialInterval;
int m_globalAutoUpdateRemainingInterval;
}; };
#endif // FEEDSMODEL_H #endif // FEEDSMODEL_H

View File

@ -291,7 +291,7 @@ void FormSettings::saveFeedsMessages() {
settings->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_cmbMessageFontStandard->currentFont().family()); settings->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_cmbMessageFontStandard->currentFont().family());
qApp->mainForm()->tabWidget()->feedMessageViewer()->loadMessageViewerFonts(); qApp->mainForm()->tabWidget()->feedMessageViewer()->loadMessageViewerFonts();
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->updateAutoUpdateStatus(); qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->updateAutoUpdateStatus();
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->reloadWholeLayout(); qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->reloadWholeLayout();
qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->updateDateFormat(); qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->updateDateFormat();
qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->reloadWholeLayout(); qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->reloadWholeLayout();

View File

@ -150,8 +150,8 @@ void FeedMessageViewer::loadMessageViewerFonts() {
} }
void FeedMessageViewer::quit() { void FeedMessageViewer::quit() {
// Quit the feeds view (stops auto-update timer etc.). // Quit the feeds model (stops auto-update timer etc.).
m_feedsView->quit(); m_feedsView->sourceModel()->quit();
// Close worker threads. // Close worker threads.
if (m_feedDownloaderThread != NULL && m_feedDownloaderThread->isRunning()) { if (m_feedDownloaderThread != NULL && m_feedDownloaderThread->isRunning()) {

View File

@ -46,8 +46,7 @@ FeedsView::FeedsView(QWidget *parent)
: QTreeView(parent), : QTreeView(parent),
m_contextMenuCategoriesFeeds(NULL), m_contextMenuCategoriesFeeds(NULL),
m_contextMenuEmptySpace(NULL), m_contextMenuEmptySpace(NULL),
m_contextMenuRecycleBin(NULL), m_contextMenuRecycleBin(NULL) {
m_autoUpdateTimer(new QTimer(this)) {
setObjectName(QSL("FeedsView")); setObjectName(QSL("FeedsView"));
// Allocate models. // Allocate models.
@ -56,53 +55,23 @@ FeedsView::FeedsView(QWidget *parent)
// Connections. // Connections.
connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex)));
connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate())); connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList<Feed*>)), this, SIGNAL(feedsUpdateRequested(QList<Feed*>)));
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder)));
setModel(m_proxyModel); setModel(m_proxyModel);
setupAppearance(); setupAppearance();
// Setup the timer.
updateAutoUpdateStatus();
} }
FeedsView::~FeedsView() { FeedsView::~FeedsView() {
qDebug("Destroying FeedsView instance."); qDebug("Destroying FeedsView instance.");
} }
void FeedsView::quit() {
if (m_autoUpdateTimer->isActive()) {
m_autoUpdateTimer->stop();
}
}
void FeedsView::setSortingEnabled(bool enable) { void FeedsView::setSortingEnabled(bool enable) {
disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder)));
QTreeView::setSortingEnabled(enable); QTreeView::setSortingEnabled(enable);
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder)));
} }
void FeedsView::updateAutoUpdateStatus() {
// Restore global intervals.
// NOTE: Specific per-feed interval are left intact.
m_globalAutoUpdateInitialInterval = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt();
m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval;
m_globalAutoUpdateEnabled = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool();
// Start global auto-update timer if it is not running yet.
// NOTE: The timer must run even if global auto-update
// is not enabled because user can still enable auto-update
// for individual feeds.
if (!m_autoUpdateTimer->isActive()) {
m_autoUpdateTimer->setInterval(AUTO_UPDATE_INTERVAL);
m_autoUpdateTimer->start();
qDebug("Auto-update timer started with interval %d.", m_autoUpdateTimer->interval());
}
else {
qDebug("Auto-update timer is already running.");
}
}
QList<Feed*> FeedsView::selectedFeeds() const { QList<Feed*> FeedsView::selectedFeeds() const {
QModelIndex current_index = currentIndex(); QModelIndex current_index = currentIndex();
@ -188,42 +157,6 @@ void FeedsView::updateAllFeedsOnStartup() {
} }
} }
void FeedsView::executeNextAutoUpdate() {
if (!qApp->feedUpdateLock()->tryLock()) {
qDebug("Delaying scheduled feed auto-updates for one minute due to another running update.");
// Cannot update, quit.
return;
}
// If global auto-update is enabled and its interval counter reached zero,
// then we need to restore it.
if (m_globalAutoUpdateEnabled && --m_globalAutoUpdateRemainingInterval < 0) {
// We should start next auto-update interval.
m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval;
}
qDebug("Starting auto-update event, pass %d/%d.", m_globalAutoUpdateRemainingInterval, m_globalAutoUpdateInitialInterval);
// Pass needed interval data and lets the model decide which feeds
// should be updated in this pass.
QList<Feed*> feeds_for_update = m_sourceModel->feedsForScheduledUpdate(m_globalAutoUpdateEnabled &&
m_globalAutoUpdateRemainingInterval == 0);
qApp->feedUpdateLock()->unlock();
if (!feeds_for_update.isEmpty()) {
// Request update for given feeds.
emit feedsUpdateRequested(feeds_for_update);
// NOTE: OSD/bubble informing about performing
// of scheduled update can be shown now.
qApp->showGuiMessage(tr("Starting auto-update of some feeds"),
tr("I will auto-update %n feed(s).", 0, feeds_for_update.size()),
QSystemTrayIcon::Information);
}
}
void FeedsView::setSelectedFeedsClearStatus(int clear) { void FeedsView::setSelectedFeedsClearStatus(int clear) {
m_sourceModel->markFeedsDeleted(selectedFeeds(), clear, 0); m_sourceModel->markFeedsDeleted(selectedFeeds(), clear, 0);
updateCountsOfSelectedFeeds(true); updateCountsOfSelectedFeeds(true);

View File

@ -49,14 +49,7 @@ class FeedsView : public QTreeView {
return m_sourceModel; return m_sourceModel;
} }
// Does necessary job before quitting this component.
void quit();
void setSortingEnabled(bool enable); void setSortingEnabled(bool enable);
// Resets global auto-update intervals according to settings
// and starts/stop the timer as needed.
void updateAutoUpdateStatus();
// Returns list of selected/all feeds. // Returns list of selected/all feeds.
// NOTE: This is recursive method which returns all descendants. // NOTE: This is recursive method which returns all descendants.
@ -82,9 +75,6 @@ class FeedsView : public QTreeView {
void updateAllFeedsOnStartup(); void updateAllFeedsOnStartup();
void updateSelectedFeeds(); void updateSelectedFeeds();
// Is executed when next auto-update round could be done.
void executeNextAutoUpdate();
// Feed read/unread manipulators. // Feed read/unread manipulators.
void markSelectedFeedsReadStatus(int read); void markSelectedFeedsReadStatus(int read);
void markSelectedFeedsRead(); void markSelectedFeedsRead();
@ -196,12 +186,6 @@ class FeedsView : public QTreeView {
FeedsModel *m_sourceModel; FeedsModel *m_sourceModel;
FeedsProxyModel *m_proxyModel; FeedsProxyModel *m_proxyModel;
// Auto-update stuff.
QTimer *m_autoUpdateTimer;
bool m_globalAutoUpdateEnabled;
int m_globalAutoUpdateInitialInterval;
int m_globalAutoUpdateRemainingInterval;
}; };
#endif // FEEDSVIEW_H #endif // FEEDSVIEW_H