From aaccbcc3750f1b0c7aa31c0fc0ab4f961a259c4f Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 27 Jul 2016 18:31:42 +0200 Subject: [PATCH] Drop Qt dependency when building only CLI --- CMakeLists.txt | 38 ++++++++++++-------- README.md | 34 ++++++++++++------ application/knownfieldmodel.cpp | 9 ++++- application/knownfieldmodel.h | 22 +++++++++--- application/main.cpp | 2 +- cli/mainfeatures.cpp | 61 ++++++++++++++++++++------------- gui/settingsdialog.cpp | 4 +-- 7 files changed, 114 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ca1a26..7501ea3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,31 +2,37 @@ cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) # meta data set(META_PROJECT_NAME tageditor) +set(META_PROJECT_TYPE application) set(META_APP_NAME "Tag Editor") set(META_APP_CATEGORIES "Utility;Audio;Video;") set(META_APP_AUTHOR "Martchus") set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") -set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska.") +set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska") set(META_VERSION_MAJOR 1) set(META_VERSION_MINOR 4) set(META_VERSION_PATCH 1) # add project files set(HEADER_FILES - application/knownfieldmodel.h - application/targetlevelmodel.h application/main.h - application/settings.h cli/mainfeatures.h + application/knownfieldmodel.h +) +set(SRC_FILES + application/main.cpp + cli/mainfeatures.cpp + application/knownfieldmodel.cpp +) + +set(GUI_HEADER_FILES + application/targetlevelmodel.h + application/settings.h misc/htmlinfo.h misc/utility.h ) -set(SRC_FILES - application/knownfieldmodel.cpp +set(GUI_SRC_FILES application/targetlevelmodel.cpp - application/main.cpp application/settings.cpp - cli/mainfeatures.cpp misc/htmlinfo.cpp misc/utility.cpp ) @@ -180,8 +186,10 @@ find_package(c++utilities 4.0.0 REQUIRED) use_cpp_utilities() # find qtutilities -find_package(qtutilities 4.0.0 REQUIRED) -use_qt_utilities() +if(WIDGETS_GUI OR QUICK_GUI) + find_package(qtutilities 5.0.0 REQUIRED) + use_qt_utilities() +endif() # find tagparser find_package(tagparser 6.0.0 REQUIRED) @@ -192,10 +200,12 @@ list(APPEND ADDITIONAL_QT_MODULES Concurrent Network) # include modules to apply configuration include(BasicConfig) -include(QtGuiConfig) -include(JsProviderConfig) -include(WebViewProviderConfig) -include(QtConfig) +if(WIDGETS_GUI OR QUICK_GUI) + include(QtGuiConfig) + include(JsProviderConfig) + include(WebViewProviderConfig) + include(QtConfig) +endif() include(WindowsResources) include(AppTarget) include(ShellCompletion) diff --git a/README.md b/README.md index a131adf..cc28941 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ However, it is also possible to force rewriting the entire file. Taking advantage of padding is currently not supported when dealing with Ogg streams (it is supported when dealing with raw FLAC streams). -## Download / repository +## Download / binary repository I currently provide packages for Arch Linux and Windows. For more information checkout my [website](http://martchus.no-ip.biz/website/page.php?name=programming). @@ -71,27 +71,30 @@ you will see a preview with the generated file names. The tag editor also features a MusicBrainz and Cover Art Archive search which can be opened with *F10*. However, this feature is still experimental. ### CLI -Usage: +#### Usage ``` tageditor [options] ``` - Checkout the available operations and options with --help. + +#### Examples Here are some Bash examples which illustrate getting and setting tag information: -* Displays title, album and artist of all *.m4a files in the specified directory: +* *Displays* title, album and artist of all *.m4a files in the specified directory: ``` tageditor get title album artist --files /some/dir/*.m4a ``` -* Displays technical information about all *.m4a files in the specified directory: + **Note**: All values are printed in UTF-8 encoding, no matter which encoding is actually used within the tag. + +* *Displays* technical information about all *.m4a files in the specified directory: ``` tageditor info --files /some/dir/*.m4a ``` -* Sets title, album, artist, cover and track number of all *.m4a files in the specified directory: +* *Sets* title, album, artist, cover and track number of all *.m4a files in the specified directory: ``` tageditor set "title=Title of "{1st,2nd,3rd}" file" "title=Title of "{4..16}"th file" \ @@ -103,6 +106,8 @@ Here are some Bash examples which illustrate getting and setting tag information The 16th and following files will all get the name *Title of the 16th file*. The same scheme is used for the track numbers. All files will get the album name *The Album*, the artist *The Artist* and the cover image from the file */path/to/image*. + **Note**: All specified values are assumed to be UTF-8 encoded, no matter which encoding has been specified as preferred encoding via ``--encoding`` option. (This mentioned option only affects the encoding to be used *within* the tag.) + * Here is another example, demonstrating the use of arrays and the syntax to auto-increase numeric fields such as the track number: ``` @@ -124,15 +129,24 @@ Here are some Bash examples which illustrate getting and setting tag information a file has been processed. ## Build instructions -The application depends on c++utilities, qtutilities and tagparser and is built in the same way as these libaries -which are also available on my GitHub profile. +The application depends on [c++utilities](https://github.com/Martchus/cpp-utilities) and [tagparser](https://github.com/Martchus/tagparser) and is built the same way as these libaries. For basic instructions checkout the README file of [c++utilities](https://github.com/Martchus/cpp-utilities). +### Building with Qt 5 GUI The following Qt 5 modules are requried: core concurrent gui network declarative/script widgets webenginewidgets/webkitwidgets +#### Select Qt modules for JavaScript and WebView * If Qt Script is installed on the system, the editor will link against it. Otherwise it will link against Qt QML. -* To force usage of Qt Script/Qt QML or to disable both add `-DJS_PROVIDER=script/qml/none` to the cmake arguments. +* To force usage of Qt Script/Qt QML or to disable both add `-DJS_PROVIDER=script/qml/none` to the CMake arguments. * If Qt WebKitWidgets is installed on the system, the editor will link against it. Otherwise it will link against Qt WebEngineWidgets. -* To force usage of Qt WebKit/Qt WebEngine or to disable both add `-DWEBVIEW_PROVIDER=webkit/webengine/none` to the cmake arguments. +* To force usage of Qt WebKit/Qt WebEngine or to disable both add `-DWEBVIEW_PROVIDER=webkit/webengine/none` to the CMake arguments. + +### Building without Qt 5 GUI +It is possible to build without the GUI if only the CLI is needed. In this case no Qt dependencies (including qtutilities) are required. + +To build without GUI, add the following parameters to the CMake call: +``` +-DWIDGETS_GUI=OFF -DQUICK_GUI=OFF +``` ## TODO - Support more formats (EXIF, PDF metadata, Theora in Ogg, ...). diff --git a/application/knownfieldmodel.cpp b/application/knownfieldmodel.cpp index 634217e..727eb85 100644 --- a/application/knownfieldmodel.cpp +++ b/application/knownfieldmodel.cpp @@ -2,9 +2,14 @@ #include -using namespace Models; using namespace Media; +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) +using namespace Models; +#else +# define QT_TR_NOOP(x) x +#endif + namespace Settings { /* @@ -47,6 +52,7 @@ const char *KnownFieldModel::fieldName(KnownField field) } } +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) QString KnownFieldModel::translatedFieldName(KnownField field) { return tr(fieldName(field)); @@ -118,5 +124,6 @@ QVariant KnownFieldModel::headerData(int section, Qt::Orientation orientation, i } return QVariant(); } +#endif } diff --git a/application/knownfieldmodel.h b/application/knownfieldmodel.h index 25edd18..0e7ac14 100644 --- a/application/knownfieldmodel.h +++ b/application/knownfieldmodel.h @@ -1,10 +1,14 @@ #ifndef KNOWNFIELDMODEL_H #define KNOWNFIELDMODEL_H -#include - -#include -#include +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) +# include +# include +# include +#else +# include +# define Q_OBJECT +#endif namespace Media { DECLARE_ENUM_CLASS(KnownField, unsigned int); @@ -12,7 +16,10 @@ DECLARE_ENUM_CLASS(KnownField, unsigned int); namespace Settings { -class KnownFieldModel : public Models::ChecklistModel +class KnownFieldModel +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) + : public Models::ChecklistModel +#endif { Q_OBJECT public: @@ -23,6 +30,8 @@ public: }; static const char *fieldName(Media::KnownField field); + +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) static QString translatedFieldName(Media::KnownField field); static Models::ChecklistItem mkItem(Media::KnownField field, Qt::CheckState checkState = Qt::Checked); @@ -31,12 +40,15 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual QString labelForId(const QVariant &id) const; +#endif }; +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) inline Models::ChecklistItem KnownFieldModel::mkItem(Media::KnownField field, Qt::CheckState checkState) { return Models::ChecklistItem(static_cast(field), translatedFieldName(field), checkState); } +#endif } diff --git a/application/main.cpp b/application/main.cpp index d39b53d..b116a0b 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -1,9 +1,9 @@ #include "./main.h" -#include "./knownfieldmodel.h" #include "../cli/mainfeatures.h" #if defined(GUI_QTWIDGETS) # include "../gui/initiate.h" +# include "./knownfieldmodel.h" #elif defined(GUI_QTQUICK) #endif diff --git a/cli/mainfeatures.cpp b/cli/mainfeatures.cpp index fdd2ccc..0d24e2a 100644 --- a/cli/mainfeatures.cpp +++ b/cli/mainfeatures.cpp @@ -1,8 +1,10 @@ #include "./mainfeatures.h" #include "../application/knownfieldmodel.h" -#include "../misc/utility.h" -#include "../misc/htmlinfo.h" +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) +# include "../misc/utility.h" +# include "../misc/htmlinfo.h" +#endif #include #include @@ -18,18 +20,24 @@ #include #include -#include +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) +# include +#endif #include +#include +#include using namespace std; using namespace ApplicationUtilities; using namespace ConversionUtilities; using namespace ChronoUtilities; using namespace EscapeCodes; -using namespace Utility; using namespace Settings; using namespace Media; +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) +using namespace Utility; +#endif namespace Cli { @@ -57,7 +65,7 @@ struct FieldDenotation DenotationType type; TagType tagType; TagTarget tagTarget; - std::vector > values; + vector > values; }; FieldDenotation::FieldDenotation(KnownField field) : @@ -71,23 +79,23 @@ inline bool isDigit(char c) return c >= '0' && c <= '9'; } -QString incremented(const QString &str, unsigned int toIncrement = 1) +string incremented(const string &str, unsigned int toIncrement = 1) { - QString res; + string res; res.reserve(str.size()); unsigned int value = 0; bool hasValue = false; - for(const QChar &c : str) { - if(toIncrement && c.isDigit()) { - value = value * 10 + static_cast(c.digitValue()); + for(const char &c : str) { + if(toIncrement && c >= '0' && c <= '9') { + value = value * 10 + static_cast(c - '0'); hasValue = true; } else { if(hasValue) { - res.append(QString::number(value + 1)); + res += numberToString(value + 1); hasValue = false; --toIncrement; } - res.append(c); + res += c; } } return res; @@ -422,7 +430,7 @@ vector parseFieldDenotations(const Argument &fieldsArg, bool re if(readOnly) { cerr << "Warning: Specified value for \"" << string(fieldDenotationString, fieldNameLen) << "\" will be ignored." << endl; } else { - fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, QString::fromLocal8Bit(equationPos + 1))); + fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, (equationPos + 1))); } } } @@ -567,6 +575,7 @@ bool AttachmentInfo::next(AbstractContainer *container) void generateFileInfo(const ArgumentOccurance &, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &validateArg) { CMD_UTILS_START_CONSOLE; +#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK) try { // parse tags MediaFileInfo inputFileInfo(inputFileArg.values().front()); @@ -587,6 +596,12 @@ void generateFileInfo(const ArgumentOccurance &, const Argument &inputFileArg, c ::IoUtilities::catchIoFailure(); cerr << "Error: An IO failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << endl; } +#else + VAR_UNUSED(inputFileArg); + VAR_UNUSED(outputFileArg); + VAR_UNUSED(validateArg); + cerr << "Error: Generating HTML info is only available if built with Qt support." << endl; +#endif } void printProperty(const char *propName, const char *value, const char *suffix = nullptr, size_t intention = 4) @@ -804,11 +819,11 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A } // write value try { - const auto textValue = tagValueToQString(value); - if(textValue.isEmpty()) { + const auto textValue = value.toString(TagTextEncoding::Utf8); + if(textValue.empty()) { cout << "can't display here (see --extract)"; } else { - cout << textValue.toLocal8Bit().data(); + cout << textValue; } } catch(const ConversionException &) { cout << "conversion error"; @@ -832,11 +847,11 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A cout << "none"; } else { try { - const auto textValue = tagValueToQString(value); - if(textValue.isEmpty()) { + const auto textValue = value.toString(TagTextEncoding::Utf8); + if(textValue.empty()) { cout << "can't display here (see --extract)"; } else { - cout << textValue.toLocal8Bit().data(); + cout << textValue; } } catch(const ConversionException &) { cout << "conversion error"; @@ -979,7 +994,7 @@ void setTagInfo(const SetTagInfoArgs &args) if((fieldDenotation.tagType == TagType::Unspecified || (fieldDenotation.tagType | tagType) != TagType::Unspecified) && (!targetSupported || fieldDenotation.tagTarget == tagTarget)) { - pair *selectedDenotatedValue = nullptr; + pair *selectedDenotatedValue = nullptr; for(auto &someDenotatedValue : fieldDenotation.values) { if(someDenotatedValue.first <= fileIndex) { if(!selectedDenotatedValue || (someDenotatedValue.first > selectedDenotatedValue->first)) { @@ -989,11 +1004,11 @@ void setTagInfo(const SetTagInfoArgs &args) } if(selectedDenotatedValue) { if(fieldDenotation.type == DenotationType::File) { - if(selectedDenotatedValue->second.isEmpty()) { + if(selectedDenotatedValue->second.empty()) { tag->setValue(fieldDenotation.field, TagValue()); } else { try { - MediaFileInfo fileInfo(selectedDenotatedValue->second.toLocal8Bit().constData()); + MediaFileInfo fileInfo(selectedDenotatedValue->second); fileInfo.open(true); fileInfo.parseContainerFormat(); auto buff = make_unique(fileInfo.size()); @@ -1014,7 +1029,7 @@ void setTagInfo(const SetTagInfoArgs &args) if(!tag->canEncodingBeUsed(denotedEncoding)) { usedEncoding = tag->proposedTextEncoding(); } - tag->setValue(fieldDenotation.field, qstringToTagValue(selectedDenotatedValue->second, usedEncoding)); + tag->setValue(fieldDenotation.field, TagValue(selectedDenotatedValue->second, TagTextEncoding::Utf8, usedEncoding)); if(fieldDenotation.type == DenotationType::Increment && tag == tags.back()) { selectedDenotatedValue->second = incremented(selectedDenotatedValue->second); } diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp index 195cdbb..812130f 100644 --- a/gui/settingsdialog.cpp +++ b/gui/settingsdialog.cpp @@ -10,7 +10,7 @@ #include #include -//#include +#include #include @@ -603,7 +603,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : category->assignPages(QList() << new FileBrowserGeneralOptionPage); categories << category; - //categories << Dialogs::qtOptionCategory(this); + categories << Dialogs::qtOptionCategory(this); categoryModel()->setCategories(categories);