use Qt Concurrent instead of pthread
This commit is contained in:
parent
70b94fa5fa
commit
eaea2e2cda
|
@ -178,7 +178,8 @@ find_package(Qt5Core REQUIRED)
|
||||||
find_package(Qt5Gui REQUIRED)
|
find_package(Qt5Gui REQUIRED)
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
find_package(Qt5LinguistTools REQUIRED)
|
find_package(Qt5LinguistTools REQUIRED)
|
||||||
find_package(Qt5Script REQUIRED)
|
find_package(Qt5Concurrent REQUIRED)
|
||||||
|
find_package(Qt5Network REQUIRED)
|
||||||
# select Qt module providing JavaScript (either Qt Script or Qt Qml)
|
# select Qt module providing JavaScript (either Qt Script or Qt Qml)
|
||||||
if(${JS_PROVIDER} STREQUAL "auto")
|
if(${JS_PROVIDER} STREQUAL "auto")
|
||||||
find_package(Qt5Script)
|
find_package(Qt5Script)
|
||||||
|
@ -258,7 +259,7 @@ add_custom_target(translations ALL DEPENDS ${QM_FILES})
|
||||||
|
|
||||||
# executable and linking
|
# executable and linking
|
||||||
add_executable(${META_PROJECT_NAME} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_HEADER_FILES} ${WIDGETS_SRC_FILES} ${WIDGETS_UI_FILES} ${QM_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH})
|
add_executable(${META_PROJECT_NAME} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_HEADER_FILES} ${WIDGETS_SRC_FILES} ${WIDGETS_UI_FILES} ${QM_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH})
|
||||||
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser pthread Qt5::Core Qt5::Widgets ${JS_PROVIDER} ${WEBVIEW_PROVIDER})
|
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser Qt5::Core Qt5::Widgets Qt5::Concurrent Qt5::Network ${JS_PROVIDER} ${WEBVIEW_PROVIDER})
|
||||||
set_target_properties(${META_PROJECT_NAME} PROPERTIES
|
set_target_properties(${META_PROJECT_NAME} PROPERTIES
|
||||||
CXX_STANDARD 11
|
CXX_STANDARD 11
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <qtutilities/aboutdialog/aboutdialog.h>
|
#include <qtutilities/aboutdialog/aboutdialog.h>
|
||||||
#include <qtutilities/misc/dialogutils.h>
|
#include <qtutilities/misc/dialogutils.h>
|
||||||
#include <qtutilities/misc/desktoputils.h>
|
#include <qtutilities/misc/desktoputils.h>
|
||||||
|
#include <qtutilities/misc/trylocker.h>
|
||||||
|
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
#include <c++utilities/io/path.h>
|
#include <c++utilities/io/path.h>
|
||||||
|
@ -30,6 +31,7 @@ using namespace Utility;
|
||||||
using namespace Media;
|
using namespace Media;
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
using namespace Widgets;
|
using namespace Widgets;
|
||||||
|
using namespace ThreadingUtils;
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ enum LoadingResult : char
|
||||||
/*!
|
/*!
|
||||||
* \brief Shortcut to access file operation mutex of TagEditorWidget.
|
* \brief Shortcut to access file operation mutex of TagEditorWidget.
|
||||||
*/
|
*/
|
||||||
std::mutex &MainWindow::fileOperationMutex()
|
QMutex &MainWindow::fileOperationMutex()
|
||||||
{
|
{
|
||||||
return m_ui->tagEditorWidget->fileOperationMutex();
|
return m_ui->tagEditorWidget->fileOperationMutex();
|
||||||
}
|
}
|
||||||
|
@ -436,28 +438,28 @@ void MainWindow::showOpenFileDlg()
|
||||||
*/
|
*/
|
||||||
void MainWindow::saveFileInformation()
|
void MainWindow::saveFileInformation()
|
||||||
{
|
{
|
||||||
if(!fileOperationMutex().try_lock()) {
|
TryLocker<> locker(fileOperationMutex());
|
||||||
m_ui->statusBar->showMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
|
if(locker) {
|
||||||
return;
|
if(fileInfo().isOpen() && m_ui->tagEditorWidget->fileInfoHtml().size()) {
|
||||||
}
|
const QString path = QFileDialog::getSaveFileName(this, windowTitle());
|
||||||
lock_guard<mutex> guard(fileOperationMutex(), adopt_lock);
|
if(!path.isEmpty()) {
|
||||||
if(fileInfo().isOpen() && m_ui->tagEditorWidget->fileInfoHtml().size()) {
|
QFile file(path);
|
||||||
const QString path = QFileDialog::getSaveFileName(this, windowTitle());
|
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
if(!path.isEmpty()) {
|
QTextStream stream(&file);
|
||||||
QFile file(path);
|
stream << m_ui->tagEditorWidget->fileInfoHtml();
|
||||||
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
file.close();
|
||||||
QTextStream stream(&file);
|
if(file.error() != QFileDevice::NoError) {
|
||||||
stream << m_ui->tagEditorWidget->fileInfoHtml();
|
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to write to file.\n%1").arg(file.errorString()));
|
||||||
file.close();
|
}
|
||||||
if(file.error() != QFileDevice::NoError) {
|
} else {
|
||||||
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to write to file.\n%1").arg(file.errorString()));
|
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to open file."));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to open file."));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
QMessageBox::information(this, QApplication::applicationName(), tr("No file information available."));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(this, QApplication::applicationName(), tr("No file information available."));
|
m_ui->statusBar->showMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,9 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QFileSystemModel)
|
QT_FORWARD_DECLARE_CLASS(QFileSystemModel)
|
||||||
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QMutex)
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
DECLARE_ENUM(TagType, unsigned int)
|
DECLARE_ENUM(TagType, unsigned int)
|
||||||
|
@ -73,7 +72,7 @@ private slots:
|
||||||
void showDbQueryWidget();
|
void showDbQueryWidget();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex &fileOperationMutex();
|
QMutex &fileOperationMutex();
|
||||||
Media::MediaFileInfo &fileInfo();
|
Media::MediaFileInfo &fileInfo();
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
using namespace RenamingUtility;
|
using namespace RenamingUtility;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <tagparser/matroska/matroskatag.h>
|
#include <tagparser/matroska/matroskatag.h>
|
||||||
|
|
||||||
#include <qtutilities/misc/dialogutils.h>
|
#include <qtutilities/misc/dialogutils.h>
|
||||||
|
#include <qtutilities/misc/trylocker.h>
|
||||||
|
#include <qtutilities/misc/adoptlocker.h>
|
||||||
#include <qtutilities/widgets/clearlineedit.h>
|
#include <qtutilities/widgets/clearlineedit.h>
|
||||||
|
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
@ -35,6 +37,8 @@
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#if defined(TAGEDITOR_NO_WEBVIEW)
|
#if defined(TAGEDITOR_NO_WEBVIEW)
|
||||||
# error "not supported (yet)."
|
# error "not supported (yet)."
|
||||||
#elif defined(TAGEDITOR_USE_WEBENGINE)
|
#elif defined(TAGEDITOR_USE_WEBENGINE)
|
||||||
|
@ -43,7 +47,6 @@
|
||||||
# include <QWebView>
|
# include <QWebView>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -51,6 +54,7 @@ using namespace std;
|
||||||
using namespace Utility;
|
using namespace Utility;
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
using namespace Widgets;
|
using namespace Widgets;
|
||||||
|
using namespace ThreadingUtils;
|
||||||
using namespace Media;
|
using namespace Media;
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
@ -602,68 +606,67 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
if(!forceRefresh && sameFile) {
|
if(!forceRefresh && sameFile) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(fileOperationMutex());
|
||||||
emit statusMessage(tr("Unable to load the selected file \"%1\" because the current process hasn't finished yet.").arg(path));
|
if(locker) {
|
||||||
return false;
|
// clear previous results and status
|
||||||
}
|
m_tags.clear();
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
m_fileInfo.clearParsingResults();
|
||||||
// clear previous results and status
|
m_fileInfo.invalidateStatus();
|
||||||
m_tags.clear();
|
m_fileInfo.invalidateNotifications();
|
||||||
m_fileInfo.clearParsingResults();
|
if(!sameFile) {
|
||||||
m_fileInfo.invalidateStatus();
|
// close last file if possibly open
|
||||||
m_fileInfo.invalidateNotifications();
|
m_fileInfo.close();
|
||||||
if(!sameFile) {
|
// set path of file info
|
||||||
// close last file if possibly open
|
m_currentPath = path;
|
||||||
m_fileInfo.close();
|
m_fileInfo.setPath(path.toLocal8Bit().data());
|
||||||
// set path of file info
|
// update directory
|
||||||
m_currentPath = path;
|
m_lastDir = m_currentDir;
|
||||||
m_fileInfo.setPath(path.toLocal8Bit().data());
|
m_currentDir = QString::fromLocal8Bit(m_fileInfo.containingDirectory().c_str());
|
||||||
// update directory
|
|
||||||
m_lastDir = m_currentDir;
|
|
||||||
m_currentDir = QString::fromLocal8Bit(m_fileInfo.containingDirectory().c_str());
|
|
||||||
}
|
|
||||||
// update availability of making results
|
|
||||||
m_makingResultsAvailable &= sameFile;
|
|
||||||
if(!m_makingResultsAvailable) {
|
|
||||||
m_originalNotifications.clear();
|
|
||||||
}
|
|
||||||
// show filename
|
|
||||||
m_ui->fileNameLabel->setText(QString::fromLocal8Bit(m_fileInfo.fileName().c_str()));
|
|
||||||
// define function to parse the file
|
|
||||||
auto startThread = [this, sameFile] {
|
|
||||||
m_fileOperationMutex.lock();
|
|
||||||
char result;
|
|
||||||
try {
|
|
||||||
if(sameFile) {
|
|
||||||
m_fileInfo.reopen();
|
|
||||||
}
|
|
||||||
m_fileInfo.setForceFullParse(Settings::forceFullParse());
|
|
||||||
m_fileInfo.parseEverything();
|
|
||||||
result = ParsingSuccessful;
|
|
||||||
} catch(Failure &) {
|
|
||||||
// the file has been opened; parsing notifications will be shown in the info box
|
|
||||||
result = FatalParsingError;
|
|
||||||
} catch(ios_base::failure &) {
|
|
||||||
// the file could not be opened because an IO error occured
|
|
||||||
m_fileInfo.close(); // ensure file is closed
|
|
||||||
result = IoError;
|
|
||||||
}
|
}
|
||||||
|
// update availability of making results
|
||||||
|
m_makingResultsAvailable &= sameFile;
|
||||||
|
if(!m_makingResultsAvailable) {
|
||||||
|
m_originalNotifications.clear();
|
||||||
|
}
|
||||||
|
// show filename
|
||||||
|
m_ui->fileNameLabel->setText(QString::fromLocal8Bit(m_fileInfo.fileName().c_str()));
|
||||||
|
// define function to parse the file
|
||||||
|
auto startThread = [this, sameFile] {
|
||||||
|
m_fileOperationMutex.lock();
|
||||||
|
char result;
|
||||||
|
try {
|
||||||
|
if(sameFile) {
|
||||||
|
m_fileInfo.reopen();
|
||||||
|
}
|
||||||
|
m_fileInfo.setForceFullParse(Settings::forceFullParse());
|
||||||
|
m_fileInfo.parseEverything();
|
||||||
|
result = ParsingSuccessful;
|
||||||
|
} catch(const Failure &) {
|
||||||
|
// the file has been opened; parsing notifications will be shown in the info box
|
||||||
|
result = FatalParsingError;
|
||||||
|
} catch(const ios_base::failure &) {
|
||||||
|
// the file could not be opened because an IO error occured
|
||||||
|
m_fileInfo.close(); // ensure file is closed
|
||||||
|
result = IoError;
|
||||||
|
}
|
||||||
|
m_fileInfo.unregisterAllCallbacks();
|
||||||
|
QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result));
|
||||||
|
// showFile() will unlock the mutex!
|
||||||
|
};
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
m_fileInfo.unregisterAllCallbacks();
|
||||||
QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result));
|
// perform the operation concurrently
|
||||||
// showFile() will unlock the mutex!
|
QtConcurrent::run(startThread);
|
||||||
};
|
// inform user
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
static const QString statusMsg(tr("The file is beeing parsed ..."));
|
||||||
//m_fileInfo.registerCallback(showProgress); can't show progress yet
|
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
|
||||||
// use another thread to perform the operation
|
m_ui->parsingNotificationWidget->setText(statusMsg);
|
||||||
std::thread thr(startThread);
|
m_ui->parsingNotificationWidget->setVisible(true); // ensure widget is visible!
|
||||||
thr.detach();
|
emit statusMessage(statusMsg);
|
||||||
// inform user
|
return true;
|
||||||
static const QString statusMsg(tr("The file is beeing parsed ..."));
|
} else {
|
||||||
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
|
emit statusMessage(tr("Unable to load the selected file \"%1\" because the current process hasn't finished yet.").arg(path));
|
||||||
m_ui->parsingNotificationWidget->setText(statusMsg);
|
}
|
||||||
m_ui->parsingNotificationWidget->setVisible(true); // ensure widget is visible!
|
return false;
|
||||||
emit statusMessage(statusMsg);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -671,14 +674,15 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
*/
|
*/
|
||||||
bool TagEditorWidget::reparseFile()
|
bool TagEditorWidget::reparseFile()
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
|
||||||
emit statusMessage(tr("Unable to reload the file because the current process hasn't finished yet."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
if(!m_fileInfo.isOpen() || m_currentPath.isEmpty()) {
|
if(locker) {
|
||||||
QMessageBox::warning(this, windowTitle(), tr("Currently is not file opened."));
|
if(!m_fileInfo.isOpen() || m_currentPath.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, windowTitle(), tr("Currently is not file opened."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit statusMessage(tr("Unable to reload the file because the current process hasn't finished yet."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -694,7 +698,7 @@ bool TagEditorWidget::reparseFile()
|
||||||
*/
|
*/
|
||||||
void TagEditorWidget::showFile(char result)
|
void TagEditorWidget::showFile(char result)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
AdoptLocker<> locker(m_fileOperationMutex);
|
||||||
if(result == IoError) {
|
if(result == IoError) {
|
||||||
// update status
|
// update status
|
||||||
updateFileStatusStatus();
|
updateFileStatusStatus();
|
||||||
|
@ -787,40 +791,41 @@ void TagEditorWidget::saveAndShowNextFile()
|
||||||
bool TagEditorWidget::applyEntriesAndSaveChangings()
|
bool TagEditorWidget::applyEntriesAndSaveChangings()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
|
if(locker) {
|
||||||
|
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Information);
|
||||||
|
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
|
||||||
|
m_ui->makingNotificationWidget->setHidden(false);
|
||||||
|
m_makingResultsAvailable = true;
|
||||||
|
if(m_fileInfo.isOpen()) {
|
||||||
|
// apply titles
|
||||||
|
if(AbstractContainer *container = m_fileInfo.container()) {
|
||||||
|
if(container->supportsTitle()) {
|
||||||
|
QLayout *docTitleLayout = m_ui->docTitleWidget->layout();
|
||||||
|
for(int i = 0, count = min<int>(docTitleLayout->count() - 1, container->segmentCount()); i < count; ++i) {
|
||||||
|
container->setTitle(static_cast<ClearLineEdit *>(docTitleLayout->itemAt(i + 1)->widget())->text().toUtf8().data(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// apply all tags
|
||||||
|
foreachTagEdit([] (TagEdit *edit) {edit->apply();});
|
||||||
|
static const QString statusMsg(tr("Saving tags ..."));
|
||||||
|
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::None);
|
||||||
|
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Progress);
|
||||||
|
m_ui->makingNotificationWidget->setText(statusMsg);
|
||||||
|
emit statusMessage(statusMsg);
|
||||||
|
} else {
|
||||||
|
QString statusMsg(tr("No file has been opened."));
|
||||||
|
m_ui->makingNotificationWidget->setText(statusMsg);
|
||||||
|
QMessageBox::warning(this, QApplication::applicationName(), statusMsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
static const QString statusMsg(tr("Unable to apply the entered tags to the file because the current process hasn't finished yet."));
|
static const QString statusMsg(tr("Unable to apply the entered tags to the file because the current process hasn't finished yet."));
|
||||||
m_ui->makingNotificationWidget->setText(statusMsg);
|
m_ui->makingNotificationWidget->setText(statusMsg);
|
||||||
emit statusMessage(statusMsg);
|
emit statusMessage(statusMsg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
|
||||||
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Information);
|
|
||||||
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
|
|
||||||
m_ui->makingNotificationWidget->setHidden(false);
|
|
||||||
m_makingResultsAvailable = true;
|
|
||||||
if(m_fileInfo.isOpen()) {
|
|
||||||
// apply titles
|
|
||||||
if(AbstractContainer *container = m_fileInfo.container()) {
|
|
||||||
if(container->supportsTitle()) {
|
|
||||||
QLayout *docTitleLayout = m_ui->docTitleWidget->layout();
|
|
||||||
for(int i = 0, count = min<int>(docTitleLayout->count() - 1, container->segmentCount()); i < count; ++i) {
|
|
||||||
container->setTitle(static_cast<ClearLineEdit *>(docTitleLayout->itemAt(i + 1)->widget())->text().toUtf8().data(), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// apply all tags
|
|
||||||
foreachTagEdit([] (TagEdit *edit) {edit->apply();});
|
|
||||||
static const QString statusMsg(tr("Saving tags ..."));
|
|
||||||
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::None);
|
|
||||||
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Progress);
|
|
||||||
m_ui->makingNotificationWidget->setText(statusMsg);
|
|
||||||
emit statusMessage(statusMsg);
|
|
||||||
} else {
|
|
||||||
QString statusMsg = tr("No file has been opened.");
|
|
||||||
m_ui->makingNotificationWidget->setText(statusMsg);
|
|
||||||
QMessageBox::warning(this, QApplication::applicationName(), statusMsg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return startSaving();
|
return startSaving();
|
||||||
}
|
}
|
||||||
|
@ -832,53 +837,54 @@ bool TagEditorWidget::applyEntriesAndSaveChangings()
|
||||||
bool TagEditorWidget::deleteAllTagsAndSave()
|
bool TagEditorWidget::deleteAllTagsAndSave()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
static const QString statusMsg(tr("Unable to delete all tags from the file because the current process hasn't been finished yet."));
|
if(locker) {
|
||||||
m_ui->makingNotificationWidget->setText(statusMsg);
|
if(Settings::askBeforeDeleting()) {
|
||||||
emit statusMessage(statusMsg);
|
QMessageBox msgBox(this);
|
||||||
return false;
|
msgBox.setText(tr("Do you really want to delete all tags from the file?"));
|
||||||
}
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
if(Settings::askBeforeDeleting()) {
|
msgBox.setDefaultButton(QMessageBox::No);
|
||||||
QMessageBox msgBox(this);
|
|
||||||
msgBox.setText(tr("Do you really want to delete all tags from the file?"));
|
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
||||||
msgBox.setDefaultButton(QMessageBox::No);
|
|
||||||
#if QT_VERSION >= 0x050200
|
#if QT_VERSION >= 0x050200
|
||||||
auto *checkBox = new QCheckBox(&msgBox);
|
auto *checkBox = new QCheckBox(&msgBox);
|
||||||
checkBox->setText(tr("don't show this message again"));
|
checkBox->setText(tr("don't show this message again"));
|
||||||
msgBox.setCheckBox(checkBox);
|
msgBox.setCheckBox(checkBox);
|
||||||
#endif
|
#endif
|
||||||
int res = msgBox.exec();
|
int res = msgBox.exec();
|
||||||
#if QT_VERSION >= 0x050200
|
#if QT_VERSION >= 0x050200
|
||||||
if(checkBox->isChecked()) {
|
if(checkBox->isChecked()) {
|
||||||
Settings::askBeforeDeleting() = false;
|
Settings::askBeforeDeleting() = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(res != QMessageBox::Yes) {
|
if(res != QMessageBox::Yes) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
|
||||||
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
|
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Information);
|
||||||
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Information);
|
m_ui->makingNotificationWidget->setHidden(false);
|
||||||
m_ui->makingNotificationWidget->setHidden(false);
|
m_makingResultsAvailable = true;
|
||||||
m_makingResultsAvailable = true;
|
if(m_fileInfo.isOpen()) {
|
||||||
if(m_fileInfo.isOpen()) {
|
if(m_fileInfo.hasAnyTag()) {
|
||||||
if(m_fileInfo.hasAnyTag()) {
|
foreachTagEdit([] (TagEdit *edit) {edit->clear();});
|
||||||
foreachTagEdit([] (TagEdit *edit) {edit->clear();});
|
m_fileInfo.removeAllTags();
|
||||||
m_fileInfo.removeAllTags();
|
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::None);
|
||||||
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::None);
|
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Progress);
|
||||||
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Progress);
|
static const QString statusMsg(tr("Deleting all tags ..."));
|
||||||
static const QString statusMsg(tr("Deleting all tags ..."));
|
m_ui->makingNotificationWidget->setText(statusMsg);
|
||||||
m_ui->makingNotificationWidget->setText(statusMsg);
|
emit statusMessage(statusMsg);
|
||||||
emit statusMessage(statusMsg);
|
} else {
|
||||||
|
m_ui->makingNotificationWidget->setText(tr("The selected file stores no tag (at least no supported), so there is nothing to delete."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_ui->makingNotificationWidget->setText(tr("The selected file stores no tag (at least no supported), so there is nothing to delete."));
|
m_ui->makingNotificationWidget->setText(tr("No file has been opened, so no tags can be deleted."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_ui->makingNotificationWidget->setText(tr("No file has been opened, so no tags can be deleted."));
|
static const QString statusMsg(tr("Unable to delete all tags from the file because the current process hasn't been finished yet."));
|
||||||
|
m_ui->makingNotificationWidget->setText(statusMsg);
|
||||||
|
emit statusMessage(statusMsg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,61 +902,61 @@ bool TagEditorWidget::deleteAllTagsAndSave()
|
||||||
*/
|
*/
|
||||||
bool TagEditorWidget::startSaving()
|
bool TagEditorWidget::startSaving()
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
|
if(locker) {
|
||||||
|
// tags might get invalidated
|
||||||
|
m_tags.clear();
|
||||||
|
foreachTagEdit([] (TagEdit *edit) { edit->setTag(nullptr, false); });
|
||||||
|
// show abort button
|
||||||
|
m_ui->abortButton->setHidden(false);
|
||||||
|
m_ui->abortButton->setEnabled(true);
|
||||||
|
m_abortClicked = false;
|
||||||
|
// remove current path from file watcher
|
||||||
|
m_fileWatcher->removePath(m_currentPath);
|
||||||
|
// use current configuration
|
||||||
|
m_fileInfo.setForceRewrite(Settings::forceRewrite());
|
||||||
|
m_fileInfo.setTagPosition(Settings::preferredTagPosition());
|
||||||
|
m_fileInfo.setForceTagPosition(Settings::forceTagPosition());
|
||||||
|
m_fileInfo.setIndexPosition(Settings::preferredIndexPosition());
|
||||||
|
m_fileInfo.setForceIndexPosition(Settings::forceIndexPosition());
|
||||||
|
m_fileInfo.setMinPadding(Settings::minPadding());
|
||||||
|
m_fileInfo.setMaxPadding(Settings::maxPadding());
|
||||||
|
m_fileInfo.setPreferredPadding(Settings::preferredPadding());
|
||||||
|
// define functions to show the saving progress and to actually applying the changes
|
||||||
|
auto showProgress = [this] (StatusProvider &sender) -> void {
|
||||||
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setPercentage", Qt::QueuedConnection, Q_ARG(int, static_cast<int>(sender.currentPercentage() * 100.0)));
|
||||||
|
if(m_abortClicked) {
|
||||||
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, tr("Cancelling ...")));
|
||||||
|
m_fileInfo.tryToAbort();
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(sender.currentStatus())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto startThread = [this] {
|
||||||
|
m_fileOperationMutex.lock();
|
||||||
|
bool processingError = false, ioError = false;
|
||||||
|
try {
|
||||||
|
m_fileInfo.applyChanges();
|
||||||
|
} catch(const Failure &) {
|
||||||
|
processingError = true;
|
||||||
|
} catch(const ios_base::failure &) {
|
||||||
|
ioError = true;
|
||||||
|
}
|
||||||
|
m_fileInfo.unregisterAllCallbacks();
|
||||||
|
QMetaObject::invokeMethod(this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError));
|
||||||
|
// showSavingResult() will unlock the mutex!
|
||||||
|
};
|
||||||
|
m_fileInfo.unregisterAllCallbacks();
|
||||||
|
m_fileInfo.registerCallback(showProgress);
|
||||||
|
// use another thread to perform the operation
|
||||||
|
QtConcurrent::run(startThread);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
static const QString errorMsg(tr("Unable to start saving process because there an other process hasn't finished yet."));
|
static const QString errorMsg(tr("Unable to start saving process because there an other process hasn't finished yet."));
|
||||||
emit statusMessage(errorMsg);
|
emit statusMessage(errorMsg);
|
||||||
QMessageBox::warning(this, QApplication::applicationName(), errorMsg);
|
QMessageBox::warning(this, QApplication::applicationName(), errorMsg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
|
||||||
// tags might get invalidated
|
|
||||||
m_tags.clear();
|
|
||||||
foreachTagEdit([] (TagEdit *edit) { edit->setTag(nullptr, false); });
|
|
||||||
// show abort button
|
|
||||||
m_ui->abortButton->setHidden(false);
|
|
||||||
m_ui->abortButton->setEnabled(true);
|
|
||||||
m_abortClicked = false;
|
|
||||||
// remove current path from file watcher
|
|
||||||
m_fileWatcher->removePath(m_currentPath);
|
|
||||||
// use current configuration
|
|
||||||
m_fileInfo.setForceRewrite(Settings::forceRewrite());
|
|
||||||
m_fileInfo.setTagPosition(Settings::preferredTagPosition());
|
|
||||||
m_fileInfo.setForceTagPosition(Settings::forceTagPosition());
|
|
||||||
m_fileInfo.setIndexPosition(Settings::preferredIndexPosition());
|
|
||||||
m_fileInfo.setForceIndexPosition(Settings::forceIndexPosition());
|
|
||||||
m_fileInfo.setMinPadding(Settings::minPadding());
|
|
||||||
m_fileInfo.setMaxPadding(Settings::maxPadding());
|
|
||||||
m_fileInfo.setPreferredPadding(Settings::preferredPadding());
|
|
||||||
// define functions to show the saving progress and to actually applying the changes
|
|
||||||
auto showProgress = [this] (StatusProvider &sender) -> void {
|
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setPercentage", Qt::QueuedConnection, Q_ARG(int, static_cast<int>(sender.currentPercentage() * 100.0)));
|
|
||||||
if(m_abortClicked) {
|
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, tr("Cancelling ...")));
|
|
||||||
m_fileInfo.tryToAbort();
|
|
||||||
} else {
|
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(sender.currentStatus())));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
auto startThread = [this] {
|
|
||||||
m_fileOperationMutex.lock();
|
|
||||||
bool processingError = false, ioError = false;
|
|
||||||
try {
|
|
||||||
m_fileInfo.applyChanges();
|
|
||||||
} catch(const Failure &) {
|
|
||||||
processingError = true;
|
|
||||||
} catch(const ios_base::failure &) {
|
|
||||||
ioError = true;
|
|
||||||
}
|
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
QMetaObject::invokeMethod(this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError));
|
|
||||||
// showSavingResult() will unlock the mutex!
|
|
||||||
};
|
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
m_fileInfo.registerCallback(showProgress);
|
|
||||||
// use another thread to perform the operation
|
|
||||||
std::thread thr(startThread);
|
|
||||||
thr.detach();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1055,18 +1061,18 @@ void TagEditorWidget::fileChangedOnDisk(const QString &path)
|
||||||
*/
|
*/
|
||||||
void TagEditorWidget::closeFile()
|
void TagEditorWidget::closeFile()
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
|
if(locker) {
|
||||||
|
// close file
|
||||||
|
m_fileInfo.close();
|
||||||
|
// remove current path from file watcher
|
||||||
|
m_fileWatcher->removePath(m_currentPath);
|
||||||
|
// update ui
|
||||||
|
emit statusMessage("The file has been closed.");
|
||||||
|
updateFileStatusStatus();
|
||||||
|
} else {
|
||||||
emit statusMessage("Unable to close the file because the current process hasn't been finished yet.");
|
emit statusMessage("Unable to close the file because the current process hasn't been finished yet.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
|
||||||
// close file
|
|
||||||
m_fileInfo.close();
|
|
||||||
// remove current path from file watcher
|
|
||||||
m_fileWatcher->removePath(m_currentPath);
|
|
||||||
// update ui
|
|
||||||
emit statusMessage("The file has been closed.");
|
|
||||||
updateFileStatusStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1119,29 +1125,28 @@ void TagEditorWidget::applySettingsFromDialog()
|
||||||
*/
|
*/
|
||||||
void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)> &createTag)
|
void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)> &createTag)
|
||||||
{
|
{
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
emit statusMessage("Unable to add a tag because the current process hasn't been finished yet.");
|
if(locker) {
|
||||||
return;
|
if(!m_fileInfo.isOpen()) {
|
||||||
}
|
emit statusMessage("Unable to add a tag because no file is opened.");
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
return;
|
||||||
if(!m_fileInfo.isOpen()) {
|
}
|
||||||
emit statusMessage("Unable to add a tag because no file is opened.");
|
if(Tag *tag = createTag(m_fileInfo)) {
|
||||||
return;
|
if(std::find(m_tags.cbegin(), m_tags.cend(), tag) == m_tags.cend()) {
|
||||||
}
|
m_tags.push_back(tag);
|
||||||
if(Tag *tag = createTag(m_fileInfo)) {
|
updateTagEditsAndAttachmentEdits(true, m_tags.size() > 1 ? PreviousValueHandling::Keep : PreviousValueHandling::Auto);
|
||||||
if(std::find(m_tags.cbegin(), m_tags.cend(), tag) == m_tags.cend()) {
|
updateTagSelectionComboBox();
|
||||||
m_tags.push_back(tag);
|
updateTagManagementMenu();
|
||||||
updateTagEditsAndAttachmentEdits(true, m_tags.size() > 1 ? PreviousValueHandling::Keep : PreviousValueHandling::Auto);
|
updateFileStatusStatus();
|
||||||
updateTagSelectionComboBox();
|
insertTitleFromFilename();
|
||||||
updateTagManagementMenu();
|
} else {
|
||||||
updateFileStatusStatus();
|
QMessageBox::warning(this, windowTitle(), tr("A tag (with the selected target) already exists."));
|
||||||
insertTitleFromFilename();
|
}
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::warning(this, windowTitle(), tr("A tag (with the selected target) already exists."));
|
QMessageBox::warning(this, windowTitle(), tr("The tag can not be created."));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::warning(this, windowTitle(), tr("The tag can not be created."));
|
emit statusMessage("Unable to add a tag because the current process hasn't been finished yet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,52 +1158,52 @@ void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)
|
||||||
void TagEditorWidget::removeTag(Tag *tag)
|
void TagEditorWidget::removeTag(Tag *tag)
|
||||||
{
|
{
|
||||||
if(tag) {
|
if(tag) {
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
emit statusMessage(tr("Unable to remove the tag because the current process hasn't been finished yet."));
|
if(locker) {
|
||||||
return;
|
if(!m_fileInfo.isOpen()) {
|
||||||
}
|
emit statusMessage(tr("Unable to remove the tag because no file is opened."));
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
return;
|
||||||
if(!m_fileInfo.isOpen()) {
|
}
|
||||||
emit statusMessage(tr("Unable to remove the tag because no file is opened."));
|
if(m_fileInfo.isOpen()) {
|
||||||
return;
|
m_fileInfo.removeTag(tag);
|
||||||
}
|
// remove tag from m_tags
|
||||||
if(m_fileInfo.isOpen()) {
|
m_tags.erase(remove(m_tags.begin(), m_tags.end(), tag), m_tags.end());
|
||||||
m_fileInfo.removeTag(tag);
|
// remove tag from all TagEdit widgets
|
||||||
// remove tag from m_tags
|
vector<TagEdit *> toRemove;
|
||||||
m_tags.erase(remove(m_tags.begin(), m_tags.end(), tag), m_tags.end());
|
for(int index = 0, count = m_ui->stackedWidget->count(); index < count; ++index) {
|
||||||
// remove tag from all TagEdit widgets
|
TagEdit *edit = qobject_cast<TagEdit *>(m_ui->stackedWidget->widget(index));
|
||||||
vector<TagEdit *> toRemove;
|
if(edit && edit->tags().contains(tag)) {
|
||||||
for(int index = 0, count = m_ui->stackedWidget->count(); index < count; ++index) {
|
QList<Tag *> tagsOfEdit = edit->tags();
|
||||||
TagEdit *edit = qobject_cast<TagEdit *>(m_ui->stackedWidget->widget(index));
|
tagsOfEdit.removeAll(tag);
|
||||||
if(edit && edit->tags().contains(tag)) {
|
if(tagsOfEdit.empty()) {
|
||||||
QList<Tag *> tagsOfEdit = edit->tags();
|
// no tags left in the edit
|
||||||
tagsOfEdit.removeAll(tag);
|
if(m_tags.empty()) {
|
||||||
if(tagsOfEdit.empty()) {
|
// there are no other tag edits -> just disable the edit
|
||||||
// no tags left in the edit
|
edit->setTag(nullptr, false);
|
||||||
if(m_tags.empty()) {
|
} else {
|
||||||
// there are no other tag edits -> just disable the edit
|
// there are still other tag edits -> remove the edit
|
||||||
edit->setTag(nullptr, false);
|
toRemove.push_back(edit);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// there are still other tag edits -> remove the edit
|
// there are still tags left, reassign remaining tags (keeping the previous values)
|
||||||
toRemove.push_back(edit);
|
edit->setPreviousValueHandling(PreviousValueHandling::Keep);
|
||||||
|
edit->setTags(tagsOfEdit, true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// there are still tags left, reassign remaining tags (keeping the previous values)
|
|
||||||
edit->setPreviousValueHandling(PreviousValueHandling::Keep);
|
|
||||||
edit->setTags(tagsOfEdit, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// remove TagEdit widgets
|
||||||
|
for(TagEdit *edit : toRemove) {
|
||||||
|
m_ui->tagSelectionComboBox->removeItem(m_ui->stackedWidget->indexOf(edit));
|
||||||
|
m_ui->stackedWidget->removeWidget(edit);
|
||||||
|
delete edit;
|
||||||
|
}
|
||||||
|
// update affected widgets
|
||||||
|
updateTagSelectionComboBox();
|
||||||
|
updateTagManagementMenu();
|
||||||
|
updateFileStatusStatus();
|
||||||
}
|
}
|
||||||
// remove TagEdit widgets
|
} else {
|
||||||
for(TagEdit *edit : toRemove) {
|
emit statusMessage(tr("Unable to remove the tag because the current process hasn't been finished yet."));
|
||||||
m_ui->tagSelectionComboBox->removeItem(m_ui->stackedWidget->indexOf(edit));
|
|
||||||
m_ui->stackedWidget->removeWidget(edit);
|
|
||||||
delete edit;
|
|
||||||
}
|
|
||||||
// update affected widgets
|
|
||||||
updateTagSelectionComboBox();
|
|
||||||
updateTagManagementMenu();
|
|
||||||
updateFileStatusStatus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1211,27 +1216,27 @@ void TagEditorWidget::removeTag(Tag *tag)
|
||||||
void TagEditorWidget::changeTarget(Tag *tag)
|
void TagEditorWidget::changeTarget(Tag *tag)
|
||||||
{
|
{
|
||||||
if(tag) {
|
if(tag) {
|
||||||
if(!m_fileOperationMutex.try_lock()) {
|
TryLocker<> locker(m_fileOperationMutex);
|
||||||
emit statusMessage(tr("Unable to change the target because the current process hasn't been finished yet."));
|
if(locker) {
|
||||||
return;
|
if(!m_fileInfo.isOpen()) {
|
||||||
}
|
emit statusMessage(tr("Unable to change the target because no file is opened."));
|
||||||
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
|
return;
|
||||||
if(!m_fileInfo.isOpen()) {
|
|
||||||
emit statusMessage(tr("Unable to change the target because no file is opened."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(m_fileInfo.isOpen()) {
|
|
||||||
if(tag->supportsTarget()) {
|
|
||||||
EnterTargetDialog targetDlg(this);
|
|
||||||
targetDlg.setTarget(tag->target(), &m_fileInfo);
|
|
||||||
if(targetDlg.exec() == QDialog::Accepted) {
|
|
||||||
tag->setTarget(targetDlg.target());
|
|
||||||
updateTagSelectionComboBox();
|
|
||||||
updateTagManagementMenu();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QMessageBox::warning(this, windowTitle(), tr("Can not change the target of the selected tag because the tag does not support targets."));
|
|
||||||
}
|
}
|
||||||
|
if(m_fileInfo.isOpen()) {
|
||||||
|
if(tag->supportsTarget()) {
|
||||||
|
EnterTargetDialog targetDlg(this);
|
||||||
|
targetDlg.setTarget(tag->target(), &m_fileInfo);
|
||||||
|
if(targetDlg.exec() == QDialog::Accepted) {
|
||||||
|
tag->setTarget(targetDlg.target());
|
||||||
|
updateTagSelectionComboBox();
|
||||||
|
updateTagManagementMenu();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, windowTitle(), tr("Can not change the target of the selected tag because the tag does not support targets."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit statusMessage(tr("Unable to change the target because the current process hasn't been finished yet."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#if defined(TAGEDITOR_NO_WEBVIEW)
|
#if defined(TAGEDITOR_NO_WEBVIEW)
|
||||||
|
@ -50,7 +50,7 @@ public:
|
||||||
virtual ~TagEditorWidget();
|
virtual ~TagEditorWidget();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::mutex &fileOperationMutex();
|
QMutex &fileOperationMutex();
|
||||||
const QString ¤tPath() const;
|
const QString ¤tPath() const;
|
||||||
Media::MediaFileInfo &fileInfo();
|
Media::MediaFileInfo &fileInfo();
|
||||||
bool isTagEditShown() const;
|
bool isTagEditShown() const;
|
||||||
|
@ -149,13 +149,13 @@ private:
|
||||||
bool m_makingResultsAvailable;
|
bool m_makingResultsAvailable;
|
||||||
Media::NotificationList m_originalNotifications;
|
Media::NotificationList m_originalNotifications;
|
||||||
bool m_abortClicked;
|
bool m_abortClicked;
|
||||||
std::mutex m_fileOperationMutex;
|
QMutex m_fileOperationMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the mutex which is internally used for thread-synchronization.
|
* \brief Returns the mutex which is internally used for thread-synchronization.
|
||||||
*/
|
*/
|
||||||
inline std::mutex &TagEditorWidget::fileOperationMutex()
|
inline QMutex &TagEditorWidget::fileOperationMutex()
|
||||||
{
|
{
|
||||||
return m_fileOperationMutex;
|
return m_fileOperationMutex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
|
|
||||||
#include <c++utilities/misc/memory.h>
|
#include <c++utilities/misc/memory.h>
|
||||||
|
|
||||||
|
#include <qtutilities/misc/trylocker.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
#include <QtConcurrent>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace ThreadingUtils;
|
||||||
|
|
||||||
namespace RenamingUtility {
|
namespace RenamingUtility {
|
||||||
|
|
||||||
|
@ -55,26 +57,25 @@ bool RemamingEngine::setProgram(const QString &program)
|
||||||
|
|
||||||
bool RemamingEngine::generatePreview(const QDir &rootDirectory, bool includeSubdirs)
|
bool RemamingEngine::generatePreview(const QDir &rootDirectory, bool includeSubdirs)
|
||||||
{
|
{
|
||||||
if(!m_mutex.try_lock()) {
|
TryLocker<> locker(m_mutex);
|
||||||
|
if(locker) {
|
||||||
|
setRootItem();
|
||||||
|
m_includeSubdirs = includeSubdirs;
|
||||||
|
m_dir = rootDirectory;
|
||||||
|
QtConcurrent::run([this] () {
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
m_aborted.store(false);
|
||||||
|
m_itemsProcessed = 0;
|
||||||
|
m_errorsOccured = 0;
|
||||||
|
m_newlyGeneratedRootItem = generatePreview(m_dir);
|
||||||
|
}
|
||||||
|
emit previewGenerated();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock_guard<mutex> guard(m_mutex, adopt_lock);
|
|
||||||
setRootItem();
|
|
||||||
m_includeSubdirs = includeSubdirs;
|
|
||||||
m_dir = rootDirectory;
|
|
||||||
auto startFunc = [this] () {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> guard(m_mutex);
|
|
||||||
m_aborted.store(false);
|
|
||||||
m_itemsProcessed = 0;
|
|
||||||
m_errorsOccured = 0;
|
|
||||||
m_newlyGeneratedRootItem = generatePreview(m_dir);
|
|
||||||
}
|
|
||||||
emit previewGenerated();
|
|
||||||
};
|
|
||||||
std::thread thread(startFunc);
|
|
||||||
thread.detach();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemamingEngine::applyChangings()
|
bool RemamingEngine::applyChangings()
|
||||||
|
@ -82,28 +83,27 @@ bool RemamingEngine::applyChangings()
|
||||||
if(!m_rootItem) {
|
if(!m_rootItem) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!m_mutex.try_lock()) {
|
TryLocker<> locker(m_mutex);
|
||||||
|
if(locker) {
|
||||||
|
QtConcurrent::run([this] () {
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
m_aborted.store(false);
|
||||||
|
m_itemsProcessed = 0;
|
||||||
|
m_errorsOccured = 0;
|
||||||
|
applyChangings(m_rootItem.get());
|
||||||
|
}
|
||||||
|
emit changingsApplied();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock_guard<mutex> guard(m_mutex, adopt_lock);
|
|
||||||
auto startFunc = [this] () {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> guard(m_mutex);
|
|
||||||
m_aborted.store(false);
|
|
||||||
m_itemsProcessed = 0;
|
|
||||||
m_errorsOccured = 0;
|
|
||||||
applyChangings(m_rootItem.get());
|
|
||||||
}
|
|
||||||
emit changingsApplied();
|
|
||||||
};
|
|
||||||
std::thread thread(startFunc);
|
|
||||||
thread.detach();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemamingEngine::isBusy()
|
bool RemamingEngine::isBusy()
|
||||||
{
|
{
|
||||||
if(m_mutex.try_lock()) {
|
if(m_mutex.tryLock()) {
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -113,7 +113,7 @@ bool RemamingEngine::isBusy()
|
||||||
|
|
||||||
void RemamingEngine::abort()
|
void RemamingEngine::abort()
|
||||||
{
|
{
|
||||||
m_aborted.store(true);
|
m_aborted.store(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemamingEngine::isAborted()
|
bool RemamingEngine::isAborted()
|
||||||
|
@ -123,8 +123,8 @@ bool RemamingEngine::isAborted()
|
||||||
|
|
||||||
bool RemamingEngine::clearPreview()
|
bool RemamingEngine::clearPreview()
|
||||||
{
|
{
|
||||||
if(m_mutex.try_lock()) {
|
TryLocker<> locker(m_mutex);
|
||||||
lock_guard<mutex> guard(m_mutex, adopt_lock);
|
if(locker) {
|
||||||
updateModel(nullptr);
|
updateModel(nullptr);
|
||||||
m_rootItem.reset();
|
m_rootItem.reset();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QAtomicInteger>
|
||||||
#if TAGEDITOR_USE_JSENGINE
|
#if TAGEDITOR_USE_JSENGINE
|
||||||
# include <QJSEngine>
|
# include <QJSEngine>
|
||||||
# include <QJSValue>
|
# include <QJSValue>
|
||||||
|
@ -17,8 +18,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QFileInfo)
|
QT_FORWARD_DECLARE_CLASS(QFileInfo)
|
||||||
|
|
||||||
|
@ -79,11 +78,11 @@ private:
|
||||||
std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem;
|
std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem;
|
||||||
int m_itemsProcessed;
|
int m_itemsProcessed;
|
||||||
int m_errorsOccured;
|
int m_errorsOccured;
|
||||||
std::atomic<bool> m_aborted;
|
QAtomicInteger<unsigned char> m_aborted;
|
||||||
TAGEDITOR_JS_VALUE m_program;
|
TAGEDITOR_JS_VALUE m_program;
|
||||||
QDir m_dir;
|
QDir m_dir;
|
||||||
bool m_includeSubdirs;
|
bool m_includeSubdirs;
|
||||||
std::mutex m_mutex;
|
QMutex m_mutex;
|
||||||
FileSystemItemModel *m_model;
|
FileSystemItemModel *m_model;
|
||||||
FilteredFileSystemItemModel *m_currentModel;
|
FilteredFileSystemItemModel *m_currentModel;
|
||||||
FilteredFileSystemItemModel *m_previewModel;
|
FilteredFileSystemItemModel *m_previewModel;
|
||||||
|
|
|
@ -15,7 +15,7 @@ VERSION = 1.4.0
|
||||||
|
|
||||||
# basic configuration: application
|
# basic configuration: application
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
QT += core gui widgets
|
QT += core gui widgets concurrent network
|
||||||
# use webkitwidgets if available; otherwise use webenginewidgets
|
# use webkitwidgets if available; otherwise use webenginewidgets
|
||||||
!forcewebengine:qtHaveModule(webkitwidgets) {
|
!forcewebengine:qtHaveModule(webkitwidgets) {
|
||||||
QT += webkitwidgets
|
QT += webkitwidgets
|
||||||
|
|
Loading…
Reference in New Issue