diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index bd3ca1d47..5041cf61d 100644 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -287,7 +287,7 @@ bool FeedsModel::addStandardFeed(FeedsModelStandardFeed *feed, query_add_feed.bindValue(":username", feed->username()); query_add_feed.bindValue(":password", feed->password()); query_add_feed.bindValue(":update_type", (int) feed->autoUpdateType()); - query_add_feed.bindValue(":update_interval", feed->autoUpdateInterval()); + query_add_feed.bindValue(":update_interval", feed->autoUpdateInitialInterval()); query_add_feed.bindValue(":type", (int) FeedsModelCategory::Standard); if (!query_add_feed.exec()) { @@ -338,7 +338,7 @@ bool FeedsModel::editStandardFeed(FeedsModelStandardFeed *original_feed, query_update_feed.bindValue(":username", new_feed->username()); query_update_feed.bindValue(":password", new_feed->password()); query_update_feed.bindValue(":update_type", (int) new_feed->autoUpdateType()); - query_update_feed.bindValue(":update_interval", new_feed->autoUpdateInterval()); + query_update_feed.bindValue(":update_interval", new_feed->autoUpdateInitialInterval()); query_update_feed.bindValue(":type", new_feed->type()); query_update_feed.bindValue(":id", original_feed->id()); @@ -358,7 +358,7 @@ bool FeedsModel::editStandardFeed(FeedsModelStandardFeed *original_feed, original_feed->setUsername(new_feed->username()); original_feed->setPassword(new_feed->password()); original_feed->setAutoUpdateType(new_feed->autoUpdateType()); - original_feed->setAutoUpdateInterval(new_feed->autoUpdateInterval()); + original_feed->setAutoUpdateInitialInterval(new_feed->autoUpdateInitialInterval()); original_feed->setType(new_feed->type()); if (original_parent != new_parent) { @@ -389,6 +389,47 @@ bool FeedsModel::editStandardFeed(FeedsModelStandardFeed *original_feed, return true; } +QList FeedsModel::feedsForScheduledUpdate(int global_auto_update_minutes_remaining) { + QList feeds_for_update; + + foreach (FeedsModelFeed *feed, allFeeds()) { + FeedsModelStandardFeed *std_feed = static_cast(feed); + + switch (std_feed->autoUpdateType()) { + case FeedsModelStandardFeed::DontAutoUpdate: + // Do not auto-update this feed ever. + continue; + + case FeedsModelStandardFeed::DefaultAutoUpdate: + if (global_auto_update_minutes_remaining == 0) { + feeds_for_update.append(feed); + } + + break; + + case FeedsModelStandardFeed::SpecificAutoUpdate: + default: + int remaining_interval = std_feed->autoUpdateRemainingInterval(); + + if (--remaining_interval <= 0) { + // Interval of this feed passed, include this feed in the output list + // and reset the interval. + feeds_for_update.append(feed); + std_feed->setAutoUpdateRemainingInterval(std_feed->autoUpdateInitialInterval()); + } + else { + // Interval did not pass, set new decremented interval and do NOT + // include this feed in the output list. + std_feed->setAutoUpdateRemainingInterval(remaining_interval); + } + + break; + } + } + + return feeds_for_update; +} + QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 15abb97f3..23f016b1f 100644 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -66,6 +66,10 @@ class FeedsModel : public QAbstractItemModel { bool editStandardFeed(FeedsModelStandardFeed *original_feed, FeedsModelStandardFeed *new_feed); + // Returns the list of updates which should be updated + // according to auto-update schedule. + QList feedsForScheduledUpdate(int global_auto_update_minutes_remaining); + // Returns (undeleted) messages for given feeds. QList messagesForFeeds(const QList &feeds); diff --git a/src/core/feedsmodelstandardfeed.cpp b/src/core/feedsmodelstandardfeed.cpp index d8379e22c..61a70b311 100755 --- a/src/core/feedsmodelstandardfeed.cpp +++ b/src/core/feedsmodelstandardfeed.cpp @@ -17,7 +17,7 @@ FeedsModelStandardFeed::FeedsModelStandardFeed(FeedsModelRootItem *parent_item) : FeedsModelFeed(parent_item), m_autoUpdateType(DontAutoUpdate), - m_autoUpdateInterval(DEFAULT_AUTO_UPDATE_INTERVAL) { + m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL) { } FeedsModelStandardFeed::~FeedsModelStandardFeed() { @@ -38,7 +38,7 @@ FeedsModelStandardFeed *FeedsModelStandardFeed::loadFromRecord(const QSqlRecord feed->setUsername(record.value(FDS_DB_USERNAME_INDEX).toString()); feed->setPassword(record.value(FDS_DB_PASSWORD_INDEX).toString()); feed->setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); - feed->setAutoUpdateInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); + feed->setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); feed->updateCounts(); return feed; @@ -284,3 +284,7 @@ void FeedsModelStandardFeed::updateMessages(const QList &messages) { qDebug("Transaction commit for message downloader failed."); } } + + + + diff --git a/src/core/feedsmodelstandardfeed.h b/src/core/feedsmodelstandardfeed.h index e59258e72..4bcbdbc78 100644 --- a/src/core/feedsmodelstandardfeed.h +++ b/src/core/feedsmodelstandardfeed.h @@ -16,7 +16,7 @@ class FeedsModelStandardFeed : public FeedsModelFeed { public: enum AutoUpdateType { DontAutoUpdate = 0, - DefaultAutpUpdate = 1, + DefaultAutoUpdate = 1, SpecificAutoUpdate = 2 }; @@ -51,12 +51,15 @@ class FeedsModelStandardFeed : public FeedsModelFeed { m_url = url; } - inline int autoUpdateInterval() const { - return m_autoUpdateInterval; + inline int autoUpdateInitialInterval() const { + return m_autoUpdateInitialInterval; } - inline void setAutoUpdateInterval(int auto_update_interval) { - m_autoUpdateInterval = auto_update_interval; + inline void setAutoUpdateInitialInterval(int auto_update_interval) { + // If new initial auto-update interval is set, then + // we should reset time that remains to the next auto-update. + m_autoUpdateInitialInterval = auto_update_interval; + m_autoUpdateRemainingInterval = auto_update_interval; } inline AutoUpdateType autoUpdateType() const { @@ -67,6 +70,14 @@ class FeedsModelStandardFeed : public FeedsModelFeed { m_autoUpdateType = autoUpdateType; } + inline int autoUpdateRemainingInterval() const { + return m_autoUpdateRemainingInterval; + } + + inline void setAutoUpdateRemainingInterval(int autoUpdateRemainingInterval) { + m_autoUpdateRemainingInterval = autoUpdateRemainingInterval; + } + // Loads standard feed object from given SQL record. static FeedsModelStandardFeed *loadFromRecord(const QSqlRecord &record); @@ -81,7 +92,8 @@ class FeedsModelStandardFeed : public FeedsModelFeed { // NOTE: Number -1 means "do not auto-update", number // 0 means "auto-update with global interval" and number // > 0 means "auto-update with specific interval". - int m_autoUpdateInterval; + int m_autoUpdateInitialInterval; + int m_autoUpdateRemainingInterval; QString m_encoding; QString m_url; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 0548c09e9..b4c438a08 100644 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -27,7 +27,6 @@ #include #include #include -#include FeedMessageViewer::FeedMessageViewer(QWidget *parent) @@ -37,23 +36,13 @@ FeedMessageViewer::FeedMessageViewer(QWidget *parent) m_feedsView(new FeedsView(this)), m_messagesBrowser(new WebBrowser(this)), m_feedDownloaderThread(new QThread()), - m_feedDownloader(new FeedDownloader()), - m_autoUpdateTimer(new QTimer(this)) { + m_feedDownloader(new FeedDownloader()) { initialize(); initializeViews(); createConnections(); // Start the feed downloader thread. m_feedDownloaderThread->start(); - - // Start the auto-update timer. - // TODO: co kdyz update bude trvat dele nez minutu? - // asi udelat metodu pro update v teto tride - // ta obali update v m_feedsView - // a nastavit jako single shot -> true nejak nevim - m_autoUpdateTimer->setInterval(AUTO_UPDATE_INTERVAL); - m_autoUpdateTimer->setSingleShot(false); - m_autoUpdateTimer->start(); } FeedMessageViewer::~FeedMessageViewer() { @@ -100,7 +89,10 @@ void FeedMessageViewer::loadSize() { default_msg_section_size).toInt()); } -void FeedMessageViewer::quitDownloader() { +void FeedMessageViewer::quit() { + // Quit the feeds view (stops auto-update timer etc.). + m_feedsView->quit(); + qDebug("Quitting feed downloader thread."); m_feedDownloaderThread->quit(); @@ -141,10 +133,6 @@ void FeedMessageViewer::onFeedUpdatesFinished() { void FeedMessageViewer::createConnections() { FormMain *form_main = FormMain::instance(); - // Timed actions. - connect(m_autoUpdateTimer, SIGNAL(timeout()), - m_feedsView, SLOT(updateScheduledFeeds())); - // Message changers. connect(m_messagesView, SIGNAL(currentMessagesRemoved()), m_messagesBrowser, SLOT(clear())); diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index 954eedb5c..2436a01e7 100644 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -14,7 +14,6 @@ class FeedsModelFeed; class QToolBar; class QSplitter; class QProgressBar; -class QTimer; class FeedMessageViewer : public TabContent { Q_OBJECT @@ -40,8 +39,9 @@ class FeedMessageViewer : public TabContent { void saveSize(); void loadSize(); - // Destroys worker/feed downloader thread. - void quitDownloader(); + // Destroys worker/feed downloader thread and + // stops any child widgets/workers. + void quit(); protected slots: // Updates counts of messages for example in tray icon. @@ -74,8 +74,6 @@ class FeedMessageViewer : public TabContent { QThread *m_feedDownloaderThread; FeedDownloader *m_feedDownloader; - - QTimer *m_autoUpdateTimer; }; #endif // FEEDMESSAGEVIEWER_H diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 4108a021d..a17910ccb 100644 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -20,24 +20,62 @@ #include #include #include -#include +#include FeedsView::FeedsView(QWidget *parent) : QTreeView(parent), m_contextMenuCategoriesFeeds(NULL), - m_contextMenuEmptySpace(NULL) { + m_contextMenuEmptySpace(NULL), + m_autoUpdateTimer(new QTimer(this)) { + // Allocate models. m_proxyModel = new FeedsProxyModel(this); m_sourceModel = m_proxyModel->sourceModel(); + // Timed actions. + connect(m_autoUpdateTimer, SIGNAL(timeout()), + this, SLOT(executeNextAutoUpdate())); + setModel(m_proxyModel); setupAppearance(); + + // Setup the timer. + updateAutoUpdateStatus(); } FeedsView::~FeedsView() { qDebug("Destroying FeedsView instance."); } +void FeedsView::quit() { + if (m_autoUpdateTimer->isActive()) { + m_autoUpdateTimer->stop(); + } +} + +void FeedsView::updateAutoUpdateStatus() { + // Update intervals. + m_globalAutoUpdateInitialInterval = Settings::instance()->value(APP_CFG_FEEDS, "auto_update_interval", DEFAULT_AUTO_UPDATE_INTERVAL).toInt(); + m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval; + + // Start/stop the timer as needed. + if (Settings::instance()->value(APP_CFG_FEEDS, "auto_update_enabled", false).toBool()) { + 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 { + if (m_autoUpdateTimer->isActive()) { + m_autoUpdateTimer->stop(); + + qDebug("Auto-update timer stopped."); + } + } +} + void FeedsView::setSortingEnabled(bool enable) { QTreeView::setSortingEnabled(enable); header()->setSortIndicatorShown(false); @@ -102,20 +140,38 @@ void FeedsView::updateSelectedFeeds() { } } -void FeedsView::updateScheduledFeeds() { - if (SystemFactory::instance()->applicationCloseLock()->tryLock()) { - // Update master lock obtained, select - // feeds which should be updated and - // request their update. - // TODO: emit feedsUpdateRequested(selectedFeeds()); - // tady vybrat feedy ktery se maj updatovat ted +void FeedsView::executeNextAutoUpdate() { + if (!SystemFactory::instance()->applicationCloseLock()->tryLock() && + SystemTrayIcon::isSystemTrayActivated()) { + SystemTrayIcon::instance()->showMessage(tr("Cannot update scheduled items"), + tr("You cannot update scheduled items because another feed update is ongoing."), + QSystemTrayIcon::Warning); + + // Cannot update, quit. + return; + } + + // If this reaches less than zero, then feeds with global auto-update interval should + // be updated. + if (--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 feeds_for_update = m_sourceModel->feedsForScheduledUpdate(m_globalAutoUpdateRemainingInterval); + + if (feeds_for_update.isEmpty()) { + // No feeds are scheduled for update now, unlock the master lock. + SystemFactory::instance()->applicationCloseLock()->unlock(); } else { - if (SystemTrayIcon::isSystemTrayActivated()) { - SystemTrayIcon::instance()->showMessage(tr("Cannot update scheduled items"), - tr("You cannot update scheduled items because another feed update is ongoing."), - QSystemTrayIcon::Warning); - } + // Request update for given feeds. + emit feedsUpdateRequested(feeds_for_update); } } diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 571821a5b..5c4c56f86 100644 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -5,11 +5,13 @@ #include "core/messagesmodel.h" #include "core/feedsmodel.h" +#include "core/settings.h" class FeedsProxyModel; class FeedsModelFeed; class FeedsModelCategory; +class QTimer; class FeedsView : public QTreeView { Q_OBJECT @@ -27,6 +29,13 @@ class FeedsView : public QTreeView { return m_sourceModel; } + // Does necessary job before quitting this component. + void quit(); + + // Resets global auto-update intervals according to settings + // and starts/stop the timer as needed. + void updateAutoUpdateStatus(); + // Enables or disables sorting. void setSortingEnabled(bool enable); @@ -44,7 +53,9 @@ class FeedsView : public QTreeView { // Feed updating. void updateAllFeeds(); void updateSelectedFeeds(); - void updateScheduledFeeds(); + + // Is executed when next auto-update round could be done. + void executeNextAutoUpdate(); // Feed read/unread manipulators. void markSelectedFeedsReadStatus(int read); @@ -130,6 +141,11 @@ class FeedsView : public QTreeView { QList m_selectedFeeds; FeedsModel *m_sourceModel; FeedsProxyModel *m_proxyModel; + + // Auto-update stuff. + QTimer *m_autoUpdateTimer; + int m_globalAutoUpdateInitialInterval; + int m_globalAutoUpdateRemainingInterval; }; #endif // FEEDSVIEW_H diff --git a/src/gui/formmain.cpp b/src/gui/formmain.cpp index 1456af77a..efdb3735d 100755 --- a/src/gui/formmain.cpp +++ b/src/gui/formmain.cpp @@ -176,19 +176,10 @@ void FormMain::onSaveState(QSessionManager &manager) { void FormMain::onAboutToQuit() { // Make sure that we obtain close lock // BEFORE even trying to quit the application. - if (SystemFactory::instance()->applicationCloseLock()->tryLock(CLOSE_LOCK_TIMEOUT)) { - // Application obtained permission to close - // in a safety way. - qDebug("Close lock obtained safely."); - } - else { - // Request for write lock timed-out. This means - // that some critical action can be processed right now. - qDebug("Close lock timed-out."); - } + bool locked_safely = SystemFactory::instance()->applicationCloseLock()->tryLock(CLOSE_LOCK_TIMEOUT); qDebug("Cleaning up resources and saving application state."); - m_ui->m_tabWidget->feedMessageViewer()->quitDownloader(); + m_ui->m_tabWidget->feedMessageViewer()->quit(); if (Settings::instance()->value(APP_CFG_MESSAGES, "clear_read_on_exit", false).toBool()) { m_ui->m_tabWidget->feedMessageViewer()->feedsView()->clearAllReadMessages(); @@ -196,6 +187,20 @@ void FormMain::onAboutToQuit() { DatabaseFactory::instance()->saveMemoryDatabase(); saveSize(); + + if (locked_safely) { + // Application obtained permission to close + // in a safety way. + qDebug("Close lock was obtained safely."); + + // We locked the lock to exit peacefully, unlock it to avoid warnings. + SystemFactory::instance()->applicationCloseLock()->unlock(); + } + else { + // Request for write lock timed-out. This means + // that some critical action can be processed right now. + qDebug("Close lock timed-out."); + } } bool FormMain::event(QEvent *event) { diff --git a/src/gui/formsettings.cpp b/src/gui/formsettings.cpp index f2c12941d..b23a58da2 100755 --- a/src/gui/formsettings.cpp +++ b/src/gui/formsettings.cpp @@ -163,6 +163,7 @@ void FormSettings::saveFeedsMessages() { Settings::instance()->setValue(APP_CFG_FEEDS, "auto_update_enabled", m_ui->m_checkAutoUpdate->isChecked()); Settings::instance()->setValue(APP_CFG_FEEDS, "auto_update_interval", m_ui->m_spinAutoUpdateInterval->value()); + FormMain::instance()->tabWidget()->feedMessageViewer()->feedsView()->updateAutoUpdateStatus(); } void FormSettings::displayProxyPassword(int state) { diff --git a/src/gui/formstandardfeeddetails.cpp b/src/gui/formstandardfeeddetails.cpp index 14ab3386b..7c930d3c1 100644 --- a/src/gui/formstandardfeeddetails.cpp +++ b/src/gui/formstandardfeeddetails.cpp @@ -136,7 +136,7 @@ void FormStandardFeedDetails::onAutoUpdateTypeChanged(int new_index) { switch (auto_update_type) { case FeedsModelStandardFeed::DontAutoUpdate: - case FeedsModelStandardFeed::DefaultAutpUpdate: + case FeedsModelStandardFeed::DefaultAutoUpdate: m_ui->m_spinAutoUpdateInterval->setEnabled(false); break; @@ -198,7 +198,7 @@ void FormStandardFeedDetails::apply() { new_feed->setUsername(m_ui->m_txtUsername->lineEdit()->text()); new_feed->setPassword(m_ui->m_txtPassword->lineEdit()->text()); new_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData(m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); - new_feed->setAutoUpdateInterval(m_ui->m_spinAutoUpdateInterval->value()); + new_feed->setAutoUpdateInitialInterval(m_ui->m_spinAutoUpdateInterval->value()); new_feed->setParent(parent); if (m_editableFeed == NULL) { @@ -280,7 +280,7 @@ void FormStandardFeedDetails::setEditableFeed(FeedsModelStandardFeed *editable_f m_ui->m_txtPassword->lineEdit()->setText(editable_feed->password()); m_ui->m_txtUrl->lineEdit()->setText(editable_feed->url()); m_ui->m_cmbAutoUpdateType->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue((int) editable_feed->autoUpdateType()))); - m_ui->m_spinAutoUpdateInterval->setValue(editable_feed->autoUpdateInterval()); + m_ui->m_spinAutoUpdateInterval->setValue(editable_feed->autoUpdateInitialInterval()); } void FormStandardFeedDetails::initialize() { @@ -355,7 +355,7 @@ void FormStandardFeedDetails::initialize() { // Setup auto-update options. m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL); m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), QVariant::fromValue((int) FeedsModelStandardFeed::DontAutoUpdate)); - m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) FeedsModelStandardFeed::DefaultAutpUpdate)); + m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) FeedsModelStandardFeed::DefaultAutoUpdate)); m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), QVariant::fromValue((int) FeedsModelStandardFeed::SpecificAutoUpdate)); // Set tab order.