From a9f3a607a36e66c94f7e7b9f7151dff35bec9542 Mon Sep 17 00:00:00 2001 From: Martchus Date: Tue, 1 Jun 2021 22:36:48 +0200 Subject: [PATCH] Improve showing IO errors * Make error messages and dialogs more consistent * Print the actual error message (which might actually contain something useful when NativeFileStream is used) --- cli/mainfeatures.cpp | 36 ++++++++++++++++++------------- gui/tageditorwidget.cpp | 47 ++++++++++++++++++++++++++--------------- gui/tageditorwidget.h | 4 ++-- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/cli/mainfeatures.cpp b/cli/mainfeatures.cpp index e2cc7eb..66c842d 100644 --- a/cli/mainfeatures.cpp +++ b/cli/mainfeatures.cpp @@ -129,12 +129,15 @@ void generateFileInfo(const ArgumentOccurrence &, const Argument &inputFileArg, if (file.open(QFile::WriteOnly) && file.write(HtmlInfo::generateInfo(inputFileInfo, diag, diagReparsing)) && file.flush()) { cout << "File information has been saved to \"" << outputFileArg.values().front() << "\"." << endl; } else { - cerr << Phrases::Error << "An IO error occured when writing the file \"" << outputFileArg.values().front() << "\"." << Phrases::EndFlush; + const auto errorMessage = file.errorString().toUtf8(); + cerr << Phrases::Error << "An IO error occured when writing the file \"" << outputFileArg.values().front() + << "\": " << std::string_view(errorMessage.data(), errorMessage.size()) << Phrases::EndFlush; } } catch (const TagParser::Failure &) { cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << Phrases::EndFlush; - } catch (const std::ios_base::failure &) { - cerr << Phrases::Error << "An IO failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << Phrases::EndFlush; + } catch (const std::ios_base::failure &e) { + cerr << Phrases::Error << "An IO error occured when reading the file \"" << inputFileArg.values().front() << "\": " << e.what() + << Phrases::EndFlush; } #else CPP_UTILITIES_UNUSED(inputFileArg); @@ -317,7 +320,7 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const } catch (const TagParser::Failure &) { cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush; } catch (const std::ios_base::failure &) { - cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"" << Phrases::EndFlush; + cerr << Phrases::Error << "An IO error occured when reading the file \"" << file << "\"" << Phrases::EndFlush; } printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent()); @@ -380,7 +383,7 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &showUnsupportedAr } catch (const TagParser::Failure &) { cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush; } catch (const std::ios_base::failure &) { - cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush; + cerr << Phrases::Error << "An IO error occured when reading the file \"" << file << "\"." << Phrases::EndFlush; } printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent()); cout << endl; @@ -892,9 +895,10 @@ void setTagInfo(const SetTagInfoArgs &args) } catch (const TagParser::Failure &) { finalizeLog(); cerr << " - " << Phrases::Error << "A parsing failure occured when reading/writing the file \"" << file << "\"." << Phrases::EndFlush; - } catch (const std::ios_base::failure &) { + } catch (const std::ios_base::failure &e) { finalizeLog(); - cerr << " - " << Phrases::Error << "An IO failure occured when reading/writing the file \"" << file << "\"." << Phrases::EndFlush; + cerr << " - " << Phrases::Error << "An IO error occured when reading/writing the file \"" << file << "\": " << e.what() + << Phrases::EndFlush; } printDiagMessages(diag, "Diagnostic messages:", args.verboseArg.isPresent()); @@ -984,8 +988,9 @@ void extractField( outputFileStream.write(value.first->dataPointer(), static_cast(value.first->dataSize())); outputFileStream.flush(); cout << " - Value has been saved to \"" << path << "\"." << endl; - } catch (const std::ios_base::failure &) { - cerr << " - " << Phrases::Error << "An IO error occured when writing the file \"" << path << "\"." << Phrases::End; + } catch (const std::ios_base::failure &e) { + cerr << " - " << Phrases::Error << "An IO error occured when writing the file \"" << path << "\": " << e.what() + << Phrases::End; } } } else { @@ -1034,8 +1039,9 @@ void extractField( attachment.first->data()->copyTo(outputFileStream); outputFileStream.flush(); cout << " - Value has been saved to \"" << path << "\"." << endl; - } catch (const std::ios_base::failure &) { - cerr << " - " << Phrases::Error << "An IO error occured when writing the file \"" << path << "\"." << Phrases::EndFlush; + } catch (const std::ios_base::failure &e) { + cerr << " - " << Phrases::Error << "An IO error occured when writing the file \"" << path << "\": " << e.what() + << Phrases::EndFlush; } } } else { @@ -1047,8 +1053,8 @@ void extractField( } catch (const TagParser::Failure &) { cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::End; - } catch (const std::ios_base::failure &) { - cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::End; + } catch (const std::ios_base::failure &e) { + cerr << Phrases::Error << "An IO error occured when reading the file \"" << file << "\": " << e.what() << Phrases::End; } printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent()); } @@ -1083,8 +1089,8 @@ void exportToJson(const ArgumentOccurrence &, const Argument &filesArg, const Ar jsonData.emplace_back(fileInfo, document.GetAllocator()); } catch (const TagParser::Failure &) { cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush; - } catch (const std::ios_base::failure &) { - cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush; + } catch (const std::ios_base::failure &e) { + cerr << Phrases::Error << "An IO error occured when reading the file \"" << file << "\": " << e.what() << Phrases::EndFlush; } } diff --git a/gui/tageditorwidget.cpp b/gui/tageditorwidget.cpp index 739c969..8c4ebb5 100644 --- a/gui/tageditorwidget.cpp +++ b/gui/tageditorwidget.cpp @@ -840,7 +840,8 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh) m_ui->fileNameLabel->setText(m_fileName); // define function to parse the file const auto startThread = [this, &diag] { - char result; + auto result = char(); + auto ioError = QString(); try { // try to open with write access try { @@ -856,15 +857,18 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh) } catch (const Failure &) { // the file has been opened; parsing notifications will be shown in the info box result = FatalParsingError; - } catch (const std::ios_base::failure &) { + } catch (const std::ios_base::failure &e) { // the file could not be opened because an IO error occured m_fileInfo.close(); // ensure file is closed result = IoError; + if ((ioError = QString::fromLocal8Bit(e.what())).isEmpty()) { + ioError = tr("unknown error"); + } } catch (const std::exception &e) { diag.emplace_back(TagParser::DiagLevel::Critical, argsToString("Something completely unexpected happened: ", +e.what()), "parsing"); result = FatalParsingError; } - QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result)); + QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result), Q_ARG(QString, ioError)); }; // perform the operation concurrently m_ongoingFileOperation = QtConcurrent::run(startThread); @@ -899,19 +903,19 @@ bool TagEditorWidget::reparseFile() * parsing operation using Qt::QueuedConnection. * \param result Specifies whether the file could be load sucessfully. */ -void TagEditorWidget::showFile(char result) +void TagEditorWidget::showFile(char result, const QString &ioError) { // handle IO errors if (result == IoError) { // update status updateFileStatusStatus(); - static const QString statusMsg(tr("The file could not be opened because an IO error occurred.")); + static const QString statusMsg(tr("The file could not be opened because an IO error occurred: %1")); auto msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Critical); msgBox->setAttribute(Qt::WA_DeleteOnClose, true); msgBox->setWindowTitle(tr("Opening file - ") + QCoreApplication::applicationName()); - msgBox->setText(statusMsg); - msgBox->setInformativeText(tr("Opening file: ") + m_currentPath); + msgBox->setText(statusMsg.arg(ioError)); + msgBox->setInformativeText(tr("Tried to open file: ") + m_currentPath); msgBox->show(); emit statusMessage(statusMsg); return; @@ -1176,7 +1180,8 @@ bool TagEditorWidget::startSaving() }); AbortableProgressFeedback progress(std::move(showStep), std::move(showPercentage)); - bool processingError = false, ioError = false, canceled = false; + auto ioError = QString(); + auto processingError = false, canceled = false; try { try { m_fileInfo.applyChanges(m_diag, progress); @@ -1184,15 +1189,17 @@ bool TagEditorWidget::startSaving() canceled = true; } catch (const Failure &) { processingError = true; - } catch (const std::ios_base::failure &) { - ioError = true; + } catch (const std::ios_base::failure &e) { + if ((ioError = QString::fromLocal8Bit(e.what())).isEmpty()) { + ioError = tr("unknown error"); + } } } catch (const exception &e) { m_diag.emplace_back(TagParser::DiagLevel::Critical, argsToString("Something completely unexpected happened: ", e.what()), "making"); processingError = true; } QMetaObject::invokeMethod( - this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError), Q_ARG(bool, canceled)); + this, "showSavingResult", Qt::QueuedConnection, Q_ARG(QString, ioError), Q_ARG(bool, processingError), Q_ARG(bool, canceled)); }; // use another thread to perform the operation m_ongoingFileOperation = QtConcurrent::run(startThread); @@ -1207,7 +1214,7 @@ bool TagEditorWidget::startSaving() * * \param sucess Specifies whether the file could be saved sucessfully. */ -void TagEditorWidget::showSavingResult(bool processingError, bool ioError, bool canceled) +void TagEditorWidget::showSavingResult(QString ioError, bool processingError, bool canceled) { m_ui->abortButton->setHidden(true); m_ui->makingNotificationWidget->setNotificationType(NotificationType::TaskComplete); @@ -1215,7 +1222,7 @@ void TagEditorWidget::showSavingResult(bool processingError, bool ioError, bool m_ui->makingNotificationWidget->setPercentage(-1); m_ui->makingNotificationWidget->setHidden(false); m_makingResultsAvailable = true; - if (!processingError && !ioError) { + if (!processingError && ioError.isEmpty()) { // display status messages QString statusMsg; size_t critical = 0, warnings = 0; @@ -1271,10 +1278,16 @@ void TagEditorWidget::showSavingResult(bool processingError, bool ioError, bool // fatal errors occured // -> show status - static const QString processingErrorMsg(tr("The tags could not be saved. See the info box for detail.")); - static const QString ioErrorMsg(tr("The tags could not be saved because an IO error occured.")); - const auto &errorMsg = ioError ? ioErrorMsg : processingErrorMsg; - QMessageBox::critical(this, QCoreApplication::applicationName(), errorMsg); + static const QString processingErrorMsg = tr("The tags could not be saved. Checkout the info box for details."); + static const QString ioErrorMsg = tr("The tags could not be saved because an IO error occured: %1"); + const auto errorMsg = !ioError.isEmpty() ? ioErrorMsg.arg(ioError) : processingErrorMsg; + auto msgBox = new QMessageBox(this); + msgBox->setIcon(QMessageBox::Critical); + msgBox->setAttribute(Qt::WA_DeleteOnClose, true); + msgBox->setWindowTitle(tr("Saving file - ") + QCoreApplication::applicationName()); + msgBox->setText(errorMsg); + msgBox->setInformativeText(tr("Tried to save file: ") + m_currentPath); + msgBox->show(); emit statusMessage(errorMsg); m_ui->makingNotificationWidget->setText(errorMsg); m_ui->makingNotificationWidget->setNotificationType(NotificationType::Critical); diff --git a/gui/tageditorwidget.h b/gui/tageditorwidget.h index c0c952d..ec59392 100644 --- a/gui/tageditorwidget.h +++ b/gui/tageditorwidget.h @@ -101,7 +101,7 @@ protected: private Q_SLOTS: // editor void fileChangedOnDisk(const QString &path); - void showFile(char result); + void showFile(char result, const QString &ioError); void handleReturnPressed(); void handleKeepPreviousValuesActionTriggered(QAction *action); void addTag(const std::function &createTag); @@ -109,7 +109,7 @@ private Q_SLOTS: void changeTarget(TagParser::Tag *tag); // saving - void showSavingResult(bool processingError, bool ioError, bool canceled); + void showSavingResult(QString ioError, bool processingError, bool canceled); // info (web) view void initInfoView();