Adapt to new notification handling
This commit is contained in:
parent
254b9b7661
commit
c2b2e4ac44
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <c++utilities/conversion/conversionexception.h>
|
#include <c++utilities/conversion/conversionexception.h>
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
#include <c++utilities/conversion/stringbuilder.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -37,7 +38,7 @@ void AttachmentInfo::parseDenotation(const char *denotation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachmentInfo::apply(AbstractContainer *container)
|
void AttachmentInfo::apply(AbstractContainer *container, Media::Diagnostics &diag)
|
||||||
{
|
{
|
||||||
static const string context("applying specified attachments");
|
static const string context("applying specified attachments");
|
||||||
AbstractAttachment *attachment = nullptr;
|
AbstractAttachment *attachment = nullptr;
|
||||||
|
@ -48,30 +49,30 @@ void AttachmentInfo::apply(AbstractContainer *container)
|
||||||
cerr << "Argument --update-argument specified but no name/path provided." << endl;
|
cerr << "Argument --update-argument specified but no name/path provided." << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
apply(container->createAttachment());
|
apply(container->createAttachment(), diag);
|
||||||
break;
|
break;
|
||||||
case AttachmentAction::Update:
|
case AttachmentAction::Update:
|
||||||
if(hasId) {
|
if(hasId) {
|
||||||
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
||||||
attachment = container->attachment(i);
|
attachment = container->attachment(i);
|
||||||
if(attachment->id() == id) {
|
if(attachment->id() == id) {
|
||||||
apply(attachment);
|
apply(attachment, diag);
|
||||||
attachmentFound = true;
|
attachmentFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!attachmentFound) {
|
if(!attachmentFound) {
|
||||||
container->addNotification(NotificationType::Critical, "Attachment with the specified ID \"" + numberToString(id) + "\" does not exist and hence can't be updated.", context);
|
diag.emplace_back(DiagLevel::Critical, argsToString("Attachment with the specified ID \"", id, "\" does not exist and hence can't be updated."), context);
|
||||||
}
|
}
|
||||||
} else if(name) {
|
} else if(name) {
|
||||||
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
||||||
attachment = container->attachment(i);
|
attachment = container->attachment(i);
|
||||||
if(attachment->name() == name) {
|
if(attachment->name() == name) {
|
||||||
apply(attachment);
|
apply(attachment, diag);
|
||||||
attachmentFound = true;
|
attachmentFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!attachmentFound) {
|
if(!attachmentFound) {
|
||||||
container->addNotification(NotificationType::Critical, "Attachment with the specified name \"" + string(name) + "\" does not exist and hence can't be updated.", context);
|
diag.emplace_back(DiagLevel::Critical, argsToString("Attachment with the specified name \"", name, "\" does not exist and hence can't be updated."), context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Argument --update-argument specified but no ID/name provided." << endl;
|
cerr << "Argument --update-argument specified but no ID/name provided." << endl;
|
||||||
|
@ -87,7 +88,7 @@ void AttachmentInfo::apply(AbstractContainer *container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!attachmentFound) {
|
if(!attachmentFound) {
|
||||||
container->addNotification(NotificationType::Critical, "Attachment with the specified ID \"" + numberToString(id) + "\" does not exist and hence can't be removed.", context);
|
diag.emplace_back(DiagLevel::Critical, "Attachment with the specified ID \"" + numberToString(id) + "\" does not exist and hence can't be removed.", context);
|
||||||
}
|
}
|
||||||
} else if(name) {
|
} else if(name) {
|
||||||
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
for(size_t i = 0, count = container->attachmentCount(); i < count; ++i) {
|
||||||
|
@ -98,7 +99,7 @@ void AttachmentInfo::apply(AbstractContainer *container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!attachmentFound) {
|
if(!attachmentFound) {
|
||||||
container->addNotification(NotificationType::Critical, "Attachment with the specified name \"" + string(name) + "\" does not exist and hence can't be removed.", context);
|
diag.emplace_back(DiagLevel::Critical, "Attachment with the specified name \"" + string(name) + "\" does not exist and hence can't be removed.", context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Argument --remove-argument specified but no ID/name provided." << endl;
|
cerr << "Argument --remove-argument specified but no ID/name provided." << endl;
|
||||||
|
@ -107,13 +108,13 @@ void AttachmentInfo::apply(AbstractContainer *container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachmentInfo::apply(AbstractAttachment *attachment)
|
void AttachmentInfo::apply(AbstractAttachment *attachment, Media::Diagnostics &diag)
|
||||||
{
|
{
|
||||||
if(hasId) {
|
if(hasId) {
|
||||||
attachment->setId(id);
|
attachment->setId(id);
|
||||||
}
|
}
|
||||||
if(path) {
|
if(path) {
|
||||||
attachment->setFile(path);
|
attachment->setFile(path, diag);
|
||||||
}
|
}
|
||||||
if(name) {
|
if(name) {
|
||||||
attachment->setName(name);
|
attachment->setName(name);
|
||||||
|
@ -134,13 +135,13 @@ void AttachmentInfo::reset()
|
||||||
path = name = mime = desc = nullptr;
|
path = name = mime = desc = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttachmentInfo::next(AbstractContainer *container)
|
bool AttachmentInfo::next(AbstractContainer *container, Media::Diagnostics &diag)
|
||||||
{
|
{
|
||||||
if(!id && !path && !name && !mime && !desc) {
|
if(!id && !path && !name && !mime && !desc) {
|
||||||
// skip empty attachment infos
|
// skip empty attachment infos
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
apply(container);
|
apply(container, diag);
|
||||||
reset();
|
reset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef CLI_ATTACHMENT_INFO
|
#ifndef CLI_ATTACHMENT_INFO
|
||||||
#define CLI_ATTACHMENT_INFO
|
#define CLI_ATTACHMENT_INFO
|
||||||
|
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <c++utilities/conversion/types.h>
|
#include <c++utilities/conversion/types.h>
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
@ -21,10 +23,10 @@ class AttachmentInfo
|
||||||
public:
|
public:
|
||||||
AttachmentInfo();
|
AttachmentInfo();
|
||||||
void parseDenotation(const char *denotation);
|
void parseDenotation(const char *denotation);
|
||||||
void apply(Media::AbstractContainer *container);
|
void apply(Media::AbstractContainer *container, Media::Diagnostics &diag);
|
||||||
void apply(Media::AbstractAttachment *attachment);
|
void apply(Media::AbstractAttachment *attachment, Media::Diagnostics &diag);
|
||||||
void reset();
|
void reset();
|
||||||
bool next(Media::AbstractContainer *container);
|
bool next(Media::AbstractContainer *container, Media::Diagnostics &diag);
|
||||||
|
|
||||||
AttachmentAction action;
|
AttachmentAction action;
|
||||||
uint64 id;
|
uint64 id;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "./fieldmapping.h"
|
#include "./fieldmapping.h"
|
||||||
|
|
||||||
#include <tagparser/mediafileinfo.h>
|
#include <tagparser/mediafileinfo.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
#include <tagparser/progressfeedback.h>
|
||||||
#include <tagparser/matroska/matroskatag.h>
|
#include <tagparser/matroska/matroskatag.h>
|
||||||
#include <tagparser/mp4/mp4tag.h>
|
#include <tagparser/mp4/mp4tag.h>
|
||||||
#include <tagparser/vorbis/vorbiscomment.h>
|
#include <tagparser/vorbis/vorbiscomment.h>
|
||||||
|
@ -118,16 +120,16 @@ string incremented(const string &str, unsigned int toIncrement)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printNotifications(NotificationList ¬ifications, const char *head, bool beVerbose)
|
void printDiagMessages(const Diagnostics &diag, const char *head, bool beVerbose)
|
||||||
{
|
{
|
||||||
if(notifications.empty()) {
|
if(diag.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!beVerbose) {
|
if(!beVerbose) {
|
||||||
for(const auto ¬ification : notifications) {
|
for(const auto &message : diag) {
|
||||||
switch(notification.type()) {
|
switch(message.level()) {
|
||||||
case NotificationType::Debug:
|
case DiagLevel::Debug:
|
||||||
case NotificationType::Information:
|
case DiagLevel::Information:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto printNotifications;
|
goto printNotifications;
|
||||||
|
@ -140,45 +142,37 @@ printNotifications:
|
||||||
if(head) {
|
if(head) {
|
||||||
cout << " - " << head << endl;
|
cout << " - " << head << endl;
|
||||||
}
|
}
|
||||||
Notification::sortByTime(notifications);
|
for(const auto &message : diag) {
|
||||||
for(const auto ¬ification : notifications) {
|
switch(message.level()) {
|
||||||
switch(notification.type()) {
|
case DiagLevel::Debug:
|
||||||
case NotificationType::Debug:
|
|
||||||
if(beVerbose) {
|
if(beVerbose) {
|
||||||
cout << " Debug ";
|
cout << " Debug ";
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case NotificationType::Information:
|
case DiagLevel::Information:
|
||||||
if(beVerbose) {
|
if(beVerbose) {
|
||||||
cout << " Information ";
|
cout << " Information ";
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case NotificationType::Warning:
|
case DiagLevel::Warning:
|
||||||
cout << " Warning ";
|
cout << " Warning ";
|
||||||
break;
|
break;
|
||||||
case NotificationType::Critical:
|
case DiagLevel::Critical:
|
||||||
cout << " Error ";
|
cout << " Error ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
cout << notification.creationTime().toString(DateTimeOutputFormat::TimeOnly) << " ";
|
cout << message.creationTime().toString(DateTimeOutputFormat::TimeOnly) << " ";
|
||||||
cout << notification.context() << ": ";
|
cout << message.context() << ": ";
|
||||||
cout << notification.message() << '\n';
|
cout << message.message() << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printNotifications(const MediaFileInfo &fileInfo, const char *head, bool beVerbose)
|
|
||||||
{
|
|
||||||
NotificationList notifications;
|
|
||||||
fileInfo.gatherRelatedNotifications(notifications);
|
|
||||||
printNotifications(notifications, head, beVerbose);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printProperty(const char *propName, const char *value, const char *suffix, Indentation indentation)
|
void printProperty(const char *propName, const char *value, const char *suffix, Indentation indentation)
|
||||||
{
|
{
|
||||||
if(!*value) {
|
if(!*value) {
|
||||||
|
@ -658,29 +652,23 @@ bool stringToBool(const string &str)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool logLineFinalized = true;
|
bool logLineFinalized = true;
|
||||||
static string lastLoggedStatus;
|
static string lastStep;
|
||||||
void logStatus(const StatusProvider &statusProvider)
|
void logNextStep(const AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if(statusProvider.currentStatus() != lastLoggedStatus) {
|
// finalize previous step
|
||||||
// the ongoing operation ("status") has changed
|
if(!logLineFinalized) {
|
||||||
// -> finalize previous line and make new line
|
cout << "\r - [100%] " << lastStep << endl;
|
||||||
if(!logLineFinalized) {
|
logLineFinalized = true;
|
||||||
cout << "\r - [100%] " << lastLoggedStatus << endl;
|
|
||||||
logLineFinalized = true;
|
|
||||||
}
|
|
||||||
// -> update lastStatus
|
|
||||||
lastLoggedStatus = statusProvider.currentStatus();
|
|
||||||
}
|
}
|
||||||
|
// print line for next step
|
||||||
|
lastStep = progress.step();
|
||||||
|
cout << "\r - [" << setw(3) << static_cast<unsigned int>(progress.stepPercentage()) << "%] " << lastStep << flush;
|
||||||
|
logLineFinalized = false;
|
||||||
|
}
|
||||||
|
|
||||||
// update current line if an operation is ongoing (status is not empty)
|
void logStepPercentage(const Media::AbortableProgressFeedback &progress)
|
||||||
if(!lastLoggedStatus.empty()) {
|
{
|
||||||
int percentage = static_cast<int>(statusProvider.currentPercentage() * 100);
|
cout << "\r - [" << setw(3) << static_cast<unsigned int>(progress.stepPercentage()) << "%] " << lastStep << flush;
|
||||||
if(percentage < 0) {
|
|
||||||
percentage = 0;
|
|
||||||
}
|
|
||||||
cout << "\r - [" << setw(3) << percentage << "%] " << lastLoggedStatus << flush;
|
|
||||||
logLineFinalized = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalizeLog()
|
void finalizeLog()
|
||||||
|
@ -688,9 +676,9 @@ void finalizeLog()
|
||||||
if(logLineFinalized) {
|
if(logLineFinalized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cout << '\n';
|
cout << "\r - [100%] " << lastStep << '\n';
|
||||||
logLineFinalized = true;
|
logLineFinalized = true;
|
||||||
lastLoggedStatus.clear();
|
lastStep.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ class Argument;
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
class MediaFileInfo;
|
class MediaFileInfo;
|
||||||
|
class Diagnostics;
|
||||||
|
class AbortableProgressFeedback;
|
||||||
enum class TagUsage;
|
enum class TagUsage;
|
||||||
enum class ElementPosition;
|
enum class ElementPosition;
|
||||||
}
|
}
|
||||||
|
@ -263,8 +265,7 @@ constexpr bool isDigit(char c)
|
||||||
|
|
||||||
std::string incremented(const std::string &str, unsigned int toIncrement = 1);
|
std::string incremented(const std::string &str, unsigned int toIncrement = 1);
|
||||||
|
|
||||||
void printNotifications(NotificationList ¬ifications, const char *head = nullptr, bool beVerbose = false);
|
void printDiagMessages(const Media::Diagnostics &diag, const char *head = nullptr, bool beVerbose = false);
|
||||||
void printNotifications(const MediaFileInfo &fileInfo, const char *head = nullptr, bool beVerbose = false);
|
|
||||||
void printProperty(const char *propName, const char *value, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
|
void printProperty(const char *propName, const char *value, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
|
||||||
void printProperty(const char *propName, ElementPosition elementPosition, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
|
void printProperty(const char *propName, ElementPosition elementPosition, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
|
||||||
|
|
||||||
|
@ -310,7 +311,8 @@ FieldDenotations parseFieldDenotations(const ApplicationUtilities::Argument &fie
|
||||||
std::string tagName(const Tag *tag);
|
std::string tagName(const Tag *tag);
|
||||||
bool stringToBool(const std::string &str);
|
bool stringToBool(const std::string &str);
|
||||||
extern bool logLineFinalized;
|
extern bool logLineFinalized;
|
||||||
void logStatus(const StatusProvider &statusProvider);
|
void logNextStep(const Media::AbortableProgressFeedback &progress);
|
||||||
|
void logStepPercentage(const Media::AbortableProgressFeedback &progress);
|
||||||
void finalizeLog();
|
void finalizeLog();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <tagparser/abstractattachment.h>
|
#include <tagparser/abstractattachment.h>
|
||||||
#include <tagparser/abstractchapter.h>
|
#include <tagparser/abstractchapter.h>
|
||||||
#include <tagparser/backuphelper.h>
|
#include <tagparser/backuphelper.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
#include <tagparser/progressfeedback.h>
|
||||||
|
|
||||||
#ifdef TAGEDITOR_JSON_EXPORT
|
#ifdef TAGEDITOR_JSON_EXPORT
|
||||||
# include <reflective_rapidjson/json/reflector.h>
|
# include <reflective_rapidjson/json/reflector.h>
|
||||||
|
@ -107,18 +109,21 @@ void generateFileInfo(const ArgumentOccurrence &, const Argument &inputFileArg,
|
||||||
MediaFileInfo inputFileInfo(inputFileArg.values().front());
|
MediaFileInfo inputFileInfo(inputFileArg.values().front());
|
||||||
inputFileInfo.setForceFullParse(validateArg.isPresent());
|
inputFileInfo.setForceFullParse(validateArg.isPresent());
|
||||||
inputFileInfo.open(true);
|
inputFileInfo.open(true);
|
||||||
inputFileInfo.parseEverything();
|
Diagnostics diag;
|
||||||
|
inputFileInfo.parseEverything(diag);
|
||||||
|
|
||||||
|
// generate and save info
|
||||||
|
Diagnostics diagReparsing;
|
||||||
(outputFileArg.isPresent() ? cout : cerr) << "Saving file info for \"" << inputFileArg.values().front() << "\" ..." << endl;
|
(outputFileArg.isPresent() ? cout : cerr) << "Saving file info for \"" << inputFileArg.values().front() << "\" ..." << endl;
|
||||||
NotificationList origNotify;
|
if(!outputFileArg.isPresent()) {
|
||||||
if(outputFileArg.isPresent()) {
|
cout << HtmlInfo::generateInfo(inputFileInfo, diag, diagReparsing).data() << endl;
|
||||||
QFile file(fromNativeFileName(outputFileArg.values().front()));
|
return;
|
||||||
if(file.open(QFile::WriteOnly) && file.write(HtmlInfo::generateInfo(inputFileInfo, origNotify)) && file.flush()) {
|
}
|
||||||
cout << "File information has been saved to \"" << outputFileArg.values().front() << "\"." << endl;
|
QFile file(fromNativeFileName(outputFileArg.values().front()));
|
||||||
} else {
|
if(file.open(QFile::WriteOnly) && file.write(HtmlInfo::generateInfo(inputFileInfo, diag, diagReparsing)) && file.flush()) {
|
||||||
cerr << Phrases::Error << "An IO error occured when writing the file \"" << outputFileArg.values().front() << "\"." << Phrases::EndFlush;
|
cout << "File information has been saved to \"" << outputFileArg.values().front() << "\"." << endl;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cout << HtmlInfo::generateInfo(inputFileInfo, origNotify).data() << endl;
|
cerr << Phrases::Error << "An IO error occured when writing the file \"" << outputFileArg.values().front() << "\"." << Phrases::EndFlush;
|
||||||
}
|
}
|
||||||
} catch(const Media::Failure &) {
|
} catch(const Media::Failure &) {
|
||||||
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << Phrases::EndFlush;
|
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << Phrases::EndFlush;
|
||||||
|
@ -146,14 +151,15 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const
|
||||||
|
|
||||||
MediaFileInfo fileInfo;
|
MediaFileInfo fileInfo;
|
||||||
for(const char *file : filesArg.values()) {
|
for(const char *file : filesArg.values()) {
|
||||||
|
Diagnostics diag;
|
||||||
try {
|
try {
|
||||||
// parse tags
|
// parse tags
|
||||||
fileInfo.setPath(file);
|
fileInfo.setPath(file);
|
||||||
fileInfo.open(true);
|
fileInfo.open(true);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
fileInfo.parseTracks();
|
fileInfo.parseTracks(diag);
|
||||||
fileInfo.parseAttachments();
|
fileInfo.parseAttachments(diag);
|
||||||
fileInfo.parseChapters();
|
fileInfo.parseChapters(diag);
|
||||||
|
|
||||||
// print general/container-related info
|
// print general/container-related info
|
||||||
cout << "Technical information for \"" << file << "\":\n";
|
cout << "Technical information for \"" << file << "\":\n";
|
||||||
|
@ -176,8 +182,8 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const
|
||||||
printProperty("Duration", container->duration());
|
printProperty("Duration", container->duration());
|
||||||
printProperty("Creation time", container->creationTime());
|
printProperty("Creation time", container->creationTime());
|
||||||
printProperty("Modification time", container->modificationTime());
|
printProperty("Modification time", container->modificationTime());
|
||||||
printProperty("Tag position", container->determineTagPosition());
|
printProperty("Tag position", container->determineTagPosition(diag));
|
||||||
printProperty("Index position", container->determineIndexPosition());
|
printProperty("Index position", container->determineIndexPosition(diag));
|
||||||
}
|
}
|
||||||
if(fileInfo.paddingSize()) {
|
if(fileInfo.paddingSize()) {
|
||||||
printProperty("Padding", dataSizeToString(fileInfo.paddingSize()));
|
printProperty("Padding", dataSizeToString(fileInfo.paddingSize()));
|
||||||
|
@ -295,7 +301,7 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const
|
||||||
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
||||||
}
|
}
|
||||||
|
|
||||||
printNotifications(fileInfo, "Parsing notifications:", verboseArg.isPresent());
|
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent());
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,12 +321,13 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A
|
||||||
|
|
||||||
MediaFileInfo fileInfo;
|
MediaFileInfo fileInfo;
|
||||||
for(const char *file : filesArg.values()) {
|
for(const char *file : filesArg.values()) {
|
||||||
|
Diagnostics diag;
|
||||||
try {
|
try {
|
||||||
// parse tags
|
// parse tags
|
||||||
fileInfo.setPath(file);
|
fileInfo.setPath(file);
|
||||||
fileInfo.open(true);
|
fileInfo.open(true);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
fileInfo.parseTags();
|
fileInfo.parseTags(diag);
|
||||||
cout << "Tag information for \"" << file << "\":\n";
|
cout << "Tag information for \"" << file << "\":\n";
|
||||||
const auto tags = fileInfo.tags();
|
const auto tags = fileInfo.tags();
|
||||||
if(!tags.empty()) {
|
if(!tags.empty()) {
|
||||||
|
@ -353,7 +360,7 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A
|
||||||
::IoUtilities::catchIoFailure();
|
::IoUtilities::catchIoFailure();
|
||||||
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
||||||
}
|
}
|
||||||
printNotifications(fileInfo, "Parsing notifications:", verboseArg.isPresent());
|
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent());
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,17 +461,16 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
|
|
||||||
// iterate through all specified files
|
// iterate through all specified files
|
||||||
unsigned int fileIndex = 0;
|
unsigned int fileIndex = 0;
|
||||||
static const string context("setting tags");
|
static string context("setting tags");
|
||||||
NotificationList notifications;
|
|
||||||
for(const char *file : args.filesArg.values()) {
|
for(const char *file : args.filesArg.values()) {
|
||||||
|
Diagnostics diag;
|
||||||
try {
|
try {
|
||||||
// parse tags and tracks (tracks are relevent because track meta-data such as language can be changed as well)
|
// parse tags and tracks (tracks are relevent because track meta-data such as language can be changed as well)
|
||||||
cout << TextAttribute::Bold << "Setting tag information for \"" << file << "\" ..." << Phrases::EndFlush;
|
cout << TextAttribute::Bold << "Setting tag information for \"" << file << "\" ..." << Phrases::EndFlush;
|
||||||
notifications.clear();
|
|
||||||
fileInfo.setPath(file);
|
fileInfo.setPath(file);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
fileInfo.parseTags();
|
fileInfo.parseTags(diag);
|
||||||
fileInfo.parseTracks();
|
fileInfo.parseTracks(diag);
|
||||||
vector<Tag *> tags;
|
vector<Tag *> tags;
|
||||||
|
|
||||||
// remove tags with the specified targets
|
// remove tags with the specified targets
|
||||||
|
@ -517,7 +523,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
// alter tags
|
// alter tags
|
||||||
fileInfo.tags(tags);
|
fileInfo.tags(tags);
|
||||||
if(tags.empty()) {
|
if(tags.empty()) {
|
||||||
fileInfo.addNotification(NotificationType::Critical, "Can not create appropriate tags for file.", context);
|
diag.emplace_back(DiagLevel::Critical, "Can not create appropriate tags for file.", context);
|
||||||
} else {
|
} else {
|
||||||
// iterate through all tags
|
// iterate through all tags
|
||||||
for(auto *tag : tags) {
|
for(auto *tag : tags) {
|
||||||
|
@ -534,7 +540,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
if(!tag->canEncodingBeUsed(denotedEncoding)) {
|
if(!tag->canEncodingBeUsed(denotedEncoding)) {
|
||||||
usedEncoding = tag->proposedTextEncoding();
|
usedEncoding = tag->proposedTextEncoding();
|
||||||
if(args.encodingArg.isPresent()) {
|
if(args.encodingArg.isPresent()) {
|
||||||
fileInfo.addNotification(NotificationType::Warning, argsToString("Can't use specified encoding \"", args.encodingArg.values().front(), "\" in ", tagName(tag), " because the tag format/version doesn't support it."), context);
|
diag.emplace_back(DiagLevel::Warning, argsToString("Can't use specified encoding \"", args.encodingArg.values().front(), "\" in ", tagName(tag), " because the tag format/version doesn't support it."), context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// iterate through all denoted field values
|
// iterate through all denoted field values
|
||||||
|
@ -553,8 +559,9 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
try {
|
try {
|
||||||
// assume the file refers to a picture
|
// assume the file refers to a picture
|
||||||
MediaFileInfo fileInfo(relevantDenotedValue->value);
|
MediaFileInfo fileInfo(relevantDenotedValue->value);
|
||||||
|
Diagnostics diag;
|
||||||
fileInfo.open(true);
|
fileInfo.open(true);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
auto buff = make_unique<char []>(fileInfo.size());
|
auto buff = make_unique<char []>(fileInfo.size());
|
||||||
fileInfo.stream().seekg(0);
|
fileInfo.stream().seekg(0);
|
||||||
fileInfo.stream().read(buff.get(), fileInfo.size());
|
fileInfo.stream().read(buff.get(), fileInfo.size());
|
||||||
|
@ -562,10 +569,10 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
value.setMimeType(fileInfo.mimeType());
|
value.setMimeType(fileInfo.mimeType());
|
||||||
convertedValues.emplace_back(move(value));
|
convertedValues.emplace_back(move(value));
|
||||||
} catch(const Media::Failure &) {
|
} catch(const Media::Failure &) {
|
||||||
fileInfo.addNotification(NotificationType::Critical, "Unable to parse specified cover file.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to parse specified cover file.", context);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
::IoUtilities::catchIoFailure();
|
::IoUtilities::catchIoFailure();
|
||||||
fileInfo.addNotification(NotificationType::Critical, "An IO error occured when parsing the specified cover file.", context);
|
diag.emplace_back(DiagLevel::Critical, "An IO error occured when parsing the specified cover file.", context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
convertedValues.emplace_back(relevantDenotedValue->value, TagTextEncoding::Utf8, usedEncoding);
|
convertedValues.emplace_back(relevantDenotedValue->value, TagTextEncoding::Utf8, usedEncoding);
|
||||||
|
@ -579,7 +586,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
try {
|
try {
|
||||||
denotedScope.field.setValues(tag, tagType, convertedValues);
|
denotedScope.field.setValues(tag, tagType, convertedValues);
|
||||||
} catch(const ConversionException &e) {
|
} catch(const ConversionException &e) {
|
||||||
fileInfo.addNotification(NotificationType::Critical, argsToString("Unable to parse denoted field ID \"", denotedScope.field.name(), "\": ", e.what()), context);
|
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse denoted field ID \"", denotedScope.field.name(), "\": ", e.what()), context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,10 +620,10 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
} else if(field.denotes("default")) {
|
} else if(field.denotes("default")) {
|
||||||
track->setDefault(stringToBool(value));
|
track->setDefault(stringToBool(value));
|
||||||
} else {
|
} else {
|
||||||
fileInfo.addNotification(NotificationType::Critical, argsToString("Denoted track property name \"", field.denotation(), "\" is invalid"), argsToString("setting meta-data of track ", track->id()));
|
diag.emplace_back(DiagLevel::Critical, argsToString("Denoted track property name \"", field.denotation(), "\" is invalid"), argsToString("setting meta-data of track ", track->id()));
|
||||||
}
|
}
|
||||||
} catch(const ConversionException &e) {
|
} catch(const ConversionException &e) {
|
||||||
fileInfo.addNotification(NotificationType::Critical, argsToString("Unable to parse value for track property \"", field.denotation(), "\": ", e.what()), argsToString("setting meta-data of track ", track->id()));
|
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse value for track property \"", field.denotation(), "\": ", e.what()), argsToString("setting meta-data of track ", track->id()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -635,7 +642,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
bool attachmentsModified = false;
|
bool attachmentsModified = false;
|
||||||
if(args.addAttachmentArg.isPresent() || args.updateAttachmentArg.isPresent() || args.removeAttachmentArg.isPresent() || args.removeExistingAttachmentsArg.isPresent()) {
|
if(args.addAttachmentArg.isPresent() || args.updateAttachmentArg.isPresent() || args.removeAttachmentArg.isPresent() || args.removeExistingAttachmentsArg.isPresent()) {
|
||||||
static const string context("setting attachments");
|
static const string context("setting attachments");
|
||||||
fileInfo.parseAttachments();
|
fileInfo.parseAttachments(diag);
|
||||||
if(fileInfo.attachmentsParsingStatus() == ParsingStatus::Ok) {
|
if(fileInfo.attachmentsParsingStatus() == ParsingStatus::Ok) {
|
||||||
if(container) {
|
if(container) {
|
||||||
// ignore all existing attachments if argument is specified
|
// ignore all existing attachments if argument is specified
|
||||||
|
@ -652,24 +659,24 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
for(const char *value : args.addAttachmentArg.values(i)) {
|
for(const char *value : args.addAttachmentArg.values(i)) {
|
||||||
currentInfo.parseDenotation(value);
|
currentInfo.parseDenotation(value);
|
||||||
}
|
}
|
||||||
attachmentsModified |= currentInfo.next(container);
|
attachmentsModified |= currentInfo.next(container, diag);
|
||||||
}
|
}
|
||||||
currentInfo.action = AttachmentAction::Update;
|
currentInfo.action = AttachmentAction::Update;
|
||||||
for(size_t i = 0, occurrences = args.updateAttachmentArg.occurrences(); i != occurrences; ++i) {
|
for(size_t i = 0, occurrences = args.updateAttachmentArg.occurrences(); i != occurrences; ++i) {
|
||||||
for(const char *value : args.updateAttachmentArg.values(i)) {
|
for(const char *value : args.updateAttachmentArg.values(i)) {
|
||||||
currentInfo.parseDenotation(value);
|
currentInfo.parseDenotation(value);
|
||||||
}
|
}
|
||||||
attachmentsModified |= currentInfo.next(container);
|
attachmentsModified |= currentInfo.next(container, diag);
|
||||||
}
|
}
|
||||||
currentInfo.action = AttachmentAction::Remove;
|
currentInfo.action = AttachmentAction::Remove;
|
||||||
for(size_t i = 0, occurrences = args.removeAttachmentArg.occurrences(); i != occurrences; ++i) {
|
for(size_t i = 0, occurrences = args.removeAttachmentArg.occurrences(); i != occurrences; ++i) {
|
||||||
for(const char *value : args.removeAttachmentArg.values(i)) {
|
for(const char *value : args.removeAttachmentArg.values(i)) {
|
||||||
currentInfo.parseDenotation(value);
|
currentInfo.parseDenotation(value);
|
||||||
}
|
}
|
||||||
attachmentsModified |= currentInfo.next(container);
|
attachmentsModified |= currentInfo.next(container, diag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileInfo.addNotification(NotificationType::Critical, "Unable to assign attachments because the container object has not been initialized.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to assign attachments because the container object has not been initialized.", context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// notification will be added by the file info automatically
|
// notification will be added by the file info automatically
|
||||||
|
@ -677,22 +684,14 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply changes
|
// apply changes
|
||||||
|
fileInfo.setSaveFilePath(currentOutputFile != noMoreOutputFiles ? string(*currentOutputFile) : string());
|
||||||
try {
|
try {
|
||||||
// save parsing notifications because notifications of sub objects like tags, tracks, ... will be gone after applying changes
|
// create handler for progress updates and aborting
|
||||||
fileInfo.setSaveFilePath(currentOutputFile != noMoreOutputFiles ? string(*currentOutputFile) : string());
|
AbortableProgressFeedback progress(logNextStep, logStepPercentage);
|
||||||
fileInfo.gatherRelatedNotifications(notifications);
|
const InterruptHandler handler(bind(&AbortableProgressFeedback::tryToAbort, ref(progress)));
|
||||||
fileInfo.invalidateNotifications();
|
|
||||||
|
|
||||||
// register handler for logging status
|
// apply changes
|
||||||
fileInfo.registerCallback(logStatus);
|
fileInfo.applyChanges(diag, progress);
|
||||||
|
|
||||||
// register interrupt handler
|
|
||||||
const InterruptHandler handler([&fileInfo] {
|
|
||||||
fileInfo.tryToAbort();
|
|
||||||
});
|
|
||||||
|
|
||||||
// apply changes and gather notifications
|
|
||||||
fileInfo.applyChanges();
|
|
||||||
|
|
||||||
// notify about completion
|
// notify about completion
|
||||||
finalizeLog();
|
finalizeLog();
|
||||||
|
@ -714,8 +713,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
||||||
cerr << " - " << Phrases::Error << "An IO failure occured when reading/writing the file \"" << file << "\"." << Phrases::EndFlush;
|
cerr << " - " << Phrases::Error << "An IO failure occured when reading/writing the file \"" << file << "\"." << Phrases::EndFlush;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInfo.gatherRelatedNotifications(notifications);
|
printDiagMessages(diag, "Diagnostic messages:", args.verboseArg.isPresent());
|
||||||
printNotifications(notifications, "Notifications:", args.verboseArg.isPresent());
|
|
||||||
|
|
||||||
// continue with next file
|
// continue with next file
|
||||||
++fileIndex;
|
++fileIndex;
|
||||||
|
@ -747,6 +745,7 @@ void extractField(const Argument &fieldArg, const Argument &attachmentArg, const
|
||||||
|
|
||||||
MediaFileInfo inputFileInfo;
|
MediaFileInfo inputFileInfo;
|
||||||
for(const char *file : inputFilesArg.values()) {
|
for(const char *file : inputFilesArg.values()) {
|
||||||
|
Diagnostics diag;
|
||||||
try {
|
try {
|
||||||
// setup media file info
|
// setup media file info
|
||||||
inputFileInfo.setPath(file);
|
inputFileInfo.setPath(file);
|
||||||
|
@ -756,8 +755,8 @@ void extractField(const Argument &fieldArg, const Argument &attachmentArg, const
|
||||||
if(!fieldDenotations.empty()) {
|
if(!fieldDenotations.empty()) {
|
||||||
// extract tag field
|
// extract tag field
|
||||||
(outputFileArg.isPresent() ? cout : cerr) << "Extracting field " << fieldArg.values().front() << " of \"" << file << "\" ..." << endl;
|
(outputFileArg.isPresent() ? cout : cerr) << "Extracting field " << fieldArg.values().front() << " of \"" << file << "\" ..." << endl;
|
||||||
inputFileInfo.parseContainerFormat();
|
inputFileInfo.parseContainerFormat(diag);
|
||||||
inputFileInfo.parseTags();
|
inputFileInfo.parseTags(diag);
|
||||||
auto tags = inputFileInfo.tags();
|
auto tags = inputFileInfo.tags();
|
||||||
vector<pair<const TagValue *, string> > values;
|
vector<pair<const TagValue *, string> > values;
|
||||||
// iterate through all tags
|
// iterate through all tags
|
||||||
|
@ -769,7 +768,7 @@ void extractField(const Argument &fieldArg, const Argument &attachmentArg, const
|
||||||
values.emplace_back(value, joinStrings({tag->typeName(), numberToString(values.size())}, "-", true));
|
values.emplace_back(value, joinStrings({tag->typeName(), numberToString(values.size())}, "-", true));
|
||||||
}
|
}
|
||||||
} catch(const ConversionException &e) {
|
} catch(const ConversionException &e) {
|
||||||
inputFileInfo.addNotification(NotificationType::Critical, "Unable to parse denoted field ID \"" % string(fieldDenotation.first.field.name()) % "\": " + e.what(), "extracting field");
|
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse denoted field ID \"", fieldDenotation.first.field.name(), "\": ", e.what()), "extracting field");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -812,8 +811,8 @@ void extractField(const Argument &fieldArg, const Argument &attachmentArg, const
|
||||||
}
|
}
|
||||||
logStream << " of \"" << file << "\" ..." << endl;
|
logStream << " of \"" << file << "\" ..." << endl;
|
||||||
|
|
||||||
inputFileInfo.parseContainerFormat();
|
inputFileInfo.parseContainerFormat(diag);
|
||||||
inputFileInfo.parseAttachments();
|
inputFileInfo.parseAttachments(diag);
|
||||||
vector<pair<const AbstractAttachment *, string> > attachments;
|
vector<pair<const AbstractAttachment *, string> > attachments;
|
||||||
// iterate through all attachments
|
// iterate through all attachments
|
||||||
for(const AbstractAttachment *attachment : inputFileInfo.attachments()) {
|
for(const AbstractAttachment *attachment : inputFileInfo.attachments()) {
|
||||||
|
@ -856,7 +855,7 @@ void extractField(const Argument &fieldArg, const Argument &attachmentArg, const
|
||||||
::IoUtilities::catchIoFailure();
|
::IoUtilities::catchIoFailure();
|
||||||
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::End;
|
cerr << Phrases::Error << "An IO failure occured when reading the file \"" << file << "\"." << Phrases::End;
|
||||||
}
|
}
|
||||||
printNotifications(inputFileInfo, "Parsing notifications:", verboseArg.isPresent());
|
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,13 +876,14 @@ void exportToJson(const ArgumentOccurrence &, const Argument &filesArg, const Ar
|
||||||
|
|
||||||
// gather tags for each file
|
// gather tags for each file
|
||||||
for(const char *file : filesArg.values()) {
|
for(const char *file : filesArg.values()) {
|
||||||
|
Diagnostics diag;
|
||||||
try {
|
try {
|
||||||
// parse tags
|
// parse tags
|
||||||
fileInfo.setPath(file);
|
fileInfo.setPath(file);
|
||||||
fileInfo.open(true);
|
fileInfo.open(true);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
fileInfo.parseTags();
|
fileInfo.parseTags(diag);
|
||||||
fileInfo.parseTracks();
|
fileInfo.parseTracks(diag);
|
||||||
jsonData.emplace_back(fileInfo, document.GetAllocator());
|
jsonData.emplace_back(fileInfo, document.GetAllocator());
|
||||||
} catch(const Media::Failure &) {
|
} catch(const Media::Failure &) {
|
||||||
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
||||||
|
@ -893,6 +893,8 @@ void exportToJson(const ArgumentOccurrence &, const Argument &filesArg, const Ar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: serialize diag messages
|
||||||
|
|
||||||
// print the gathered data as JSON document
|
// print the gathered data as JSON document
|
||||||
ReflectiveRapidJSON::JsonReflector::push(jsonData, document, document.GetAllocator());
|
ReflectiveRapidJSON::JsonReflector::push(jsonData, document, document.GetAllocator());
|
||||||
RAPIDJSON_NAMESPACE::OStreamWrapper osw(cout);
|
RAPIDJSON_NAMESPACE::OStreamWrapper osw(cout);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <tagparser/mediafileinfo.h>
|
#include <tagparser/mediafileinfo.h>
|
||||||
#include <tagparser/abstractattachment.h>
|
#include <tagparser/abstractattachment.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <qtutilities/misc/conversion.h>
|
#include <qtutilities/misc/conversion.h>
|
||||||
|
|
||||||
|
@ -91,16 +92,17 @@ void AttachmentsEdit::invalidate()
|
||||||
|
|
||||||
void AttachmentsEdit::addFile(const QString &path)
|
void AttachmentsEdit::addFile(const QString &path)
|
||||||
{
|
{
|
||||||
if(fileInfo() && fileInfo()->attachmentsParsingStatus() == ParsingStatus::Ok && fileInfo()->container()) {
|
if(!fileInfo() || fileInfo()->attachmentsParsingStatus() != ParsingStatus::Ok || !fileInfo()->container()) {
|
||||||
// create and add attachment
|
|
||||||
auto *attachment = fileInfo()->container()->createAttachment();
|
|
||||||
attachment->setIgnored(true);
|
|
||||||
attachment->setFile(toNativeFileName(path).data());
|
|
||||||
m_addedAttachments << attachment;
|
|
||||||
m_model->addAttachment(-1, attachment, true, path);
|
|
||||||
} else {
|
|
||||||
throw Failure();
|
throw Failure();
|
||||||
}
|
}
|
||||||
|
// create and add attachment
|
||||||
|
auto *const attachment = fileInfo()->container()->createAttachment();
|
||||||
|
attachment->setIgnored(true);
|
||||||
|
Diagnostics diag;
|
||||||
|
attachment->setFile(toNativeFileName(path).data(), diag);
|
||||||
|
// TODO: show diag messages
|
||||||
|
m_addedAttachments << attachment;
|
||||||
|
m_model->addAttachment(-1, attachment, true, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachmentsEdit::showFileSelection()
|
void AttachmentsEdit::showFileSelection()
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <tagparser/mp4/mp4container.h>
|
#include <tagparser/mp4/mp4container.h>
|
||||||
#include <tagparser/abstracttrack.h>
|
#include <tagparser/abstracttrack.h>
|
||||||
#include <tagparser/abstractattachment.h>
|
#include <tagparser/abstractattachment.h>
|
||||||
#include <tagparser/notification.h>
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <c++utilities/chrono/datetime.h>
|
#include <c++utilities/chrono/datetime.h>
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
@ -30,6 +30,7 @@ using namespace std;
|
||||||
using namespace ChronoUtilities;
|
using namespace ChronoUtilities;
|
||||||
using namespace ConversionUtilities;
|
using namespace ConversionUtilities;
|
||||||
using namespace Media;
|
using namespace Media;
|
||||||
|
using namespace Utility;
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
|
||||||
|
@ -115,34 +116,33 @@ private:
|
||||||
QStandardItem *m_item;
|
QStandardItem *m_item;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addNotifications(Media::NotificationList *notifications, QStandardItem *parent)
|
void addDiagMessages(Media::Diagnostics *diag, QStandardItem *parent)
|
||||||
{
|
{
|
||||||
Notification::sortByTime(*notifications);
|
for(const auto &msg : *diag) {
|
||||||
for(Notification ¬ification : *notifications) {
|
|
||||||
QList<QStandardItem *> notificationRow;
|
QList<QStandardItem *> notificationRow;
|
||||||
notificationRow.reserve(3);
|
notificationRow.reserve(3);
|
||||||
|
|
||||||
auto *firstItem = defaultItem(QString::fromUtf8(notification.creationTime().toString().data()));
|
auto *firstItem = defaultItem(QString::fromUtf8(msg.creationTime().toString().data()));
|
||||||
switch(notification.type()) {
|
switch(msg.level()) {
|
||||||
case NotificationType::None:
|
case DiagLevel::None:
|
||||||
break;
|
case DiagLevel::Debug:
|
||||||
case NotificationType::Debug:
|
|
||||||
firstItem->setIcon(FileInfoModel::debugIcon());
|
firstItem->setIcon(FileInfoModel::debugIcon());
|
||||||
break;
|
break;
|
||||||
case NotificationType::Information:
|
case DiagLevel::Information:
|
||||||
firstItem->setIcon(FileInfoModel::informationIcon());
|
firstItem->setIcon(FileInfoModel::informationIcon());
|
||||||
break;
|
break;
|
||||||
case NotificationType::Warning:
|
case DiagLevel::Warning:
|
||||||
firstItem->setIcon(FileInfoModel::warningIcon());
|
firstItem->setIcon(FileInfoModel::warningIcon());
|
||||||
break;
|
break;
|
||||||
case NotificationType::Critical:
|
case DiagLevel::Critical:
|
||||||
|
case DiagLevel::Fatal:
|
||||||
firstItem->setIcon(FileInfoModel::errorIcon());
|
firstItem->setIcon(FileInfoModel::errorIcon());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parent->appendRow(QList<QStandardItem *>()
|
parent->appendRow(QList<QStandardItem *>()
|
||||||
<< firstItem
|
<< firstItem
|
||||||
<< defaultItem(QString::fromUtf8(notification.message().data()))
|
<< defaultItem(QString::fromUtf8(msg.message().data()))
|
||||||
<< defaultItem(QString::fromUtf8(notification.context().data())));
|
<< defaultItem(QString::fromUtf8(msg.context().data())));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,10 +190,9 @@ template<class ElementType, bool isAdditional = false> void addElementNode(const
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new instance with the specified \a fileInfo which might be nullptr.
|
* \brief Constructs a new instance with the specified \a fileInfo which might be nullptr.
|
||||||
*/
|
*/
|
||||||
FileInfoModel::FileInfoModel(Media::MediaFileInfo *fileInfo, QObject *parent) :
|
FileInfoModel::FileInfoModel(QObject *parent) :
|
||||||
QStandardItemModel(parent)
|
QStandardItemModel(parent)
|
||||||
{
|
{
|
||||||
setFileInfo(fileInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FileInfoModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant FileInfoModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
@ -231,10 +230,11 @@ const MediaFileInfo *FileInfoModel::fileInfo() const
|
||||||
* \brief Assigns a Media::MediaFileInfo.
|
* \brief Assigns a Media::MediaFileInfo.
|
||||||
* \remarks Causes updating the internal cache and resets the model.
|
* \remarks Causes updating the internal cache and resets the model.
|
||||||
*/
|
*/
|
||||||
void FileInfoModel::setFileInfo(MediaFileInfo *fileInfo, Media::NotificationList *originalNotifications)
|
void FileInfoModel::setFileInfo(MediaFileInfo &fileInfo, Diagnostics &diag, Diagnostics *diagReparsing)
|
||||||
{
|
{
|
||||||
m_file = fileInfo;
|
m_file = &fileInfo;
|
||||||
m_originalNotifications = originalNotifications;
|
m_diag = &diag;
|
||||||
|
m_diagReparsing = diagReparsing;
|
||||||
updateCache();
|
updateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +271,9 @@ void FileInfoModel::updateCache()
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
clear();
|
clear();
|
||||||
if(m_file) {
|
if(m_file) {
|
||||||
|
// get diag
|
||||||
|
Diagnostics &diag = m_diagReparsing ? *m_diagReparsing : *m_diag;
|
||||||
|
|
||||||
// get container
|
// get container
|
||||||
AbstractContainer *container = m_file->container();
|
AbstractContainer *container = m_file->container();
|
||||||
|
|
||||||
|
@ -327,8 +330,8 @@ void FileInfoModel::updateCache()
|
||||||
containerHelper.appendRow(tr("Document type"), container->documentType());
|
containerHelper.appendRow(tr("Document type"), container->documentType());
|
||||||
containerHelper.appendRow(tr("Document version"), container->doctypeVersion());
|
containerHelper.appendRow(tr("Document version"), container->doctypeVersion());
|
||||||
containerHelper.appendRow(tr("Document read version"), container->doctypeReadVersion());
|
containerHelper.appendRow(tr("Document read version"), container->doctypeReadVersion());
|
||||||
containerHelper.appendRow(tr("Tag position"), Utility::elementPositionToQString(container->determineTagPosition()));
|
containerHelper.appendRow(tr("Tag position"), Utility::elementPositionToQString(container->determineTagPosition(diag)));
|
||||||
containerHelper.appendRow(tr("Index position"), Utility::elementPositionToQString(container->determineIndexPosition()));
|
containerHelper.appendRow(tr("Index position"), Utility::elementPositionToQString(container->determineIndexPosition(diag)));
|
||||||
}
|
}
|
||||||
containerHelper.appendRow(tr("Padding size"), m_file->paddingSize());
|
containerHelper.appendRow(tr("Padding size"), m_file->paddingSize());
|
||||||
|
|
||||||
|
@ -338,7 +341,7 @@ void FileInfoModel::updateCache()
|
||||||
if(!tags.empty()) {
|
if(!tags.empty()) {
|
||||||
auto *tagsItem = defaultItem(tr("Tags"));
|
auto *tagsItem = defaultItem(tr("Tags"));
|
||||||
setItem(++currentRow, tagsItem);
|
setItem(++currentRow, tagsItem);
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 tag(s) assigned", nullptr, static_cast<int>(tags.size())).arg(tags.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 tag(s) assigned", nullptr, trQuandity(tags.size())).arg(tags.size())));
|
||||||
|
|
||||||
for(const Tag *tag : tags) {
|
for(const Tag *tag : tags) {
|
||||||
auto *tagItem = defaultItem(tag->typeName());
|
auto *tagItem = defaultItem(tag->typeName());
|
||||||
|
@ -360,9 +363,9 @@ void FileInfoModel::updateCache()
|
||||||
setItem(++currentRow, tracksItem);
|
setItem(++currentRow, tracksItem);
|
||||||
const string summary(m_file->technicalSummary());
|
const string summary(m_file->technicalSummary());
|
||||||
if(summary.empty()) {
|
if(summary.empty()) {
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 track(s) contained", nullptr, static_cast<int>(tracks.size())).arg(tracks.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 track(s) contained", nullptr, trQuandity(tracks.size())).arg(tracks.size())));
|
||||||
} else {
|
} else {
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 track(s): ", nullptr, static_cast<int>(tracks.size())).arg(tracks.size()) + QString::fromUtf8(summary.data(), summary.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 track(s): ", nullptr, trQuandity(tracks.size())).arg(tracks.size()) + QString::fromUtf8(summary.data(), summary.size())));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t number = 0;
|
size_t number = 0;
|
||||||
|
@ -461,7 +464,7 @@ void FileInfoModel::updateCache()
|
||||||
if(!attachments.empty()) {
|
if(!attachments.empty()) {
|
||||||
auto *attachmentsItem = defaultItem(tr("Attachments"));
|
auto *attachmentsItem = defaultItem(tr("Attachments"));
|
||||||
setItem(++currentRow, attachmentsItem);
|
setItem(++currentRow, attachmentsItem);
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 attachment(s) present", nullptr, attachments.size()).arg(attachments.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 attachment(s) present", nullptr, trQuandity(attachments.size())).arg(attachments.size())));
|
||||||
|
|
||||||
size_t number = 0;
|
size_t number = 0;
|
||||||
for(const AbstractAttachment *attachment : attachments) {
|
for(const AbstractAttachment *attachment : attachments) {
|
||||||
|
@ -524,7 +527,7 @@ void FileInfoModel::updateCache()
|
||||||
if(!editionEntries.empty()) {
|
if(!editionEntries.empty()) {
|
||||||
auto *editionsItem = defaultItem(tr("Editions"));
|
auto *editionsItem = defaultItem(tr("Editions"));
|
||||||
setItem(++currentRow, editionsItem);
|
setItem(++currentRow, editionsItem);
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 edition(s) present", nullptr, editionEntries.size()).arg(editionEntries.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 edition(s) present", nullptr, trQuandity(editionEntries.size())).arg(editionEntries.size())));
|
||||||
size_t editionNumber = 0;
|
size_t editionNumber = 0;
|
||||||
for(const auto &edition : editionEntries) {
|
for(const auto &edition : editionEntries) {
|
||||||
auto *editionItem = defaultItem(tr("Edition #%1").arg(++editionNumber));
|
auto *editionItem = defaultItem(tr("Edition #%1").arg(++editionNumber));
|
||||||
|
@ -554,7 +557,7 @@ void FileInfoModel::updateCache()
|
||||||
if(!chapters.empty()) {
|
if(!chapters.empty()) {
|
||||||
auto *chaptersItem = defaultItem(tr("Chapters"));
|
auto *chaptersItem = defaultItem(tr("Chapters"));
|
||||||
setItem(++currentRow, chaptersItem);
|
setItem(++currentRow, chaptersItem);
|
||||||
setItem(currentRow, 1, defaultItem(tr("%1 chapter(s) present", nullptr, chapters.size()).arg(chapters.size())));
|
setItem(currentRow, 1, defaultItem(tr("%1 chapter(s) present", nullptr, trQuandity(chapters.size())).arg(chapters.size())));
|
||||||
for(const AbstractChapter *chapter : chapters) {
|
for(const AbstractChapter *chapter : chapters) {
|
||||||
addChapter(chapter, chaptersItem);
|
addChapter(chapter, chaptersItem);
|
||||||
}
|
}
|
||||||
|
@ -592,18 +595,14 @@ void FileInfoModel::updateCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
// notifications
|
// notifications
|
||||||
auto currentNotifications = m_file->gatherRelatedNotifications();
|
auto *const diagItem = defaultItem(tr("Diagnostic messages"));
|
||||||
if(!currentNotifications.empty()) {
|
addDiagMessages(m_diag, diagItem);
|
||||||
auto *notificationsItem= defaultItem(m_originalNotifications ? tr("Notifications (reparsing after saving)") : tr("Notifications"));
|
setItem(++currentRow, diagItem);
|
||||||
addNotifications(¤tNotifications, notificationsItem);
|
if (m_diagReparsing) {
|
||||||
setItem(++currentRow, notificationsItem);
|
auto *diagReparsingItem = defaultItem(tr("Diagnostic messages from reparsing"));
|
||||||
|
addDiagMessages(m_diagReparsing, diagReparsingItem);
|
||||||
|
setItem(++currentRow, diagReparsingItem);
|
||||||
}
|
}
|
||||||
if(m_originalNotifications && !m_originalNotifications->empty()) {
|
|
||||||
auto *notificationsItem = defaultItem(tr("Notifications"));
|
|
||||||
addNotifications(m_originalNotifications, notificationsItem);
|
|
||||||
setItem(++currentRow, notificationsItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
class MediaFileInfo;
|
class MediaFileInfo;
|
||||||
class Notification;
|
class Diagnostics;
|
||||||
typedef std::list<Notification> NotificationList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
@ -17,12 +16,12 @@ class FileInfoModel : public QStandardItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit FileInfoModel(Media::MediaFileInfo *fileInfo = nullptr, QObject *parent = nullptr);
|
explicit FileInfoModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
const Media::MediaFileInfo *fileInfo() const;
|
const Media::MediaFileInfo *fileInfo() const;
|
||||||
void setFileInfo(Media::MediaFileInfo *fileInfo, Media::NotificationList *originalNotifications = nullptr);
|
void setFileInfo(Media::MediaFileInfo &fileInfo, Media::Diagnostics &diag, Media::Diagnostics *diagReparsing = nullptr);
|
||||||
|
|
||||||
#if defined(GUI_QTWIDGETS)
|
#if defined(GUI_QTWIDGETS)
|
||||||
static const QIcon &informationIcon();
|
static const QIcon &informationIcon();
|
||||||
|
@ -36,7 +35,8 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Media::MediaFileInfo *m_file;
|
Media::MediaFileInfo *m_file;
|
||||||
Media::NotificationList *m_originalNotifications;
|
Media::Diagnostics *m_diag;
|
||||||
|
Media::Diagnostics *m_diagReparsing;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "./notificationmodel.h"
|
#include "./notificationmodel.h"
|
||||||
|
|
||||||
|
#include "../misc/utility.h"
|
||||||
|
|
||||||
#include <c++utilities/chrono/datetime.h>
|
#include <c++utilities/chrono/datetime.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -9,14 +11,15 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ChronoUtilities;
|
using namespace ChronoUtilities;
|
||||||
using namespace Media;
|
using namespace Media;
|
||||||
|
using namespace Utility;
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
|
||||||
NotificationModel::NotificationModel(QObject *parent) :
|
DiagModel::DiagModel(QObject *parent) :
|
||||||
QAbstractListModel(parent)
|
QAbstractListModel(parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QVariant NotificationModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant DiagModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
switch(orientation) {
|
switch(orientation) {
|
||||||
case Qt::Horizontal:
|
case Qt::Horizontal:
|
||||||
|
@ -41,7 +44,7 @@ QVariant NotificationModel::headerData(int section, Qt::Orientation orientation,
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
int NotificationModel::columnCount(const QModelIndex &parent) const
|
int DiagModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if(!parent.isValid()) {
|
if(!parent.isValid()) {
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -49,27 +52,27 @@ int NotificationModel::columnCount(const QModelIndex &parent) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NotificationModel::rowCount(const QModelIndex &parent) const
|
int DiagModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if(!parent.isValid()) {
|
if(!parent.isValid()) {
|
||||||
return m_notifications.size();
|
return sizeToInt(m_diag.size());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags NotificationModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags DiagModel::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
return QAbstractListModel::flags(index);
|
return QAbstractListModel::flags(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant NotificationModel::data(const QModelIndex &index, int role) const
|
QVariant DiagModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if(index.isValid() && index.row() < m_notifications.size()) {
|
if(index.isValid() && index.row() >= 0 && static_cast<std::size_t>(index.row()) < m_diag.size()) {
|
||||||
switch(role) {
|
switch(role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case 0: {
|
case 0: {
|
||||||
const string &context = m_notifications.at(index.row()).context();
|
const string &context = m_diag[static_cast<std::size_t>(index.row())].context();
|
||||||
if(context.empty()) {
|
if(context.empty()) {
|
||||||
return tr("unspecified");
|
return tr("unspecified");
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,9 +80,9 @@ QVariant NotificationModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
return QString::fromUtf8(m_notifications.at(index.row()).message().c_str());
|
return QString::fromUtf8(m_diag[static_cast<std::size_t>(index.row())].message().c_str());
|
||||||
case 2:
|
case 2:
|
||||||
return QString::fromUtf8(m_notifications.at(index.row()).creationTime().toString(DateTimeOutputFormat::DateAndTime, true).c_str());
|
return QString::fromUtf8(m_diag[static_cast<std::size_t>(index.row())].creationTime().toString(DateTimeOutputFormat::DateAndTime, true).c_str());
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -87,18 +90,19 @@ QVariant NotificationModel::data(const QModelIndex &index, int role) const
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole:
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case 0:
|
case 0:
|
||||||
switch(m_notifications.at(index.row()).type()) {
|
switch(m_diag[static_cast<std::size_t>(index.row())].level()) {
|
||||||
case NotificationType::Information:
|
case DiagLevel::None:
|
||||||
return informationIcon();
|
case DiagLevel::Debug:
|
||||||
case NotificationType::Warning:
|
|
||||||
return warningIcon();
|
|
||||||
case NotificationType::Critical:
|
|
||||||
return errorIcon();
|
|
||||||
case NotificationType::Debug:
|
|
||||||
return debugIcon();
|
return debugIcon();
|
||||||
default:
|
case DiagLevel::Information:
|
||||||
;
|
return informationIcon();
|
||||||
|
case DiagLevel::Warning:
|
||||||
|
return warningIcon();
|
||||||
|
case DiagLevel::Critical:
|
||||||
|
case DiagLevel::Fatal:
|
||||||
|
return errorIcon();
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -110,42 +114,37 @@ QVariant NotificationModel::data(const QModelIndex &index, int role) const
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<Notification> &NotificationModel::notifications() const
|
const Diagnostics &DiagModel::diagnostics() const
|
||||||
{
|
{
|
||||||
return m_notifications;
|
return m_diag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationModel::setNotifications(const QList<Notification> ¬ifications)
|
void DiagModel::setDiagnostics(const Media::Diagnostics ¬ifications)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_notifications = notifications;
|
m_diag = notifications;
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationModel::setNotifications(const NotificationList ¬ifications)
|
const QIcon &DiagModel::informationIcon()
|
||||||
{
|
|
||||||
setNotifications(QList<Notification>::fromStdList(notifications));
|
|
||||||
}
|
|
||||||
|
|
||||||
const QIcon &NotificationModel::informationIcon()
|
|
||||||
{
|
{
|
||||||
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QIcon &NotificationModel::warningIcon()
|
const QIcon &DiagModel::warningIcon()
|
||||||
{
|
{
|
||||||
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QIcon &NotificationModel::errorIcon()
|
const QIcon &DiagModel::errorIcon()
|
||||||
{
|
{
|
||||||
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
static const QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QIcon &NotificationModel::debugIcon()
|
const QIcon &DiagModel::debugIcon()
|
||||||
{
|
{
|
||||||
static const QIcon icon = QIcon(QStringLiteral("/images/bug"));
|
static const QIcon icon = QIcon(QStringLiteral("/images/bug"));
|
||||||
return icon;
|
return icon;
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#ifndef NOTIFICATIONMODEL_H
|
#ifndef NOTIFICATIONMODEL_H
|
||||||
#define NOTIFICATIONMODEL_H
|
#define NOTIFICATIONMODEL_H
|
||||||
|
|
||||||
#include <tagparser/notification.h>
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
namespace QtGui {
|
namespace QtGui {
|
||||||
|
|
||||||
class NotificationModel : public QAbstractListModel
|
class DiagModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit NotificationModel(QObject *parent = nullptr);
|
explicit DiagModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
int columnCount(const QModelIndex &parent) const;
|
int columnCount(const QModelIndex &parent) const;
|
||||||
|
@ -19,9 +19,8 @@ public:
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
const QList<Media::Notification> ¬ifications() const;
|
const Media::Diagnostics &diagnostics() const;
|
||||||
void setNotifications(const QList<Media::Notification> ¬ifications);
|
void setDiagnostics(const Media::Diagnostics &diagnostics);
|
||||||
void setNotifications(const Media::NotificationList ¬ifications);
|
|
||||||
|
|
||||||
static const QIcon &informationIcon();
|
static const QIcon &informationIcon();
|
||||||
static const QIcon &warningIcon();
|
static const QIcon &warningIcon();
|
||||||
|
@ -33,7 +32,7 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Media::Notification> m_notifications;
|
Media::Diagnostics m_diag;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <tagparser/id3/id3v2frame.h>
|
#include <tagparser/id3/id3v2frame.h>
|
||||||
#include <tagparser/vorbis/vorbiscomment.h>
|
#include <tagparser/vorbis/vorbiscomment.h>
|
||||||
#include <tagparser/vorbis/vorbiscommentfield.h>
|
#include <tagparser/vorbis/vorbiscommentfield.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <qtutilities/misc/conversion.h>
|
#include <qtutilities/misc/conversion.h>
|
||||||
|
|
||||||
|
@ -318,8 +319,10 @@ void PicturePreviewSelection::addOfSelectedType(const QString &path)
|
||||||
TagValue &selectedCover = m_values[m_currentTypeIndex];
|
TagValue &selectedCover = m_values[m_currentTypeIndex];
|
||||||
try {
|
try {
|
||||||
MediaFileInfo fileInfo(toNativeFileName(path).constData());
|
MediaFileInfo fileInfo(toNativeFileName(path).constData());
|
||||||
|
Diagnostics diag;
|
||||||
fileInfo.open(true);
|
fileInfo.open(true);
|
||||||
fileInfo.parseContainerFormat();
|
fileInfo.parseContainerFormat(diag);
|
||||||
|
// TODO: show diagnostic messages
|
||||||
auto mimeType = QString::fromUtf8(fileInfo.mimeType());
|
auto mimeType = QString::fromUtf8(fileInfo.mimeType());
|
||||||
bool ok;
|
bool ok;
|
||||||
mimeType = QInputDialog::getText(this, tr("Enter/confirm mime type"), tr("Confirm or enter the mime type of the selected file."), QLineEdit::Normal, mimeType, &ok);
|
mimeType = QInputDialog::getText(this, tr("Enter/confirm mime type"), tr("Confirm or enter the mime type of the selected file."), QLineEdit::Normal, mimeType, &ok);
|
||||||
|
|
|
@ -164,7 +164,7 @@ TagEditorWidget::~TagEditorWidget()
|
||||||
const QByteArray &TagEditorWidget::generateFileInfoHtml()
|
const QByteArray &TagEditorWidget::generateFileInfoHtml()
|
||||||
{
|
{
|
||||||
if(m_fileInfoHtml.isEmpty()) {
|
if(m_fileInfoHtml.isEmpty()) {
|
||||||
m_fileInfoHtml = HtmlInfo::generateInfo(m_fileInfo, m_originalNotifications);
|
m_fileInfoHtml = HtmlInfo::generateInfo(m_fileInfo, m_diag, m_diagReparsing);
|
||||||
}
|
}
|
||||||
return m_fileInfoHtml;
|
return m_fileInfoHtml;
|
||||||
}
|
}
|
||||||
|
@ -627,7 +627,8 @@ void TagEditorWidget::initInfoView()
|
||||||
m_ui->tagSplitter->addWidget(m_infoTreeView);
|
m_ui->tagSplitter->addWidget(m_infoTreeView);
|
||||||
}
|
}
|
||||||
if(!m_infoModel) {
|
if(!m_infoModel) {
|
||||||
m_infoModel = new FileInfoModel(m_fileInfo.isOpen() ? &m_fileInfo : nullptr, this);
|
m_infoModel = new FileInfoModel(this);
|
||||||
|
m_infoModel->setFileInfo(m_fileInfo, m_diag, m_makingResultsAvailable ? &m_diagReparsing : nullptr);
|
||||||
m_infoTreeView->setModel(m_infoModel);
|
m_infoTreeView->setModel(m_infoModel);
|
||||||
m_infoTreeView->setHeaderHidden(true);
|
m_infoTreeView->setHeaderHidden(true);
|
||||||
m_infoTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
m_infoTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
@ -658,7 +659,7 @@ void TagEditorWidget::updateInfoView()
|
||||||
|
|
||||||
// update info model if present
|
// update info model if present
|
||||||
if(m_infoModel) {
|
if(m_infoModel) {
|
||||||
m_infoModel->setFileInfo(m_fileInfo.isOpen() ? &m_fileInfo : nullptr); // resets the model
|
m_infoModel->setFileInfo(m_fileInfo, m_diag, m_makingResultsAvailable ? &m_diagReparsing : nullptr); // resets the model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,8 +759,6 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
// clear previous results and status
|
// clear previous results and status
|
||||||
m_tags.clear();
|
m_tags.clear();
|
||||||
m_fileInfo.clearParsingResults();
|
m_fileInfo.clearParsingResults();
|
||||||
m_fileInfo.invalidateStatus();
|
|
||||||
m_fileInfo.invalidateNotifications();
|
|
||||||
if(!sameFile) {
|
if(!sameFile) {
|
||||||
// close last file if possibly open
|
// close last file if possibly open
|
||||||
m_fileInfo.close();
|
m_fileInfo.close();
|
||||||
|
@ -768,25 +767,26 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
m_fileInfo.setSaveFilePath(string());
|
m_fileInfo.setSaveFilePath(string());
|
||||||
m_fileInfo.setPath(toNativeFileName(path).data());
|
m_fileInfo.setPath(toNativeFileName(path).data());
|
||||||
// update file name and directory
|
// update file name and directory
|
||||||
QFileInfo fileInfo(path);
|
const QFileInfo fileInfo(path);
|
||||||
m_lastDir = m_currentDir;
|
m_lastDir = m_currentDir;
|
||||||
m_currentDir = fileInfo.absolutePath();
|
m_currentDir = fileInfo.absolutePath();
|
||||||
m_fileName = fileInfo.fileName();
|
m_fileName = fileInfo.fileName();
|
||||||
}
|
}
|
||||||
// update availability of making results
|
// write diagnostics to m_diagReparsing if making results are avalable
|
||||||
m_makingResultsAvailable &= sameFile;
|
m_makingResultsAvailable &= sameFile;
|
||||||
if(!m_makingResultsAvailable) {
|
Diagnostics &diag = m_makingResultsAvailable ? m_diagReparsing : m_diag;
|
||||||
m_originalNotifications.clear();
|
// clear diagnostics
|
||||||
}
|
diag.clear();
|
||||||
|
m_diagReparsing.clear();
|
||||||
// show filename
|
// show filename
|
||||||
m_ui->fileNameLabel->setText(m_fileName);
|
m_ui->fileNameLabel->setText(m_fileName);
|
||||||
// define function to parse the file
|
// define function to parse the file
|
||||||
auto startThread = [this] {
|
const auto startThread = [this, &diag] {
|
||||||
char result;
|
char result;
|
||||||
try { // credits for this nesting go to GCC regression 66145
|
try { // credits for this nesting go to GCC regression 66145
|
||||||
try {
|
try {
|
||||||
|
// try to open with write access
|
||||||
try {
|
try {
|
||||||
// try to open with write access
|
|
||||||
m_fileInfo.reopen(false);
|
m_fileInfo.reopen(false);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
::IoUtilities::catchIoFailure();
|
::IoUtilities::catchIoFailure();
|
||||||
|
@ -794,7 +794,7 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
m_fileInfo.reopen(true);
|
m_fileInfo.reopen(true);
|
||||||
}
|
}
|
||||||
m_fileInfo.setForceFullParse(Settings::values().editor.forceFullParse);
|
m_fileInfo.setForceFullParse(Settings::values().editor.forceFullParse);
|
||||||
m_fileInfo.parseEverything();
|
m_fileInfo.parseEverything(diag);
|
||||||
result = ParsingSuccessful;
|
result = ParsingSuccessful;
|
||||||
} catch(const Failure &) {
|
} catch(const Failure &) {
|
||||||
// the file has been opened; parsing notifications will be shown in the info box
|
// the file has been opened; parsing notifications will be shown in the info box
|
||||||
|
@ -806,21 +806,19 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
|
||||||
result = IoError;
|
result = IoError;
|
||||||
}
|
}
|
||||||
} catch(const exception &e) {
|
} catch(const exception &e) {
|
||||||
m_fileInfo.addNotification(Media::NotificationType::Critical, string("Something completely unexpected happened: ") + e.what(), "parsing");
|
diag.emplace_back(Media::DiagLevel::Critical, argsToString("Something completely unexpected happened: ", + e.what()), "parsing");
|
||||||
result = FatalParsingError;
|
result = FatalParsingError;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
m_fileInfo.addNotification(Media::NotificationType::Critical, "Something completely unexpected happened", "parsing");
|
diag.emplace_back(Media::DiagLevel::Critical, "Something completely unexpected happened", "parsing");
|
||||||
result = FatalParsingError;
|
result = FatalParsingError;
|
||||||
}
|
}
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result));
|
QMetaObject::invokeMethod(this, "showFile", Qt::QueuedConnection, Q_ARG(char, result));
|
||||||
};
|
};
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
m_fileOperationOngoing = true;
|
m_fileOperationOngoing = true;
|
||||||
// perform the operation concurrently
|
// perform the operation concurrently
|
||||||
QtConcurrent::run(startThread);
|
QtConcurrent::run(startThread);
|
||||||
// inform user
|
// inform user
|
||||||
static const QString statusMsg(tr("The file is beeing parsed ..."));
|
static const auto statusMsg(tr("The file is beeing parsed ..."));
|
||||||
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
|
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
|
||||||
m_ui->parsingNotificationWidget->setText(statusMsg);
|
m_ui->parsingNotificationWidget->setText(statusMsg);
|
||||||
m_ui->parsingNotificationWidget->setVisible(true); // ensure widget is visible!
|
m_ui->parsingNotificationWidget->setVisible(true); // ensure widget is visible!
|
||||||
|
@ -899,10 +897,13 @@ void TagEditorWidget::showFile(char result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// show parsing status/result using parsing notification widget
|
// show parsing status/result using parsing notification widget
|
||||||
auto worstNotificationType = m_fileInfo.worstNotificationTypeIncludingRelatedObjects();
|
auto diagLevel = m_diag.level();
|
||||||
if(worstNotificationType >= Media::NotificationType::Critical) {
|
if (diagLevel < worstDiagLevel) {
|
||||||
// we catched no exception, but there are critical notifications
|
diagLevel |= m_diagReparsing.level();
|
||||||
// -> treat critical notifications as fatal parsing errors
|
}
|
||||||
|
if(diagLevel >= DiagLevel::Critical) {
|
||||||
|
// we catched no exception, but there are critical diag messages
|
||||||
|
// -> treat those as fatal parsing errors
|
||||||
result = LoadingResult::FatalParsingError;
|
result = LoadingResult::FatalParsingError;
|
||||||
}
|
}
|
||||||
switch(result) {
|
switch(result) {
|
||||||
|
@ -915,12 +916,12 @@ void TagEditorWidget::showFile(char result)
|
||||||
m_ui->parsingNotificationWidget->setText(tr("File couldn't be parsed correctly."));
|
m_ui->parsingNotificationWidget->setText(tr("File couldn't be parsed correctly."));
|
||||||
}
|
}
|
||||||
bool multipleSegmentsNotTested = m_fileInfo.containerFormat() == ContainerFormat::Matroska && m_fileInfo.container()->segmentCount() > 1;
|
bool multipleSegmentsNotTested = m_fileInfo.containerFormat() == ContainerFormat::Matroska && m_fileInfo.container()->segmentCount() > 1;
|
||||||
if(worstNotificationType >= Media::NotificationType::Critical) {
|
if(diagLevel >= Media::DiagLevel::Critical) {
|
||||||
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Critical);
|
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Critical);
|
||||||
m_ui->parsingNotificationWidget->appendLine(tr("There are critical parsing notifications."));
|
m_ui->parsingNotificationWidget->appendLine(tr("Errors occured."));
|
||||||
} else if(worstNotificationType == Media::NotificationType::Warning || m_fileInfo.isReadOnly() || !m_fileInfo.areTagsSupported() || multipleSegmentsNotTested) {
|
} else if(diagLevel == Media::DiagLevel::Warning || m_fileInfo.isReadOnly() || !m_fileInfo.areTagsSupported() || multipleSegmentsNotTested) {
|
||||||
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Warning);
|
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Warning);
|
||||||
if(worstNotificationType == Media::NotificationType::Warning) {
|
if(diagLevel == Media::DiagLevel::Warning) {
|
||||||
m_ui->parsingNotificationWidget->appendLine(tr("There are warnings."));
|
m_ui->parsingNotificationWidget->appendLine(tr("There are warnings."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1099,21 +1100,26 @@ bool TagEditorWidget::startSaving()
|
||||||
m_fileInfo.setMinPadding(settings.minPadding);
|
m_fileInfo.setMinPadding(settings.minPadding);
|
||||||
m_fileInfo.setMaxPadding(settings.maxPadding);
|
m_fileInfo.setMaxPadding(settings.maxPadding);
|
||||||
m_fileInfo.setPreferredPadding(settings.preferredPadding);
|
m_fileInfo.setPreferredPadding(settings.preferredPadding);
|
||||||
// define functions to show the saving progress and to actually applying the changes
|
const auto startThread = [this] {
|
||||||
auto showProgress = [this] (StatusProvider &sender) -> void {
|
// define functions to show the saving progress and to actually applying the changes
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setPercentage", Qt::QueuedConnection, Q_ARG(int, static_cast<int>(sender.currentPercentage() * 100.0)));
|
const auto showPercentage([this] (const AbortableProgressFeedback &progress) {
|
||||||
if(m_abortClicked) {
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setPercentage", Qt::QueuedConnection, Q_ARG(int, progress.stepPercentage()));
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, tr("Cancelling ...")));
|
});
|
||||||
m_fileInfo.tryToAbort();
|
const auto showStep([this] (AbortableProgressFeedback &progress) {
|
||||||
} else {
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setPercentage", Qt::QueuedConnection, Q_ARG(int, progress.stepPercentage()));
|
||||||
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(sender.currentStatus())));
|
if(m_abortClicked) {
|
||||||
}
|
progress.tryToAbort();
|
||||||
};
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, tr("Cancelling ...")));
|
||||||
auto startThread = [this] {
|
} else {
|
||||||
|
QMetaObject::invokeMethod(m_ui->makingNotificationWidget, "setText", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(progress.step())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AbortableProgressFeedback progress(std::move(showStep), std::move(showPercentage));
|
||||||
|
|
||||||
bool processingError = false, ioError = false;
|
bool processingError = false, ioError = false;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
m_fileInfo.applyChanges();
|
m_fileInfo.applyChanges(m_diag, progress);
|
||||||
} catch(const Failure &) {
|
} catch(const Failure &) {
|
||||||
processingError = true;
|
processingError = true;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
|
@ -1121,17 +1127,14 @@ bool TagEditorWidget::startSaving()
|
||||||
ioError = true;
|
ioError = true;
|
||||||
}
|
}
|
||||||
} catch(const exception &e) {
|
} catch(const exception &e) {
|
||||||
m_fileInfo.addNotification(Media::NotificationType::Critical, string("Something completely unexpected happened: ") + e.what(), "making");
|
m_diag.emplace_back(Media::DiagLevel::Critical, argsToString("Something completely unexpected happened: ", e.what()), "making");
|
||||||
processingError = true;
|
processingError = true;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
m_fileInfo.addNotification(Media::NotificationType::Critical, "Something completely unexpected happened", "making");
|
m_diag.emplace_back(Media::DiagLevel::Critical, "Something completely unexpected happened", "making");
|
||||||
processingError = true;
|
processingError = true;
|
||||||
}
|
}
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
QMetaObject::invokeMethod(this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError));
|
QMetaObject::invokeMethod(this, "showSavingResult", Qt::QueuedConnection, Q_ARG(bool, processingError), Q_ARG(bool, ioError));
|
||||||
};
|
};
|
||||||
m_fileInfo.unregisterAllCallbacks();
|
|
||||||
m_fileInfo.registerCallback(showProgress);
|
|
||||||
m_fileOperationOngoing = true;
|
m_fileOperationOngoing = true;
|
||||||
// use another thread to perform the operation
|
// use another thread to perform the operation
|
||||||
QtConcurrent::run(startThread);
|
QtConcurrent::run(startThread);
|
||||||
|
@ -1155,17 +1158,17 @@ void TagEditorWidget::showSavingResult(bool processingError, bool ioError)
|
||||||
m_ui->makingNotificationWidget->setPercentage(-1);
|
m_ui->makingNotificationWidget->setPercentage(-1);
|
||||||
m_ui->makingNotificationWidget->setHidden(false);
|
m_ui->makingNotificationWidget->setHidden(false);
|
||||||
m_makingResultsAvailable = true;
|
m_makingResultsAvailable = true;
|
||||||
m_originalNotifications = m_fileInfo.gatherRelatedNotifications();
|
|
||||||
if(!processingError && !ioError) {
|
if(!processingError && !ioError) {
|
||||||
// display status messages
|
// display status messages
|
||||||
QString statusMsg;
|
QString statusMsg;
|
||||||
size_t critical = 0, warnings = 0;
|
size_t critical = 0, warnings = 0;
|
||||||
for(const Notification ¬ification : m_originalNotifications) {
|
for(const auto &msg : m_diag) {
|
||||||
switch(notification.type()) {
|
switch(msg.level()) {
|
||||||
case Media::NotificationType::Critical:
|
case Media::DiagLevel::Fatal:
|
||||||
|
case Media::DiagLevel::Critical:
|
||||||
++critical;
|
++critical;
|
||||||
break;
|
break;
|
||||||
case Media::NotificationType::Warning:
|
case Media::DiagLevel::Warning:
|
||||||
++warnings;
|
++warnings;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1174,12 +1177,12 @@ void TagEditorWidget::showSavingResult(bool processingError, bool ioError)
|
||||||
}
|
}
|
||||||
if(warnings || critical) {
|
if(warnings || critical) {
|
||||||
if(critical) {
|
if(critical) {
|
||||||
statusMsg = tr("The tags have been saved, but there is/are %1 warning(s) ", 0, warnings).arg(warnings);
|
statusMsg = tr("The tags have been saved, but there is/are %1 warning(s) ", nullptr, trQuandity(warnings)).arg(warnings);
|
||||||
statusMsg.append(tr("and %1 error(s).", 0, critical).arg(critical));
|
statusMsg.append(tr("and %1 error(s).", nullptr, trQuandity(critical)).arg(critical));
|
||||||
} else {
|
} else {
|
||||||
statusMsg = tr("The tags have been saved, but there is/are %1 warning(s).", 0, warnings).arg(warnings);
|
statusMsg = tr("The tags have been saved, but there is/are %1 warning(s).", nullptr, trQuandity(warnings)).arg(warnings);
|
||||||
}
|
}
|
||||||
m_ui->makingNotificationWidget->setNotificationType(critical > 0 ? NotificationType::Critical : NotificationType::Warning);
|
m_ui->makingNotificationWidget->setNotificationType(critical ? NotificationType::Critical : NotificationType::Warning);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
statusMsg = tr("The tags have been saved.");
|
statusMsg = tr("The tags have been saved.");
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "./webviewdefs.h"
|
#include "./webviewdefs.h"
|
||||||
|
|
||||||
#include <tagparser/mediafileinfo.h>
|
#include <tagparser/mediafileinfo.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
@ -49,7 +50,7 @@ public:
|
||||||
const QString ¤tPath() const;
|
const QString ¤tPath() const;
|
||||||
const QString ¤tDir() const;
|
const QString ¤tDir() const;
|
||||||
Media::MediaFileInfo &fileInfo();
|
Media::MediaFileInfo &fileInfo();
|
||||||
Media::NotificationList &originalNotifications();
|
const Media::Diagnostics &diagnostics() const;
|
||||||
bool isTagEditShown() const;
|
bool isTagEditShown() const;
|
||||||
const QByteArray &fileInfoHtml() const;
|
const QByteArray &fileInfoHtml() const;
|
||||||
const QByteArray &generateFileInfoHtml();
|
const QByteArray &generateFileInfoHtml();
|
||||||
|
@ -150,9 +151,10 @@ private:
|
||||||
QString m_lastDir;
|
QString m_lastDir;
|
||||||
QString m_saveFilePath;
|
QString m_saveFilePath;
|
||||||
// status
|
// status
|
||||||
|
Media::Diagnostics m_diag;
|
||||||
|
Media::Diagnostics m_diagReparsing;
|
||||||
bool m_nextFileAfterSaving;
|
bool m_nextFileAfterSaving;
|
||||||
bool m_makingResultsAvailable;
|
bool m_makingResultsAvailable;
|
||||||
Media::NotificationList m_originalNotifications;
|
|
||||||
bool m_abortClicked;
|
bool m_abortClicked;
|
||||||
bool m_fileOperationOngoing;
|
bool m_fileOperationOngoing;
|
||||||
};
|
};
|
||||||
|
@ -191,11 +193,11 @@ inline Media::MediaFileInfo &TagEditorWidget::fileInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the original notifications.
|
* \brief Returns the diagnostic messages.
|
||||||
*/
|
*/
|
||||||
inline Media::NotificationList &TagEditorWidget::originalNotifications()
|
inline const Media::Diagnostics &TagEditorWidget::diagnostics() const
|
||||||
{
|
{
|
||||||
return m_originalNotifications;
|
return m_diag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <tagparser/mp4/mp4container.h>
|
#include <tagparser/mp4/mp4container.h>
|
||||||
#include <tagparser/abstracttrack.h>
|
#include <tagparser/abstracttrack.h>
|
||||||
#include <tagparser/abstractattachment.h>
|
#include <tagparser/abstractattachment.h>
|
||||||
#include <tagparser/notification.h>
|
|
||||||
|
|
||||||
#include <qtutilities/resources/resources.h>
|
#include <qtutilities/resources/resources.h>
|
||||||
|
|
||||||
|
@ -56,6 +55,7 @@ using namespace std;
|
||||||
using namespace ConversionUtilities;
|
using namespace ConversionUtilities;
|
||||||
using namespace ChronoUtilities;
|
using namespace ChronoUtilities;
|
||||||
using namespace Media;
|
using namespace Media;
|
||||||
|
using namespace Utility;
|
||||||
|
|
||||||
namespace HtmlInfo {
|
namespace HtmlInfo {
|
||||||
|
|
||||||
|
@ -308,11 +308,12 @@ class Generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Generator(const MediaFileInfo &file, NotificationList &originalNotifications) :
|
Generator(const MediaFileInfo &file, Diagnostics &diag, Diagnostics &diagReparsing) :
|
||||||
m_writer(&m_res),
|
m_writer(&m_res),
|
||||||
m_rowMaker(m_writer),
|
m_rowMaker(m_writer),
|
||||||
m_file(file),
|
m_file(file),
|
||||||
originalNotifications(originalNotifications)
|
m_diag(diag),
|
||||||
|
m_diagReparsing(diagReparsing)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QString mkStyle()
|
QString mkStyle()
|
||||||
|
@ -808,33 +809,33 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkNotifications(NotificationList ¬ifications, bool reparsing = false)
|
void mkNotifications(Diagnostics &diag, bool reparsing = false)
|
||||||
{
|
{
|
||||||
if(notifications.size()) {
|
if (diag.empty()) {
|
||||||
startTableSection();
|
return;
|
||||||
const QString moreId(reparsing ? QStringLiteral("notificationsReparsingMore") : QStringLiteral("notificationsMore"));
|
}
|
||||||
m_rowMaker.startRow(reparsing ? QCoreApplication::translate("HtmlInfo", "Notifications (reparsing after saving)") : QCoreApplication::translate("HtmlInfo", "Notifications"));
|
startTableSection();
|
||||||
m_writer.writeCharacters(QCoreApplication::translate("HtmlInfo", "%1 notification(s) available", 0, static_cast<int>(notifications.size())).arg(notifications.size()));
|
const QString moreId(reparsing ? QStringLiteral("notificationsReparsingMore") : QStringLiteral("notificationsMore"));
|
||||||
mkSpace();
|
m_rowMaker.startRow(reparsing ? QCoreApplication::translate("HtmlInfo", "Notifications (reparsing after saving)") : QCoreApplication::translate("HtmlInfo", "Notifications"));
|
||||||
mkDetailsLink(moreId, QCoreApplication::translate("HtmlInfo", "show notifications"));
|
m_writer.writeCharacters(QCoreApplication::translate("HtmlInfo", "%1 notification(s) available", nullptr, trQuandity(diag.size())).arg(diag.size()));
|
||||||
m_rowMaker.endRow();
|
mkSpace();
|
||||||
m_writer.writeEndElement();
|
mkDetailsLink(moreId, QCoreApplication::translate("HtmlInfo", "show notifications"));
|
||||||
|
m_rowMaker.endRow();
|
||||||
|
m_writer.writeEndElement();
|
||||||
|
|
||||||
startExtendedTableSection(moreId);
|
startExtendedTableSection(moreId);
|
||||||
m_rowMaker.startHorizontalSubTab(QString(), QStringList() << QString() << QCoreApplication::translate("HtmlInfo", "Context") << QCoreApplication::translate("HtmlInfo", "Message") << QCoreApplication::translate("HtmlInfo", "Time"));
|
m_rowMaker.startHorizontalSubTab(QString(), QStringList({QString(), QCoreApplication::translate("HtmlInfo", "Context"), QCoreApplication::translate("HtmlInfo", "Message"), QCoreApplication::translate("HtmlInfo", "Time")}));
|
||||||
Notification::sortByTime(notifications);
|
for(const auto &msg : diag) {
|
||||||
for(const Notification ¬ification : notifications) {
|
m_writer.writeStartElement(QStringLiteral("tr"));
|
||||||
m_writer.writeStartElement(QStringLiteral("tr"));
|
m_writer.writeEmptyElement(QStringLiteral("td"));
|
||||||
m_writer.writeEmptyElement(QStringLiteral("td"));
|
m_writer.writeAttribute(QStringLiteral("class"), qstr(msg.levelName()));
|
||||||
m_writer.writeAttribute(QStringLiteral("class"), qstr(notification.typeName()));
|
m_writer.writeTextElement(QStringLiteral("td"), qstr(msg.context()));
|
||||||
m_writer.writeTextElement(QStringLiteral("td"), qstr(notification.context()));
|
m_writer.writeTextElement(QStringLiteral("td"), qstr(msg.message()));
|
||||||
m_writer.writeTextElement(QStringLiteral("td"), qstr(notification.message()));
|
m_writer.writeTextElement(QStringLiteral("td"), qstr(msg.creationTime().toString(DateTimeOutputFormat::DateAndTime, false)));
|
||||||
m_writer.writeTextElement(QStringLiteral("td"), qstr(notification.creationTime().toString(DateTimeOutputFormat::DateAndTime, false)));
|
|
||||||
m_writer.writeEndElement();
|
|
||||||
}
|
|
||||||
m_rowMaker.endSubTab();
|
|
||||||
m_writer.writeEndElement();
|
m_writer.writeEndElement();
|
||||||
}
|
}
|
||||||
|
m_rowMaker.endSubTab();
|
||||||
|
m_writer.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkDoc()
|
void mkDoc()
|
||||||
|
@ -932,8 +933,8 @@ public:
|
||||||
if(m_file.paddingSize()) {
|
if(m_file.paddingSize()) {
|
||||||
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Padding size"), QStringLiteral("%1 (%2 %)").arg(qstr(dataSizeToString(m_file.paddingSize(), true))).arg(static_cast<double>(m_file.paddingSize()) / m_file.size() * 100.0, 0, 'g', 2));
|
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Padding size"), QStringLiteral("%1 (%2 %)").arg(qstr(dataSizeToString(m_file.paddingSize(), true))).arg(static_cast<double>(m_file.paddingSize()) / m_file.size() * 100.0, 0, 'g', 2));
|
||||||
}
|
}
|
||||||
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Tag position"), container->determineTagPosition());
|
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Tag position"), container->determineTagPosition(m_diagReparsing));
|
||||||
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Index position"), container->determineIndexPosition());
|
rowMaker.mkRow(QCoreApplication::translate("HtmlInfo", "Index position"), container->determineIndexPosition(m_diagReparsing));
|
||||||
|
|
||||||
m_writer.writeEndElement();
|
m_writer.writeEndElement();
|
||||||
}
|
}
|
||||||
|
@ -1110,11 +1111,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// notifications
|
// notifications
|
||||||
auto currentNotifications = m_file.gatherRelatedNotifications();
|
mkNotifications(m_diag);
|
||||||
mkNotifications(currentNotifications, !originalNotifications.empty());
|
mkNotifications(m_diagReparsing, true);
|
||||||
if(!originalNotifications.empty()) {
|
|
||||||
mkNotifications(originalNotifications);
|
|
||||||
}
|
|
||||||
|
|
||||||
// </table> </body> </html>
|
// </table> </body> </html>
|
||||||
|
|
||||||
|
@ -1132,7 +1130,8 @@ private:
|
||||||
QByteArray m_res;
|
QByteArray m_res;
|
||||||
RowMaker m_rowMaker;
|
RowMaker m_rowMaker;
|
||||||
const MediaFileInfo &m_file;
|
const MediaFileInfo &m_file;
|
||||||
NotificationList &originalNotifications;
|
Diagnostics &m_diag;
|
||||||
|
Diagnostics &m_diagReparsing;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1143,9 +1142,9 @@ private:
|
||||||
* A QGuiApplication instance should be available for setting fonts.
|
* A QGuiApplication instance should be available for setting fonts.
|
||||||
* A QApplication instance should be available for standard icons.
|
* A QApplication instance should be available for standard icons.
|
||||||
*/
|
*/
|
||||||
QByteArray generateInfo(const MediaFileInfo &file, NotificationList &originalNotifications)
|
QByteArray generateInfo(const MediaFileInfo &file, Diagnostics &diag, Diagnostics &diagReparsing)
|
||||||
{
|
{
|
||||||
Generator gen(file, originalNotifications);
|
Generator gen(file, diag, diagReparsing);
|
||||||
gen.mkDoc();
|
gen.mkDoc();
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
QFile test(QStringLiteral("/tmp/test.xhtml"));
|
QFile test(QStringLiteral("/tmp/test.xhtml"));
|
||||||
|
|
|
@ -7,13 +7,12 @@
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
class MediaFileInfo;
|
class MediaFileInfo;
|
||||||
class Notification;
|
class Diagnostics;
|
||||||
typedef std::list<Notification> NotificationList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace HtmlInfo {
|
namespace HtmlInfo {
|
||||||
|
|
||||||
QByteArray generateInfo(const Media::MediaFileInfo &file, Media::NotificationList &originalNotifications);
|
QByteArray generateInfo(const Media::MediaFileInfo &file, Media::Diagnostics &diag, Media::Diagnostics &diagReparsing);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,16 @@ void parseFileName(const QString &fileName, QString &title, int &trackNumber);
|
||||||
QString printModel(QAbstractItemModel *model);
|
QString printModel(QAbstractItemModel *model);
|
||||||
void printModelIndex(const QModelIndex &index, QString &res, int level);
|
void printModelIndex(const QModelIndex &index, QString &res, int level);
|
||||||
|
|
||||||
|
constexpr int sizeToInt(std::size_t size)
|
||||||
|
{
|
||||||
|
return size > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : static_cast<int>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int trQuandity(quint64 quandity)
|
||||||
|
{
|
||||||
|
return quandity > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : static_cast<int>(quandity);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // UTILITYFEATURES_H
|
#endif // UTILITYFEATURES_H
|
||||||
|
|
|
@ -29,17 +29,17 @@ using namespace std;
|
||||||
namespace RenamingUtility {
|
namespace RenamingUtility {
|
||||||
|
|
||||||
/// \brief Adds notifications from \a statusProvider to \a notificationsObject.
|
/// \brief Adds notifications from \a statusProvider to \a notificationsObject.
|
||||||
TAGEDITOR_JS_VALUE &operator <<(TAGEDITOR_JS_VALUE ¬ificationsObject, const StatusProvider &statusProvider)
|
TAGEDITOR_JS_VALUE &operator <<(TAGEDITOR_JS_VALUE &diagObject, const Diagnostics &diag)
|
||||||
{
|
{
|
||||||
quint32 counter = 0;
|
quint32 counter = 0;
|
||||||
for(const auto ¬ification : statusProvider.notifications()) {
|
for(const auto &msg : diag) {
|
||||||
TAGEDITOR_JS_VALUE val;
|
TAGEDITOR_JS_VALUE val;
|
||||||
val.setProperty("msg", QString::fromUtf8(notification.message().data()) TAGEDITOR_JS_READONLY);
|
val.setProperty("msg", QString::fromUtf8(msg.message().data()) TAGEDITOR_JS_READONLY);
|
||||||
val.setProperty("critical", notification.type() == NotificationType::Critical TAGEDITOR_JS_READONLY);
|
val.setProperty("critical", msg.level() >= DiagLevel::Critical TAGEDITOR_JS_READONLY);
|
||||||
notificationsObject.setProperty(counter, val);
|
diagObject.setProperty(counter, val);
|
||||||
++counter;
|
++counter;
|
||||||
}
|
}
|
||||||
return notificationsObject;
|
return diagObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add fields and notifications from \a tag to \a tagObject.
|
/// \brief Add fields and notifications from \a tag to \a tagObject.
|
||||||
|
@ -79,8 +79,6 @@ TAGEDITOR_JS_VALUE &operator <<(TAGEDITOR_JS_VALUE &tagObject, const Tag &tag)
|
||||||
tagObject.setProperty("diskPos", pos.position() TAGEDITOR_JS_READONLY);
|
tagObject.setProperty("diskPos", pos.position() TAGEDITOR_JS_READONLY);
|
||||||
tagObject.setProperty("diskTotal", pos.total() TAGEDITOR_JS_READONLY);
|
tagObject.setProperty("diskTotal", pos.total() TAGEDITOR_JS_READONLY);
|
||||||
|
|
||||||
// add notifications
|
|
||||||
tagObject.setProperty("hasCriticalNotifications", tag.hasCriticalNotifications() TAGEDITOR_JS_READONLY);
|
|
||||||
return tagObject;
|
return tagObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +136,7 @@ const QString &TagEditorObject::newRelativeDirectory() const
|
||||||
|
|
||||||
TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||||
{
|
{
|
||||||
|
Diagnostics diag;
|
||||||
MediaFileInfo fileInfo(toNativeFileName(fileName).data());
|
MediaFileInfo fileInfo(toNativeFileName(fileName).data());
|
||||||
|
|
||||||
// add basic file information
|
// add basic file information
|
||||||
|
@ -153,7 +152,7 @@ TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||||
// parse further file information
|
// parse further file information
|
||||||
bool criticalParseingErrorOccured = false;
|
bool criticalParseingErrorOccured = false;
|
||||||
try {
|
try {
|
||||||
fileInfo.parseEverything();
|
fileInfo.parseEverything(diag);
|
||||||
} catch(const Failure &) {
|
} catch(const Failure &) {
|
||||||
// parsing notifications will be addded anyways
|
// parsing notifications will be addded anyways
|
||||||
criticalParseingErrorOccured = true;
|
criticalParseingErrorOccured = true;
|
||||||
|
@ -163,11 +162,11 @@ TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gather notifications
|
// gather notifications
|
||||||
auto mainNotificationObject = m_engine->newArray(static_cast<uint>(fileInfo.notifications().size()));
|
auto diagObj = m_engine->newArray(static_cast<uint>(diag.size()));
|
||||||
mainNotificationObject << fileInfo;
|
diagObj << diag;
|
||||||
criticalParseingErrorOccured |= fileInfo.hasCriticalNotifications();
|
criticalParseingErrorOccured |= diag.level() >= DiagLevel::Critical;
|
||||||
fileInfoObject.setProperty(QStringLiteral("hasCriticalNotifications"), criticalParseingErrorOccured);
|
fileInfoObject.setProperty(QStringLiteral("hasCriticalMessages"), criticalParseingErrorOccured);
|
||||||
fileInfoObject.setProperty(QStringLiteral("notifications"), mainNotificationObject);
|
fileInfoObject.setProperty(QStringLiteral("diagMessages"), diagObj);
|
||||||
|
|
||||||
// add MIME-type, suitable suffix and technical summary
|
// add MIME-type, suitable suffix and technical summary
|
||||||
fileInfoObject.setProperty(QStringLiteral("mimeType"), QString::fromUtf8(fileInfo.mimeType()) TAGEDITOR_JS_READONLY);
|
fileInfoObject.setProperty(QStringLiteral("mimeType"), QString::fromUtf8(fileInfo.mimeType()) TAGEDITOR_JS_READONLY);
|
||||||
|
@ -186,9 +185,6 @@ TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||||
combinedTagObject << tag;
|
combinedTagObject << tag;
|
||||||
combinedTagNotifications << tag;
|
combinedTagNotifications << tag;
|
||||||
tagObject << tag;
|
tagObject << tag;
|
||||||
auto tagNotificationsObject = m_engine->newArray(static_cast<uint>(tag.notifications().size()));
|
|
||||||
tagNotificationsObject << tag;
|
|
||||||
tagObject.setProperty(QStringLiteral("notifications"), tagNotificationsObject TAGEDITOR_JS_READONLY);
|
|
||||||
tagsObject.setProperty(tagIndex, tagObject TAGEDITOR_JS_READONLY);
|
tagsObject.setProperty(tagIndex, tagObject TAGEDITOR_JS_READONLY);
|
||||||
}
|
}
|
||||||
combinedTagObject.setProperty(QStringLiteral("notifications"), combinedTagNotifications TAGEDITOR_JS_READONLY);
|
combinedTagObject.setProperty(QStringLiteral("notifications"), combinedTagNotifications TAGEDITOR_JS_READONLY);
|
||||||
|
@ -206,9 +202,6 @@ TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||||
trackObject.setProperty(QStringLiteral("format"), QString::fromUtf8(track.formatName()));
|
trackObject.setProperty(QStringLiteral("format"), QString::fromUtf8(track.formatName()));
|
||||||
trackObject.setProperty(QStringLiteral("formatAbbreviation"), QString::fromUtf8(track.formatAbbreviation()));
|
trackObject.setProperty(QStringLiteral("formatAbbreviation"), QString::fromUtf8(track.formatAbbreviation()));
|
||||||
trackObject.setProperty(QStringLiteral("description"), QString::fromUtf8(track.description().data()));
|
trackObject.setProperty(QStringLiteral("description"), QString::fromUtf8(track.description().data()));
|
||||||
auto trackNotificationsObject = m_engine->newArray(static_cast<uint>(track.notifications().size()));
|
|
||||||
trackNotificationsObject << track;
|
|
||||||
trackObject.setProperty(QStringLiteral("notifications"), trackNotificationsObject TAGEDITOR_JS_READONLY);
|
|
||||||
tracksObject.setProperty(trackIndex, trackObject TAGEDITOR_JS_READONLY);
|
tracksObject.setProperty(trackIndex, trackObject TAGEDITOR_JS_READONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,12 +221,12 @@ TAGEDITOR_JS_VALUE TagEditorObject::parseFileName(const QString &fileName)
|
||||||
|
|
||||||
TAGEDITOR_JS_VALUE TagEditorObject::allFiles(const QString &dirName)
|
TAGEDITOR_JS_VALUE TagEditorObject::allFiles(const QString &dirName)
|
||||||
{
|
{
|
||||||
QDir dir(dirName);
|
const QDir dir(dirName);
|
||||||
if(dir.exists()) {
|
if(dir.exists()) {
|
||||||
QStringList files = dir.entryList(QDir::Files);
|
const auto files(dir.entryList(QDir::Files));
|
||||||
auto entriesObj = m_engine->newArray(files.length());
|
auto entriesObj = m_engine->newArray(static_cast<uint>(files.size()));
|
||||||
quint32 counter = 0;
|
quint32 counter = 0;
|
||||||
for(const QString &file : files) {
|
for(const auto &file : files) {
|
||||||
entriesObj.setProperty(counter, file TAGEDITOR_JS_READONLY);
|
entriesObj.setProperty(counter, file TAGEDITOR_JS_READONLY);
|
||||||
++counter;
|
++counter;
|
||||||
}
|
}
|
||||||
|
@ -245,9 +238,9 @@ TAGEDITOR_JS_VALUE TagEditorObject::allFiles(const QString &dirName)
|
||||||
|
|
||||||
TAGEDITOR_JS_VALUE TagEditorObject::firstFile(const QString &dirName)
|
TAGEDITOR_JS_VALUE TagEditorObject::firstFile(const QString &dirName)
|
||||||
{
|
{
|
||||||
QDir dir(dirName);
|
const QDir dir(dirName);
|
||||||
if(dir.exists()) {
|
if(dir.exists()) {
|
||||||
QStringList files = dir.entryList(QDir::Files);
|
const auto files(dir.entryList(QDir::Files));
|
||||||
if(!files.empty()) {
|
if(!files.empty()) {
|
||||||
return TAGEDITOR_JS_VALUE(files.first());
|
return TAGEDITOR_JS_VALUE(files.first());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,27 @@
|
||||||
#include <c++utilities/io/catchiofailure.h>
|
#include <c++utilities/io/catchiofailure.h>
|
||||||
#include <c++utilities/io/misc.h>
|
#include <c++utilities/io/misc.h>
|
||||||
#include <c++utilities/io/path.h>
|
#include <c++utilities/io/path.h>
|
||||||
#include <c++utilities/tests/testutils.h>
|
|
||||||
|
// order of includes and definition of operator << matters for C++ to resolve the correct overload
|
||||||
|
|
||||||
#include <tagparser/mediafileinfo.h>
|
#include <tagparser/mediafileinfo.h>
|
||||||
|
#include <tagparser/diagnostics.h>
|
||||||
|
|
||||||
|
namespace TestUtilities {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Prints a DiagMessage to enable using it in CPPUNIT_ASSERT_EQUAL.
|
||||||
|
*/
|
||||||
|
inline std::ostream &operator <<(std::ostream &os, const Media::DiagMessage &diagMessage)
|
||||||
|
{
|
||||||
|
return os << diagMessage.levelName() << ':' << ' ' << diagMessage.message() << ' ' << '(' << diagMessage.context() << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace TestUtilities;
|
||||||
|
|
||||||
|
#include <c++utilities/tests/testutils.h>
|
||||||
|
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
#include <cppunit/TestFixture.h>
|
#include <cppunit/TestFixture.h>
|
||||||
|
@ -804,9 +822,10 @@ void CliTests::testExtraction()
|
||||||
// test extraction of cover
|
// test extraction of cover
|
||||||
const char *const args1[] = {"tageditor", "extract", "cover", "-f", mp4File1.data(), "-o", "/tmp/extracted.jpeg", nullptr};
|
const char *const args1[] = {"tageditor", "extract", "cover", "-f", mp4File1.data(), "-o", "/tmp/extracted.jpeg", nullptr};
|
||||||
TESTUTILS_ASSERT_EXEC(args1);
|
TESTUTILS_ASSERT_EXEC(args1);
|
||||||
|
Diagnostics diag;
|
||||||
MediaFileInfo extractedInfo("/tmp/extracted.jpeg");
|
MediaFileInfo extractedInfo("/tmp/extracted.jpeg");
|
||||||
extractedInfo.open(true);
|
extractedInfo.open(true);
|
||||||
extractedInfo.parseContainerFormat();
|
extractedInfo.parseContainerFormat(diag);
|
||||||
CPPUNIT_ASSERT_EQUAL(22771_st, extractedInfo.size());
|
CPPUNIT_ASSERT_EQUAL(22771_st, extractedInfo.size());
|
||||||
CPPUNIT_ASSERT(ContainerFormat::Jpeg == extractedInfo.containerFormat());
|
CPPUNIT_ASSERT(ContainerFormat::Jpeg == extractedInfo.containerFormat());
|
||||||
extractedInfo.invalidate();
|
extractedInfo.invalidate();
|
||||||
|
@ -819,12 +838,13 @@ void CliTests::testExtraction()
|
||||||
CPPUNIT_ASSERT_EQUAL(0, remove("/tmp/extracted.jpeg"));
|
CPPUNIT_ASSERT_EQUAL(0, remove("/tmp/extracted.jpeg"));
|
||||||
TESTUTILS_ASSERT_EXEC(args3);
|
TESTUTILS_ASSERT_EXEC(args3);
|
||||||
extractedInfo.open(true);
|
extractedInfo.open(true);
|
||||||
extractedInfo.parseContainerFormat();
|
extractedInfo.parseContainerFormat(diag);
|
||||||
CPPUNIT_ASSERT_EQUAL(22771_st, extractedInfo.size());
|
CPPUNIT_ASSERT_EQUAL(22771_st, extractedInfo.size());
|
||||||
CPPUNIT_ASSERT(ContainerFormat::Jpeg == extractedInfo.containerFormat());
|
CPPUNIT_ASSERT(ContainerFormat::Jpeg == extractedInfo.containerFormat());
|
||||||
CPPUNIT_ASSERT_EQUAL(0, remove("/tmp/extracted.jpeg"));
|
CPPUNIT_ASSERT_EQUAL(0, remove("/tmp/extracted.jpeg"));
|
||||||
CPPUNIT_ASSERT_EQUAL(0, remove(mp4File2.data()));
|
CPPUNIT_ASSERT_EQUAL(0, remove(mp4File2.data()));
|
||||||
CPPUNIT_ASSERT_EQUAL(0, remove((mp4File2 + ".bak").data()));
|
CPPUNIT_ASSERT_EQUAL(0, remove((mp4File2 + ".bak").data()));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(Diagnostics(), diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
Loading…
Reference in New Issue