From 2250b9aa478a6a227fd80d0fb3f7bfbd9b0ebb39 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 26 May 2018 22:41:59 +0200 Subject: [PATCH] Ensure MediaFileInfo isn't destroyed before concurrent operation finishes --- CMakeLists.txt | 2 +- gui/mainwindow.cpp | 10 +++++++++- gui/tageditorwidget.cpp | 36 +++++++++++++++++++----------------- gui/tageditorwidget.h | 10 ++++++---- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85cf592..fd66869 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 13d8dcf..3d740cd 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -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(); diff --git a/gui/tageditorwidget.cpp b/gui/tageditorwidget.cpp index 5aefbc0..107b7c1 100644 --- a/gui/tageditorwidget.cpp +++ b/gui/tageditorwidget.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -51,9 +52,11 @@ #include #include +#include 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 &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; } diff --git a/gui/tageditorwidget.h b/gui/tageditorwidget.h index 3ab5312..3d0715c 100644 --- a/gui/tageditorwidget.h +++ b/gui/tageditorwidget.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -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 ¤tPath() const; const QString ¤tDir() const; TagParser::MediaFileInfo &fileInfo(); @@ -153,18 +155,18 @@ private: // status TagParser::Diagnostics m_diag; TagParser::Diagnostics m_diagReparsing; + QFuture 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(); } /*!