diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG
index 5f40745c3..8dd1222c0 100644
--- a/resources/text/CHANGELOG
+++ b/resources/text/CHANGELOG
@@ -1,6 +1,11 @@
[2.0.0]
-- Initial second generation release.
+- [@] Initial second generation release.
+
+[+] added
+[#] fixed
+[~] changed
+[@] other action
diff --git a/src/core/defs.h.in b/src/core/defs.h.in
index f9566788d..3374b16d0 100755
--- a/src/core/defs.h.in
+++ b/src/core/defs.h.in
@@ -29,6 +29,7 @@
#define NO_PARENT_CATEGORY -1
#define TRAY_ICON_BUBBLE_TIMEOUT 15000
#define KEY_MESSAGES_VIEW "messages_view_column_"
+#define CLOSE_LOCK_TIMEOUT 2000
#define APP_DB_INIT_FILE "db_init.sql"
#define APP_DB_INIT_SPLIT "-- !\n"
diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp
index a2681309e..f44ca474a 100644
--- a/src/core/messagesmodel.cpp
+++ b/src/core/messagesmodel.cpp
@@ -56,15 +56,15 @@ void MessagesModel::setupFonts() {
}
QList MessagesModel::currentFeeds() const {
- return m_currentFeeds;
+ return m_currentFeeds;
}
void MessagesModel::loadMessages(const QList feed_ids) {
- // Conversion of parameter.
- m_currentFeeds = feed_ids;
-
- setFilter(QString("feed IN (%1) AND deleted = 0").arg(textualFeeds().join(", ")));
+ // Conversion of parameter.
+ m_currentFeeds = feed_ids;
+
+ setFilter(QString("feed IN (%1) AND deleted = 0").arg(textualFeeds().join(", ")));
select();
fetchAll();
}
@@ -428,7 +428,7 @@ bool MessagesModel::setAllMessagesDeleted(int deleted) {
QSqlQuery query_delete_msg(db_handle);
if (!query_delete_msg.prepare(QString("UPDATE messages SET deleted = :deleted "
- "WHERE feed IN (%1) AND deleted = 0").arg(textualFeeds().join(", ")))) {
+ "WHERE feed IN (%1) AND deleted = 0").arg(textualFeeds().join(", ")))) {
qWarning("Query preparation failed for message deletion.");
db_handle.rollback();
diff --git a/src/core/systemfactory.cpp b/src/core/systemfactory.cpp
index 6c45f4936..2d4f97c4a 100644
--- a/src/core/systemfactory.cpp
+++ b/src/core/systemfactory.cpp
@@ -17,10 +17,13 @@
QPointer SystemFactory::s_instance;
SystemFactory::SystemFactory(QObject *parent) : QObject(parent) {
+ m_applicationCloseLock = new QReadWriteLock(QReadWriteLock::NonRecursive);
}
SystemFactory::~SystemFactory() {
qDebug("Destroying SystemFactory instance.");
+
+ delete m_applicationCloseLock;
}
@@ -99,6 +102,10 @@ SystemFactory *SystemFactory::getInstance() {
return s_instance;
}
+QReadWriteLock *SystemFactory::applicationCloseLock() const {
+ return m_applicationCloseLock;
+}
+
bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
SystemFactory::AutoStartStatus current_status = SystemFactory::getAutoStartStatus();
diff --git a/src/core/systemfactory.h b/src/core/systemfactory.h
index fb303aec9..c38cf7afd 100644
--- a/src/core/systemfactory.h
+++ b/src/core/systemfactory.h
@@ -6,14 +6,17 @@
class QReadWriteLock;
+class QMutex;
class SystemFactory : public QObject {
Q_OBJECT
private:
+ // Constructors and destructors.
explicit SystemFactory(QObject *parent = 0);
public:
+ // Constructors and destructors.
virtual ~SystemFactory();
// Specifies possible states of auto-start functionality.
@@ -40,7 +43,24 @@ class SystemFactory : public QObject {
// Singleton getter.
static SystemFactory *getInstance();
+ // Access to application-wide close lock.
+ QReadWriteLock *applicationCloseLock() const;
+
private:
+ // This read-write lock is used by application on its close.
+ // Application locks this lock for WRITTING.
+ // This means that if application locks that lock, then
+ // no other transaction-critical action can acquire lock
+ // for reading and won't be executed, so no critical action
+ // will be running when application quits
+ //
+ // EACH critical action locks this lock for READING.
+ // Several actions can lock this lock for reading.
+ // But of user decides to close the application (in other words,
+ // tries to lock the lock for writting), then no other
+ // action will be allowed to lock for reading.
+ QReadWriteLock *m_applicationCloseLock;
+
static QPointer s_instance;
};
diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h
index f93154100..706585679 100644
--- a/src/gui/feedsview.h
+++ b/src/gui/feedsview.h
@@ -18,6 +18,7 @@ class FeedsView : public QTreeView {
void setSortingEnabled(bool enable);
+ // Returns list of selected feeds.
QList selectedFeeds() const;
public slots:
@@ -25,7 +26,10 @@ class FeedsView : public QTreeView {
void updateCountsOfSelectedFeeds();
protected:
+ // Sets up appearance of this widget.
void setupAppearance();
+
+
void selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected);
diff --git a/src/gui/formmain.cpp b/src/gui/formmain.cpp
index 9a6408c35..337c5f573 100755
--- a/src/gui/formmain.cpp
+++ b/src/gui/formmain.cpp
@@ -2,6 +2,7 @@
#include "core/defs.h"
#include "core/settings.h"
+#include "core/systemfactory.h"
#include "gui/formabout.h"
#include "gui/formsettings.h"
#include "gui/webbrowser.h"
@@ -17,6 +18,7 @@
#include
#include
#include
+#include
FormMain *FormMain::s_instance;
@@ -129,6 +131,20 @@ void FormMain::processExecutionMessage(const QString &message) {
void FormMain::quit() {
qDebug("Quitting the application.");
+
+ // Make sure that we obtain close lock
+ // BEFORE even trying to quit the application.
+ if (SystemFactory::getInstance()->applicationCloseLock()->tryLockForWrite(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.");
+ }
+
qApp->quit();
}
@@ -178,6 +194,7 @@ void FormMain::onSaveState(QSessionManager &manager) {
void FormMain::onAboutToQuit() {
qDebug("Cleaning up resources and saving application state.");
+
saveSize();
}
diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp
index 737f9f1da..8c4300fc1 100644
--- a/src/gui/messagesview.cpp
+++ b/src/gui/messagesview.cpp
@@ -103,6 +103,11 @@ void MessagesView::setupAppearance() {
setSortingEnabled(true);
setAllColumnsShowFocus(true);
setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ // Make sure that initial sorting is that unread messages are visible
+ // first.
+ // NOTE: This can be rewritten so that it's changeable.
+ sortByColumn(MSG_DB_READ_INDEX, Qt::AscendingOrder);
}
void MessagesView::keyPressEvent(QKeyEvent *event) {
@@ -198,7 +203,13 @@ void MessagesView::currentChanged(const QModelIndex ¤t,
}
void MessagesView::loadFeeds(const QList &feed_ids) {
+ // Load messages.
+ // TODO: Here we could load user-defined default sorting
+ // column/order AND possibly hide/show user-defined columns.
m_sourceModel->loadMessages(feed_ids);
+
+ // Messages are loaded, make sure that previously
+ // active message is not shown in browser.
emit currentMessageRemoved();
}
diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h
index 3266334b9..51ea6093f 100755
--- a/src/gui/messagesview.h
+++ b/src/gui/messagesview.h
@@ -23,6 +23,7 @@ class MessagesView : public QTreeView {
MessagesModel *sourceModel();
public slots:
+ // Loads un-deleted messages from selected feeds.
void loadFeeds(const QList &feed_ids);
// Message manipulators.