Work on mutexes, preparation for two next issues.

This commit is contained in:
Martin Rotter 2015-06-02 12:22:38 +02:00
parent 136cd10fd5
commit 71996f27de
16 changed files with 155 additions and 100 deletions

View File

@ -383,6 +383,7 @@ set(APP_SOURCES
src/miscellaneous/iconfactory.cpp src/miscellaneous/iconfactory.cpp
src/miscellaneous/iofactory.cpp src/miscellaneous/iofactory.cpp
src/miscellaneous/autosaver.cpp src/miscellaneous/autosaver.cpp
src/miscellaneous/mutex.cpp
# EXCEPTIONS sources. # EXCEPTIONS sources.
src/exceptions/applicationexception.cpp src/exceptions/applicationexception.cpp
@ -476,6 +477,7 @@ set(APP_HEADERS
src/miscellaneous/iconfactory.h src/miscellaneous/iconfactory.h
src/miscellaneous/skinfactory.h src/miscellaneous/skinfactory.h
src/miscellaneous/autosaver.h src/miscellaneous/autosaver.h
src/miscellaneous/mutex.h
# CORE headers. # CORE headers.
src/core/messagesmodel.h src/core/messagesmodel.h

View File

@ -21,6 +21,7 @@
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "core/messagesproxymodel.h" #include "core/messagesproxymodel.h"
#include "core/feeddownloader.h" #include "core/feeddownloader.h"
#include "core/feedsmodelfeed.h" #include "core/feedsmodelfeed.h"

View File

@ -26,6 +26,7 @@
#include "core/feedsmodelrecyclebin.h" #include "core/feedsmodelrecyclebin.h"
#include "core/feedsmodelfeed.h" #include "core/feedsmodelfeed.h"
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
#include "miscellaneous/mutex.h"
#include "gui/formmain.h" #include "gui/formmain.h"
#include "gui/formcategorydetails.h" #include "gui/formcategorydetails.h"
#include "gui/formfeeddetails.h" #include "gui/formfeeddetails.h"
@ -202,8 +203,7 @@ void FeedsView::executeNextAutoUpdate() {
return; return;
} }
// If global auto-update is enabled // If global auto-update is enabled and its interval counter reached zero,
// and its interval counter reached zero,
// then we need to restore it. // then we need to restore it.
if (m_globalAutoUpdateEnabled && --m_globalAutoUpdateRemainingInterval < 0) { if (m_globalAutoUpdateEnabled && --m_globalAutoUpdateRemainingInterval < 0) {
// We should start next auto-update interval. // We should start next auto-update interval.

View File

@ -36,6 +36,7 @@ class FormImportExport : public QDialog {
OPML20 = 0 OPML20 = 0
}; };
// Constructors.
explicit FormImportExport(QWidget *parent = 0); explicit FormImportExport(QWidget *parent = 0);
virtual ~FormImportExport(); virtual ~FormImportExport();

View File

@ -21,6 +21,7 @@
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "network-web/webfactory.h" #include "network-web/webfactory.h"

View File

@ -19,6 +19,7 @@
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/iofactory.h" #include "miscellaneous/iofactory.h"
#include "miscellaneous/mutex.h"
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "gui/feedmessageviewer.h" #include "gui/feedmessageviewer.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
@ -66,13 +67,20 @@ DownloadManager *Application::downloadManager() {
m_downloadManager = new DownloadManager(); m_downloadManager = new DownloadManager();
connect(m_downloadManager, SIGNAL(downloadFinished()), mainForm()->statusBar(), SLOT(clearProgressDownload())); connect(m_downloadManager, SIGNAL(downloadFinished()), mainForm()->statusBar(), SLOT(clearProgressDownload()));
connect(m_downloadManager, SIGNAL(downloadProgress(int,QString)), connect(m_downloadManager, SIGNAL(downloadProgress(int,QString)), mainForm()->statusBar(), SLOT(showProgressDownload(int,QString)));
mainForm()->statusBar(), SLOT(showProgressDownload(int,QString)));
} }
return m_downloadManager; return m_downloadManager;
} }
Mutex *Application::feedUpdateLock() {
if (m_updateFeedsLock == NULL) {
m_updateFeedsLock = new Mutex();
}
return m_updateFeedsLock;
}
void Application::backupDatabaseSettings(bool backup_database, bool backup_settings, void Application::backupDatabaseSettings(bool backup_database, bool backup_settings,
const QString &target_path, const QString &backup_name) { const QString &target_path, const QString &backup_name) {
if (!QFileInfo(target_path).isWritable()) { if (!QFileInfo(target_path).isWritable()) {

View File

@ -30,7 +30,6 @@
#include "gui/systemtrayicon.h" #include "gui/systemtrayicon.h"
#include "network-web/downloadmanager.h" #include "network-web/downloadmanager.h"
#include <QMutex>
#include <QList> #include <QList>
#if defined(qApp) #if defined(qApp)
@ -44,6 +43,7 @@
class FormMain; class FormMain;
class IconFactory; class IconFactory;
class QAction; class QAction;
class Mutex;
class Application : public QtSingleApplication { class Application : public QtSingleApplication {
Q_OBJECT Q_OBJECT
@ -99,13 +99,7 @@ class Application : public QtSingleApplication {
} }
// Access to application-wide close lock. // Access to application-wide close lock.
inline QMutex *feedUpdateLock() { Mutex *feedUpdateLock();
if (m_updateFeedsLock == NULL) {
m_updateFeedsLock = new QMutex();
}
return m_updateFeedsLock;
}
inline FormMain *mainForm() { inline FormMain *mainForm() {
return m_mainForm; return m_mainForm;
@ -178,7 +172,7 @@ class Application : public QtSingleApplication {
// But of user decides to close the application (in other words, // But of user decides to close the application (in other words,
// tries to lock the lock for writing), then no other // tries to lock the lock for writing), then no other
// action will be allowed to lock for reading. // action will be allowed to lock for reading.
QMutex *m_updateFeedsLock; Mutex *m_updateFeedsLock;
QList<QAction*> m_userActions; QList<QAction*> m_userActions;
FormMain *m_mainForm; FormMain *m_mainForm;
SystemTrayIcon *m_trayIcon; SystemTrayIcon *m_trayIcon;

View File

@ -59,76 +59,3 @@ bool IOFactory::copyFile(const QString &source, const QString &destination) {
return QFile::copy(source, destination); return QFile::copy(source, destination);
} }
bool IOFactory::removeFolder(const QString& directory_name,
const QStringList& exception_file_list,
const QStringList& exception_folder_list) {
bool result = true;
QDir dir(directory_name);
if (dir.exists(directory_name)) {
foreach (QFileInfo info,
dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System |
QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) {
if (!exception_folder_list.contains(info.fileName())) {
result &= removeFolder(info.absoluteFilePath(), exception_file_list, exception_folder_list);
}
}
else if (!exception_file_list.contains(info.fileName())) {
if (!QFile::remove(info.absoluteFilePath())) {
result &= false;
qDebug("Failed to remove file \'%s\'.", qPrintable(QDir::toNativeSeparators(info.absoluteFilePath())));
}
else {
result &= true;
}
}
}
if (dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files).isEmpty()) {
result &= dir.rmdir(directory_name);
}
}
return result;
}
bool IOFactory::copyFolder(const QString &source, const QString &destination) {
QDir dir_source(source);
if (!dir_source.exists()) {
return false;
}
QDir dir_destination(destination);
if (!dir_destination.exists()) {
dir_destination.mkpath(destination);
}
foreach (QString d, dir_source.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
QString dst_path = destination + QDir::separator() + d;
dir_source.mkpath(dst_path);
copyFolder(source + QDir::separator() + d, dst_path);
}
foreach (QString f, dir_source.entryList(QDir::Files)) {
QString original_file = source + QDir::separator() + f;
QString destination_file = destination + QDir::separator() + f;
if (!QFile::exists(destination_file) || QFile::remove(destination_file)) {
if (QFile::copy(original_file, destination_file)) {
qDebug("Copied file \'%s\'.", qPrintable(f));
}
else {
qDebug("Failed to copy file \'%s\'.", qPrintable(QDir::toNativeSeparators(original_file)));
}
}
else {
qDebug("Failed to remove file \'%s\'.", qPrintable(QDir::toNativeSeparators(original_file)));
}
}
return true;
}

View File

@ -18,7 +18,6 @@
#ifndef IOFACTORY_H #ifndef IOFACTORY_H
#define IOFACTORY_H #define IOFACTORY_H
#include <QStringList>
#include <QCoreApplication> #include <QCoreApplication>
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
@ -40,19 +39,12 @@ class IOFactory {
// Returns system-wide folder according to type. // Returns system-wide folder according to type.
static QString getSystemFolder(SYSTEM_FOLDER_ENUM::StandardLocation location); static QString getSystemFolder(SYSTEM_FOLDER_ENUM::StandardLocation location);
// Returns contents of a file.
// Throws exception when no such file exists.
static QByteArray readTextFile(const QString &file_path); static QByteArray readTextFile(const QString &file_path);
// Copies file, overwrites destination. // Copies file, overwrites destination.
static bool copyFile(const QString &source, const QString &destination); static bool copyFile(const QString &source, const QString &destination);
// Copy whole directory recursively.
// Destination path is created if it does not exist.
static bool copyFolder(const QString &source, const QString &destination);
// Removes directory recursively and skips given folders/files.
static bool removeFolder(const QString &directory_name,
const QStringList &exception_file_list = QStringList(),
const QStringList &exception_folder_list = QStringList());
}; };
#endif // IOFACTORY_H #endif // IOFACTORY_H

View File

@ -0,0 +1,71 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2015 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "miscellaneous/mutex.h"
Mutex::Mutex(QMutex::RecursionMode mode, QObject *parent) : QObject(parent), m_mutex(new QMutex(mode)), m_isLocked(false) {
}
Mutex::~Mutex() {
qDebug("Destroying Mutex instance.");
delete m_mutex;
}
void Mutex::lock() {
m_mutex->lock();
setLocked();
}
bool Mutex::tryLock() {
bool result;
if (result = m_mutex->tryLock()) {
setLocked();
}
return result;
}
bool Mutex::tryLock(int timeout) {
bool result;
if (result = m_mutex->tryLock(timeout)) {
setLocked();
}
return result;
}
void Mutex::unlock() {
m_mutex->unlock();
setUnlocked();
}
void Mutex::setLocked() {
m_isLocked = true;
emit locked();
}
void Mutex::setUnlocked() {
m_isLocked = false;
emit unlocked();
}
bool Mutex::isLocked() const {
return m_isLocked;
}

56
src/miscellaneous/mutex.h Normal file
View File

@ -0,0 +1,56 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2015 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef MUTEX_H
#define MUTEX_H
#include <QMutex>
#include <QObject>
class Mutex : public QObject {
Q_OBJECT
public:
// Constructors.
explicit Mutex(QMutex::RecursionMode mode = QMutex::NonRecursive, QObject *parent = 0);
virtual ~Mutex();
// Main methods.
void lock();
bool tryLock();
bool tryLock(int timeout);
void unlock();
// Identifies if mutes is locked or not.
bool isLocked() const;
protected:
// These methods set proper value for m_isLocked and emit signals.
void setLocked();
void setUnlocked();
signals:
void locked();
void unlocked();
private:
QMutex *m_mutex;
bool m_isLocked;
};
#endif // MUTEX_H

View File

@ -294,7 +294,7 @@ class Settings : public QSettings {
return m_initializationStatus; return m_initializationStatus;
} }
// Getter/setter for settings values. // Getters/setters for settings values.
inline QVariant value(const QString &section, const QString &key, const QVariant &default_value = QVariant()) { inline QVariant value(const QString &section, const QString &key, const QVariant &default_value = QVariant()) {
return QSettings::value(QString("%1/%2").arg(section, key), default_value); return QSettings::value(QString("%1/%2").arg(section, key), default_value);
} }

View File

@ -83,6 +83,7 @@ class SystemFactory : public QObject {
// Tries to download list with new updates. // Tries to download list with new updates.
QPair<UpdateInfo, QNetworkReply::NetworkError> checkForUpdates(); QPair<UpdateInfo, QNetworkReply::NetworkError> checkForUpdates();
// Checks if update is newer than current application version.
static bool isUpdateNewer(const QString &update_version); static bool isUpdateNewer(const QString &update_version);
public slots: public slots:

View File

@ -132,6 +132,8 @@ class WebBrowser : public TabContent {
void onTitleChanged(const QString &new_title); void onTitleChanged(const QString &new_title);
void onIconChanged(); void onIconChanged();
// User selected any feed from website to add to reader.
// This copies feed link to clipboard and triggers "add feed" dialog.
void addFeedFromWebsite(const QString &feed_link); void addFeedFromWebsite(const QString &feed_link);
signals: signals:

View File

@ -74,6 +74,7 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame,
QString scheme = request.url().scheme(); QString scheme = request.url().scheme();
if (scheme == "mailto" || scheme == "ftp") { if (scheme == "mailto" || scheme == "ftp") {
qWarning("Received request with scheme '%s', blocking it.", qPrintable(scheme));
return false; return false;
} }
@ -85,6 +86,5 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame,
} }
qDebug("Accepting request '%s'.", qPrintable(request.url().toString())); qDebug("Accepting request '%s'.", qPrintable(request.url().toString()));
return QWebPage::acceptNavigationRequest(frame, request, type); return QWebPage::acceptNavigationRequest(frame, request, type);
} }

View File

@ -66,12 +66,11 @@ class WebView : public QWebView {
void openImageInNewTab(); void openImageInNewTab();
void searchTextViaGoogle(); void searchTextViaGoogle();
void saveCurrentPageToFile(); void saveCurrentPageToFile();
void printCurrentPage();
// Provides custom context menu. // Provides custom context menu.
void popupContextMenu(const QPoint &pos); void popupContextMenu(const QPoint &pos);
void printCurrentPage();
private slots: private slots:
void downloadLink(const QNetworkRequest &request); void downloadLink(const QNetworkRequest &request);