Very initial implementation of feeds auto-update.

This commit is contained in:
Martin Rotter 2014-02-04 10:02:07 +01:00
parent 5d000862ab
commit 63cb32a098
11 changed files with 188 additions and 63 deletions

View File

@ -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<FeedsModelFeed*> FeedsModel::feedsForScheduledUpdate(int global_auto_update_minutes_remaining) {
QList<FeedsModelFeed*> feeds_for_update;
foreach (FeedsModelFeed *feed, allFeeds()) {
FeedsModelStandardFeed *std_feed = static_cast<FeedsModelStandardFeed*>(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<Message> FeedsModel::messagesForFeeds(const QList<FeedsModelFeed*> &feeds) {
QList<Message> messages;

View File

@ -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<FeedsModelFeed*> feedsForScheduledUpdate(int global_auto_update_minutes_remaining);
// Returns (undeleted) messages for given feeds.
QList<Message> messagesForFeeds(const QList<FeedsModelFeed*> &feeds);

View File

@ -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<FeedsModelStandardFeed::AutoUpdateType>(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<Message> &messages) {
qDebug("Transaction commit for message downloader failed.");
}
}

View File

@ -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;

View File

@ -27,7 +27,6 @@
#include <QThread>
#include <QProgressBar>
#include <QStatusBar>
#include <QTimer>
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()));

View File

@ -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

View File

@ -20,24 +20,62 @@
#include <QContextMenuEvent>
#include <QPointer>
#include <QPainter>
#include <QReadWriteLock>
#include <QTimer>
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<FeedsModelFeed*> 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);
}
}

View File

@ -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<int> m_selectedFeeds;
FeedsModel *m_sourceModel;
FeedsProxyModel *m_proxyModel;
// Auto-update stuff.
QTimer *m_autoUpdateTimer;
int m_globalAutoUpdateInitialInterval;
int m_globalAutoUpdateRemainingInterval;
};
#endif // FEEDSVIEW_H

View File

@ -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) {

View File

@ -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) {

View File

@ -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<FeedsModelStandardFeed::AutoUpdateType>(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.