Drop Qt dependency when building only CLI

This commit is contained in:
Martchus 2016-07-27 18:31:42 +02:00
parent cd301090c2
commit aaccbcc375
7 changed files with 114 additions and 56 deletions

View File

@ -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)

View File

@ -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 <operation> [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, ...).

View File

@ -2,9 +2,14 @@
#include <tagparser/tag.h>
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
}

View File

@ -1,10 +1,14 @@
#ifndef KNOWNFIELDMODEL_H
#define KNOWNFIELDMODEL_H
#include <qtutilities/models/checklistmodel.h>
#include <QAbstractListModel>
#include <QList>
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
# include <qtutilities/models/checklistmodel.h>
# include <QAbstractListModel>
# include <QList>
#else
# include <c++utilities/application/global.h>
# 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<int>(field), translatedFieldName(field), checkState);
}
#endif
}

View File

@ -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

View File

@ -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 <tagparser/mediafileinfo.h>
#include <tagparser/tag.h>
@ -18,18 +20,24 @@
#include <c++utilities/io/catchiofailure.h>
#include <c++utilities/misc/memory.h>
#include <QDir>
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
# include <QDir>
#endif
#include <iostream>
#include <cstring>
#include <algorithm>
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<std::pair<unsigned int, QString> > values;
vector<pair<unsigned int, string> > 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<unsigned int>(c.digitValue());
for(const char &c : str) {
if(toIncrement && c >= '0' && c <= '9') {
value = value * 10 + static_cast<unsigned int>(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<FieldDenotation> 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<unsigned int, QString> *selectedDenotatedValue = nullptr;
pair<unsigned int, string> *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<char []>(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);
}

View File

@ -10,7 +10,7 @@
#include <qtutilities/settingsdialog/optioncategory.h>
#include <qtutilities/settingsdialog/optioncategorymodel.h>
//#include <qtutilities/settingsdialog/qtsettings.h>
#include <qtutilities/settingsdialog/qtsettings.h>
#include <QFileDialog>
@ -603,7 +603,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
category->assignPages(QList<Dialogs::OptionPage *>() << new FileBrowserGeneralOptionPage);
categories << category;
//categories << Dialogs::qtOptionCategory(this);
categories << Dialogs::qtOptionCategory(this);
categoryModel()->setCategories(categories);