Ensure MediaFileInfo isn't destroyed before concurrent operation finishes

This commit is contained in:
Martchus 2018-05-26 22:41:59 +02:00
parent eec19fd710
commit 2250b9aa47
4 changed files with 35 additions and 23 deletions

View File

@ -12,7 +12,7 @@ set(META_GUI_OPTIONAL true)
set(META_JS_SRC_DIR renamingutility)
set(META_VERSION_MAJOR 3)
set(META_VERSION_MINOR 1)
set(META_VERSION_PATCH 0)
set(META_VERSION_PATCH 1)
# add project files
set(HEADER_FILES

View File

@ -21,6 +21,7 @@
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/io/path.h>
#include <QCoreApplication>
#include <QFileDialog>
#include <QFileSystemModel>
#include <QMessageBox>
@ -54,7 +55,7 @@ enum LoadingResult : char { ParsingSuccessful, FatalParsingError, IoError };
*/
bool MainWindow::fileOperationOngoing() const
{
return m_ui->tagEditorWidget->fileOperationOngoing();
return m_ui->tagEditorWidget->isFileOperationOngoing();
}
/*!
@ -225,6 +226,13 @@ bool MainWindow::event(QEvent *event)
auto &settings = Settings::values();
switch (event->type()) {
case QEvent::Close:
if (m_ui->tagEditorWidget->isFileOperationOngoing()) {
event->ignore();
static const auto warning(tr("Unable to close while the file operation is still ongoing."));
QMessageBox::warning(this, QCoreApplication::applicationName(), warning);
return true;
}
// save settings
settings.mainWindow.geometry = saveGeometry();
settings.mainWindow.state = saveState();

View File

@ -28,6 +28,7 @@
#include <qtutilities/widgets/clearlineedit.h>
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/io/ansiescapecodes.h>
#include <c++utilities/io/catchiofailure.h>
#include <c++utilities/io/path.h>
@ -51,9 +52,11 @@
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
using namespace std::placeholders;
using namespace EscapeCodes;
using namespace Utility;
using namespace Dialogs;
using namespace Widgets;
@ -89,7 +92,6 @@ TagEditorWidget::TagEditorWidget(QWidget *parent)
, m_nextFileAfterSaving(false)
, m_makingResultsAvailable(false)
, m_abortClicked(false)
, m_fileOperationOngoing(false)
{
// setup UI
m_ui->setupUi(this);
@ -167,6 +169,10 @@ TagEditorWidget::TagEditorWidget(QWidget *parent)
*/
TagEditorWidget::~TagEditorWidget()
{
if (isFileOperationOngoing()) {
cout << Phrases::Warning << "Waiting for the ongoing file operation to finish ..." << Phrases::EndFlush;
m_ongoingFileOperation.waitForFinished();
}
}
/*!
@ -772,7 +778,7 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
if (!forceRefresh && sameFile) {
return true;
}
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage(tr("Unable to load the selected file \"%1\" because the current process hasn't finished yet.").arg(path));
return false;
}
@ -835,9 +841,8 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
}
QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result));
};
m_fileOperationOngoing = true;
// perform the operation concurrently
QtConcurrent::run(startThread);
m_ongoingFileOperation = QtConcurrent::run(startThread);
// inform user
static const auto statusMsg(tr("The file is beeing parsed ..."));
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
@ -852,7 +857,7 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
*/
bool TagEditorWidget::reparseFile()
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage(tr("Unable to reload the file because the current process hasn't finished yet."));
return false;
}
@ -871,7 +876,6 @@ bool TagEditorWidget::reparseFile()
*/
void TagEditorWidget::showFile(char result)
{
m_fileOperationOngoing = false;
if (result == IoError) {
// update status
updateFileStatusStatus();
@ -990,7 +994,7 @@ void TagEditorWidget::saveAndShowNextFile()
*/
bool TagEditorWidget::applyEntriesAndSaveChangings()
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
static const QString statusMsg(tr("Unable to apply the entered tags to the file because the current process hasn't finished yet."));
emit statusMessage(statusMsg);
return false;
@ -1032,7 +1036,7 @@ bool TagEditorWidget::applyEntriesAndSaveChangings()
*/
bool TagEditorWidget::deleteAllTagsAndSave()
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
static const QString statusMsg(tr("Unable to delete all tags from the file because the current process hasn't been finished yet."));
emit statusMessage(statusMsg);
return false;
@ -1098,7 +1102,7 @@ bool TagEditorWidget::deleteAllTagsAndSave()
*/
bool TagEditorWidget::startSaving()
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
static const QString errorMsg(tr("Unable to start saving process because there an other process hasn't finished yet."));
emit statusMessage(errorMsg);
QMessageBox::warning(this, QCoreApplication::applicationName(), errorMsg);
@ -1160,9 +1164,8 @@ bool TagEditorWidget::startSaving()
}
QMetaObject::invokeMethod(this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError));
};
m_fileOperationOngoing = true;
// use another thread to perform the operation
QtConcurrent::run(startThread);
m_ongoingFileOperation = QtConcurrent::run(startThread);
return true;
}
@ -1176,7 +1179,6 @@ bool TagEditorWidget::startSaving()
*/
void TagEditorWidget::showSavingResult(bool processingError, bool ioError)
{
m_fileOperationOngoing = false;
m_ui->abortButton->setHidden(true);
m_ui->makingNotificationWidget->setNotificationType(NotificationType::TaskComplete);
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
@ -1277,7 +1279,7 @@ void TagEditorWidget::fileChangedOnDisk(const QString &path)
*/
void TagEditorWidget::closeFile()
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage("Unable to close the file because the current process hasn't been finished yet.");
return;
}
@ -1293,7 +1295,7 @@ void TagEditorWidget::closeFile()
bool TagEditorWidget::handleFileInfoUnavailable()
{
if (fileOperationOngoing()) {
if (isFileOperationOngoing()) {
emit statusMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
return true;
}
@ -1419,7 +1421,7 @@ void TagEditorWidget::applySettingsFromDialog()
*/
void TagEditorWidget::addTag(const function<TagParser::Tag *(TagParser::MediaFileInfo &)> &createTag)
{
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage("Unable to add a tag because the current process hasn't been finished yet.");
return;
}
@ -1456,7 +1458,7 @@ void TagEditorWidget::removeTag(Tag *tag)
if (!tag) {
return;
}
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage(tr("Unable to remove the tag because the current process hasn't been finished yet."));
return;
}
@ -1520,7 +1522,7 @@ void TagEditorWidget::changeTarget(Tag *tag)
if (!tag) {
return;
}
if (m_fileOperationOngoing) {
if (isFileOperationOngoing()) {
emit statusMessage(tr("Unable to change the target because the current process hasn't been finished yet."));
return;
}

View File

@ -8,6 +8,7 @@
#include <tagparser/mediafileinfo.h>
#include <QByteArray>
#include <QFuture>
#include <QWidget>
#include <functional>
@ -39,13 +40,14 @@ class TagEditorWidget : public QWidget {
Q_PROPERTY(QByteArray fileInfoHtml READ fileInfoHtml)
Q_PROPERTY(bool fileNameVisible READ isFileNameVisible WRITE setFileNameVisible)
Q_PROPERTY(bool buttonsVisible READ areButtonsVisible WRITE setButtonVisible)
Q_PROPERTY(bool fileOperationOngoing READ isFileOperationOngoing)
public:
explicit TagEditorWidget(QWidget *parent = nullptr);
~TagEditorWidget();
public:
bool fileOperationOngoing() const;
bool isFileOperationOngoing() const;
const QString &currentPath() const;
const QString &currentDir() const;
TagParser::MediaFileInfo &fileInfo();
@ -153,18 +155,18 @@ private:
// status
TagParser::Diagnostics m_diag;
TagParser::Diagnostics m_diagReparsing;
QFuture<void> m_ongoingFileOperation;
bool m_nextFileAfterSaving;
bool m_makingResultsAvailable;
bool m_abortClicked;
bool m_fileOperationOngoing;
};
/*!
* \brief Returns the mutex which is internally used for thread-synchronization.
*/
inline bool TagEditorWidget::fileOperationOngoing() const
inline bool TagEditorWidget::isFileOperationOngoing() const
{
return m_fileOperationOngoing;
return m_ongoingFileOperation.isRunning();
}
/*!