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] + +[+] 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.