improved project files
This commit is contained in:
parent
c3417c5d2a
commit
11ad156131
192
CMakeLists.txt
192
CMakeLists.txt
|
@ -5,43 +5,156 @@ set(META_PROJECT_NAME tageditor)
|
|||
set(META_APP_NAME "Tag Editor")
|
||||
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 and Matroska.")
|
||||
set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis and Matroska.")
|
||||
set(META_VERSION_MAJOR 1)
|
||||
set(META_VERSION_MINOR 2)
|
||||
set(META_VERSION_MINOR 3)
|
||||
set(META_VERSION_PATCH 0)
|
||||
|
||||
# define project
|
||||
project(${META_PROJECT_NAME})
|
||||
|
||||
# stringification of meta data
|
||||
set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"")
|
||||
set(META_APP_NAME_STR "\"${META_APP_NAME}\"")
|
||||
set(META_APP_AUTHOR_STR "\"${META_APP_AUTHOR}\"")
|
||||
set(META_APP_URL_STR "\"${META_APP_URL}\"")
|
||||
set(APP_DESCRIPTION_STR "\"${APP_DESCRIPTION}\"")
|
||||
set(META_APP_VERSION_STR "\"${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}\"")
|
||||
set(META_APP_DESCRIPTION_STR "\"${META_APP_DESCRIPTION}\"")
|
||||
set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH})
|
||||
set(META_APP_VERSION_STR "\"${META_APP_VERSION}\"")
|
||||
|
||||
# add project files
|
||||
set(HEADER_FILES
|
||||
application/knownfieldmodel.h
|
||||
application/main.h
|
||||
application/settings.h
|
||||
cli/mainfeatures.h
|
||||
misc/htmlinfo.h
|
||||
misc/utility.h
|
||||
)
|
||||
set(SRC_FILES
|
||||
application/knownfieldmodel.cpp
|
||||
application/main.cpp
|
||||
application/settings.cpp
|
||||
cli/mainfeatures.cpp
|
||||
misc/htmlinfo.cpp
|
||||
misc/utility.cpp
|
||||
)
|
||||
set(WIDGETS_HEADER_FILES
|
||||
gui/entertargetdialog.h
|
||||
gui/javascripthighlighter.h
|
||||
gui/attachmentsedit.h
|
||||
gui/attachmentsmodel.h
|
||||
gui/codeedit.h
|
||||
gui/mainwindow.h
|
||||
gui/minimumemptyspinbox.h
|
||||
gui/notificationlabel.h
|
||||
gui/notificationmodel.h
|
||||
gui/pathlineedit.h
|
||||
gui/picturepreviewselection.h
|
||||
gui/filefilterproxymodel.h
|
||||
gui/infowidgetbase.h
|
||||
gui/initiate.h
|
||||
gui/previousvaluehandling.h
|
||||
gui/renamefilesdialog.h
|
||||
gui/settingsdialog.h
|
||||
gui/tagedit.h
|
||||
gui/tagfieldedit.h
|
||||
renamingutility/filesystemitem.h
|
||||
renamingutility/filesystemitemmodel.h
|
||||
renamingutility/filteredfilesystemitemmodel.h
|
||||
renamingutility/renamingengine.h
|
||||
renamingutility/scriptfunctions.h
|
||||
)
|
||||
set(WIDGETS_SRC_FILES
|
||||
gui/attachmentsedit.cpp
|
||||
gui/attachmentsmodel.cpp
|
||||
gui/codeedit.cpp
|
||||
gui/entertargetdialog.cpp
|
||||
gui/mainwindow.cpp
|
||||
gui/minimumemptyspinbox.cpp
|
||||
gui/notificationlabel.cpp
|
||||
gui/notificationmodel.cpp
|
||||
gui/pathlineedit.cpp
|
||||
gui/picturepreviewselection.cpp
|
||||
gui/filefilterproxymodel.cpp
|
||||
gui/infowidgetbase.cpp
|
||||
gui/initiate.cpp
|
||||
gui/javascripthighlighter.cpp
|
||||
gui/previousvaluehandling.cpp
|
||||
gui/renamefilesdialog.cpp
|
||||
gui/settingsdialog.cpp
|
||||
gui/tagedit.cpp
|
||||
gui/tagfieldedit.cpp
|
||||
renamingutility/filesystemitem.cpp
|
||||
renamingutility/filesystemitemmodel.cpp
|
||||
renamingutility/filteredfilesystemitemmodel.cpp
|
||||
renamingutility/renamingengine.cpp
|
||||
renamingutility/scriptfunctions.cpp
|
||||
resources/icons.qrc
|
||||
)
|
||||
#set(QUICK_HEADER_FILES
|
||||
#)
|
||||
#set(QUICK_SRC_FILES
|
||||
# resources/icons.qrc
|
||||
#)
|
||||
set(TS_FILES
|
||||
translations/${META_PROJECT_NAME}_de_DE.ts
|
||||
translations/${META_PROJECT_NAME}_en_US.ts
|
||||
)
|
||||
|
||||
# define project
|
||||
project(${META_PROJECT_NAME})
|
||||
|
||||
# add configuration header
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/config.h"
|
||||
"${PROJECT_SOURCE_DIR}/resources/config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/resources/config.h"
|
||||
)
|
||||
include_directories("${PROJECT_BINARY_DIR}")
|
||||
|
||||
# add source and header files
|
||||
file(GLOB_RECURSE SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "application/*.cpp" "cli/*.cpp" "misc/*.cpp")
|
||||
file(GLOB_RECURSE WIDGETS_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "gui/*.cpp" "renamingutility/*.cpp" "resources/icons.qrc")
|
||||
file(GLOB_RECURSE HEADER_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "application/*.h" "cli/*.h" "misc/*.h")
|
||||
file(GLOB_RECURSE WIDGETS_HEADER_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "gui/*.h" "renamingutility/*.cpp")
|
||||
# set "GUI-type" to WIN32 to hide console under windows
|
||||
if(WIN32)
|
||||
set(GUI_TYPE WIN32)
|
||||
endif(WIN32)
|
||||
|
||||
# enable only Qt Widgets GUI
|
||||
add_definitions(-DGUI_QTWIDGETS -DMODEL_UNDO_SUPPORT)
|
||||
# add windows resource file
|
||||
if(MINGW)
|
||||
# creation windows icon from png with ffmpeg if available
|
||||
find_program(FFMPEG_BIN ffmpeg avconv)
|
||||
if(FFMPEG_BIN)
|
||||
set(PNG_ICON_PATH "${PROJECT_SOURCE_DIR}/resources/icons/hicolor/128x128/apps/${META_PROJECT_NAME}.png")
|
||||
if(EXISTS ${PNG_ICON_PATH})
|
||||
set(WINDOWS_ICON_PATH "${PROJECT_BINARY_DIR}/${META_PROJECT_NAME}.ico")
|
||||
set(WINDOWS_ICON_RC_ENTRY "IDI_ICON1 ICON DISCARDABLE \"${WINDOWS_ICON_PATH}\"")
|
||||
add_custom_command(
|
||||
OUTPUT "${WINDOWS_ICON_PATH}"
|
||||
COMMAND ${FFMPEG_BIN} -y -i "${PNG_ICON_PATH}" -vf crop=iw-20:ih-20:10:10,scale=64:64 "${WINDOWS_ICON_PATH}"
|
||||
)
|
||||
endif()
|
||||
endif(FFMPEG_BIN)
|
||||
# create windows rc file from template
|
||||
set(WINDOWS_EXT "exe")
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/resources/windows.rc.in"
|
||||
"${PROJECT_BINARY_DIR}/resources/windows.rc"
|
||||
)
|
||||
# set windres as resource compiler
|
||||
set(RES_FILES "${PROJECT_BINARY_DIR}/resources/windows.rc")
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
enable_language(RC)
|
||||
endif(MINGW)
|
||||
|
||||
# enable Qt Widgets GUI
|
||||
add_definitions(
|
||||
-DGUI_QTWIDGETS
|
||||
-DMODEL_UNDO_SUPPORT
|
||||
)
|
||||
|
||||
# check required Qt 5 modules
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Gui REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5WebKit REQUIRED)
|
||||
find_package(Qt5LinguistTools REQUIRED)
|
||||
find_package(Qt5WebKitWidgets REQUIRED)
|
||||
find_package(Qt5Script REQUIRED)
|
||||
|
||||
# enable moc, uic and rcc
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
@ -49,22 +162,53 @@ set(CMAKE_AUTOUIC ON)
|
|||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# executable and linking
|
||||
add_executable(${META_PROJECT_NAME} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_HEADER_FILES} ${WIDGETS_SRC_FILES})
|
||||
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser Qt5::Core Qt5::Widgets Qt5::WebKit)
|
||||
# enable lrelease
|
||||
qt5_add_translation(QM_FILES ${TS_FILES})
|
||||
ADD_CUSTOM_TARGET(translations ALL DEPENDS ${QM_FILES})
|
||||
|
||||
# enable C++11
|
||||
set_property(TARGET ${META_PROJECT_NAME} PROPERTY CXX_STANDARD 11)
|
||||
# executable and linking
|
||||
add_executable(${META_PROJECT_NAME} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_HEADER_FILES} ${WIDGETS_SRC_FILES} ${QM_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH})
|
||||
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser pthread Qt5::Core Qt5::Widgets Qt5::WebKitWidgets Qt5::Script)
|
||||
set_target_properties(${META_PROJECT_NAME} PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
# add install target
|
||||
install(TARGETS ${META_PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
COMPONENT binary
|
||||
)
|
||||
install(FILES resources/icons/hicolor/scalable/apps/${META_PROJECT_NAME}.svg
|
||||
DESTINATION share/icons/hicolor/scalable/apps
|
||||
COMPONENT desktop
|
||||
)
|
||||
install(FILES resources/desktop/applications/${META_PROJECT_NAME}.desktop
|
||||
DESTINATION share/applications
|
||||
COMPONENT desktop
|
||||
)
|
||||
install(FILES ${QM_FILES}
|
||||
DESTINATION share/${META_PROJECT_NAME}/translations
|
||||
COMPONENT localization
|
||||
)
|
||||
add_custom_target(install-binary
|
||||
DEPENDS ${META_PROJECT_NAME}
|
||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
)
|
||||
add_custom_target(install-desktop
|
||||
DEPENDS ${META_PROJECT_NAME}
|
||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=desktop -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
)
|
||||
add_custom_target(install-localization
|
||||
DEPENDS ${META_PROJECT_NAME}
|
||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=localization -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
)
|
||||
add_custom_target(install-mingw-w64
|
||||
DEPENDS install-binary install-localization
|
||||
)
|
||||
add_custom_target(install-binary-strip
|
||||
DEPENDS ${META_PROJECT_NAME}
|
||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_DO_STRIP=1 -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
)
|
||||
add_custom_target(install-mingw-w64-strip
|
||||
DEPENDS install-binary-strip install-localization
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
// include configuration from separate header file when building with CMake
|
||||
#ifndef APP_METADATA_AVAIL
|
||||
#include "config.h"
|
||||
#include "resources/config.h"
|
||||
#endif
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
|
|
56
general.pri
56
general.pri
|
@ -1,28 +1,12 @@
|
|||
#dirs
|
||||
# specify build directories for moc, object and rcc files
|
||||
MOC_DIR = ./moc
|
||||
OBJECTS_DIR = ./obj
|
||||
RCC_DIR = ./res
|
||||
# compiler flags
|
||||
|
||||
# compiler flags: enable C++11
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
QMAKE_LFLAGS += -std=c++11
|
||||
# prefix
|
||||
targetprefix = $$(TARGET_PREFIX)
|
||||
message("Using target prefix \"$${targetprefix}\".")
|
||||
# print install root
|
||||
message("Using install root \"$$(INSTALL_ROOT)\".")
|
||||
# target
|
||||
CONFIG(debug, debug|release) {
|
||||
TARGET = $${targetprefix}$${projectname}d
|
||||
} else {
|
||||
TARGET = $${targetprefix}$${projectname}
|
||||
}
|
||||
# add defines
|
||||
DEFINES += "APP_METADATA_AVAIL"
|
||||
DEFINES += "'PROJECT_NAME=\"$${projectname}\"'"
|
||||
DEFINES += "'APP_NAME=\"$${appname}\"'"
|
||||
DEFINES += "'APP_AUTHOR=\"$${appauthor}\"'"
|
||||
DEFINES += "'APP_URL=\"$${appurl}\"'"
|
||||
DEFINES += "'APP_VERSION=\"$${VERSION}\"'"
|
||||
|
||||
# variables to check target architecture
|
||||
win32-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch
|
||||
win32-g++-32:QMAKE_TARGET.arch = x86
|
||||
|
@ -30,7 +14,30 @@ win32-g++-64:QMAKE_TARGET.arch = x86_64
|
|||
linux-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch
|
||||
linux-g++-32:QMAKE_TARGET.arch = x86
|
||||
linux-g++-64:QMAKE_TARGET.arch = x86_64
|
||||
# configuration
|
||||
|
||||
# determine and print target prefix
|
||||
targetprefix = $$(TARGET_PREFIX)
|
||||
message("Using target prefix \"$${targetprefix}\".")
|
||||
|
||||
# print install root
|
||||
message("Using install root \"$$(INSTALL_ROOT)\".")
|
||||
|
||||
# set target
|
||||
CONFIG(debug, debug|release) {
|
||||
TARGET = $${targetprefix}$${projectname}d
|
||||
} else {
|
||||
TARGET = $${targetprefix}$${projectname}
|
||||
}
|
||||
|
||||
# add defines for meta data
|
||||
DEFINES += "APP_METADATA_AVAIL"
|
||||
DEFINES += "'PROJECT_NAME=\"$${projectname}\"'"
|
||||
DEFINES += "'APP_NAME=\"$${appname}\"'"
|
||||
DEFINES += "'APP_AUTHOR=\"$${appauthor}\"'"
|
||||
DEFINES += "'APP_URL=\"$${appurl}\"'"
|
||||
DEFINES += "'APP_VERSION=\"$${VERSION}\"'"
|
||||
|
||||
# configure Qt modules and defines
|
||||
mobile {
|
||||
DEFINES += CONFIG_MOBILE
|
||||
} else:desktop {
|
||||
|
@ -61,7 +68,7 @@ no-gui {
|
|||
}
|
||||
guiqtquick {
|
||||
message("Configured for Qt Quick GUI support.")
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += quick
|
||||
QT += quick
|
||||
CONFIG(debug, debug|release) {
|
||||
CONFIG += qml_debug
|
||||
}
|
||||
|
@ -69,11 +76,12 @@ guiqtquick {
|
|||
}
|
||||
guiqtwidgets {
|
||||
message("Configured for Qt widgets GUI support.")
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
QT += widgets
|
||||
DEFINES += GUI_QTWIDGETS
|
||||
DEFINES += MODEL_UNDO_SUPPORT
|
||||
}
|
||||
# Windows stuff: configuration for cross compliation with mingw-w64
|
||||
|
||||
# configuration for cross compliation with mingw-w64
|
||||
win32 {
|
||||
QMAKE_TARGET_PRODUCT = "$${appname}"
|
||||
QMAKE_TARGET_COPYRIGHT = "by $${appauthor}"
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
#include "containerinfowidget.h"
|
||||
|
||||
#include <taginfo/mediafileinfo.h>
|
||||
#include <taginfo/abstractcontainer.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
using namespace std;
|
||||
using namespace Media;
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
ContainerInfoWidget::ContainerInfoWidget(QWidget *parent) :
|
||||
InfoWidgetBase(parent),
|
||||
m_nameLabel(nullptr),
|
||||
m_abbreviationLabel(nullptr),
|
||||
m_versionLabel(nullptr),
|
||||
m_readVersionLabel(nullptr),
|
||||
m_docTypeLabel(nullptr),
|
||||
m_docVersionLabel(nullptr),
|
||||
m_docReadVersionLabel(nullptr),
|
||||
m_titleLabel(nullptr)
|
||||
{}
|
||||
|
||||
ContainerInfoWidget::~ContainerInfoWidget()
|
||||
{}
|
||||
|
||||
void ContainerInfoWidget::update(const Media::MediaFileInfo &fileInfo, const Media::AbstractContainer &container)
|
||||
{
|
||||
int row = 0;
|
||||
|
||||
// use container format name as name
|
||||
string name(fileInfo.containerFormatName());
|
||||
const char *subversion = fileInfo.containerFormatSubversion();
|
||||
if(*subversion) {
|
||||
name.append(" ");
|
||||
name.append(subversion);
|
||||
}
|
||||
setupName(name);
|
||||
setupRow(row, "Name", m_nameLabel, name);
|
||||
++row;
|
||||
|
||||
// notifications
|
||||
setupNotifications(container);
|
||||
|
||||
// abbreviation
|
||||
const char *abbreviation = fileInfo.containerFormatAbbreviation();
|
||||
if(*abbreviation) {
|
||||
setupRow(row, "Abbreviation", m_abbreviationLabel, QString::fromLocal8Bit(abbreviation));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_abbreviationLabel);
|
||||
}
|
||||
|
||||
// version
|
||||
if(container.version()) {
|
||||
setupRow(row, "Version", m_versionLabel, QString::number(container.version()));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_versionLabel);
|
||||
}
|
||||
if(container.readVersion()) {
|
||||
setupRow(row, "Read version", m_readVersionLabel, QString::number(container.readVersion()));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_docReadVersionLabel);
|
||||
}
|
||||
|
||||
// document
|
||||
if(!container.documentType().empty()) {
|
||||
setupRow(row, "Document type", m_docTypeLabel, container.documentType());
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_docTypeLabel);
|
||||
}
|
||||
if(container.doctypeVersion()) {
|
||||
setupRow(row, "Document version", m_docVersionLabel, QString::number(container.doctypeVersion()));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_docVersionLabel);
|
||||
}
|
||||
if(container.doctypeReadVersion()) {
|
||||
setupRow(row, "Document read version", m_docReadVersionLabel, QString::number(container.doctypeReadVersion()));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_docReadVersionLabel);
|
||||
}
|
||||
setupRow(row, "Title", m_titleLabel, container.title());
|
||||
m_titleLabel->setReadOnly(fileInfo.containerFormat() != ContainerFormat::Matroska);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef CONTAINERINFOWIDGET_H
|
||||
#define CONTAINERINFOWIDGET_H
|
||||
|
||||
#include "infowidgetbase.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Media {
|
||||
class MediaFileInfo;
|
||||
class AbstractContainer;
|
||||
}
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
class ContainerInfoWidget : public InfoWidgetBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ContainerInfoWidget(QWidget *parent = nullptr);
|
||||
~ContainerInfoWidget();
|
||||
|
||||
void update(const Media::MediaFileInfo &fileInfo, const Media::AbstractContainer &container);
|
||||
|
||||
private:
|
||||
QLabel *m_nameLabel;
|
||||
QLabel *m_abbreviationLabel;
|
||||
QLabel *m_versionLabel;
|
||||
QLabel *m_readVersionLabel;
|
||||
QLabel *m_docTypeLabel;
|
||||
QLabel *m_docVersionLabel;
|
||||
QLabel *m_docReadVersionLabel;
|
||||
QLineEdit *m_titleLabel;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONTAINERINFOWIDGET_H
|
|
@ -1,577 +0,0 @@
|
|||
#include "fileinfomodel.h"
|
||||
|
||||
#include <taginfo/parsingexception.h>
|
||||
#include <taginfo/tag.h>
|
||||
#include <taginfo/abstractcontainer.h>
|
||||
#include <taginfo/abstracttrack.h>
|
||||
#include <taginfo/id3/id3v1tag.h>
|
||||
#include <taginfo/id3/id3v2tag.h>
|
||||
#include <taginfo/mp4/mp4atom.h>
|
||||
#include <taginfo/mp4/mp4container.h>
|
||||
#include <taginfo/matroska/matroskaid.h>
|
||||
#include <taginfo/matroska/ebmlelement.h>
|
||||
#include <taginfo/matroska/matroskacontainer.h>
|
||||
|
||||
#include <martchusutilities/misc/misc.h>
|
||||
#include <martchusutilities/conversion/stringconversion.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace ChronoUtilities;
|
||||
using namespace Media;
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent) :
|
||||
m_itemData(data),
|
||||
m_parentItem(parent)
|
||||
{}
|
||||
|
||||
TreeItem::TreeItem(const QString &data0, const QString &data1, TreeItem *parent) :
|
||||
m_itemData(QList<QVariant>() << data0 << data1),
|
||||
m_parentItem(parent)
|
||||
{}
|
||||
|
||||
TreeItem::TreeItem(const QString &data0, const string &data1, TreeItem *parent) :
|
||||
m_itemData(QList<QVariant>() << data0 << QString::fromLocal8Bit(data1.c_str())),
|
||||
m_parentItem(parent)
|
||||
{}
|
||||
|
||||
TreeItem::TreeItem(const std::string &data0, const std::string &data1, TreeItem *parent) :
|
||||
m_itemData(QList<QVariant>() << QString::fromLocal8Bit(data0.c_str()) << QString::fromLocal8Bit(data1.c_str())),
|
||||
m_parentItem(parent)
|
||||
{}
|
||||
|
||||
TreeItem::~TreeItem()
|
||||
{
|
||||
qDeleteAll(m_childItems);
|
||||
}
|
||||
|
||||
void TreeItem::appendChild(TreeItem *item)
|
||||
{
|
||||
m_childItems.append(item);
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const QList<QVariant> &data)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data, this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const QString &data)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data, QString(), this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const QString &data0, const QString &data1)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data0, data1, this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const QString &data0, const string &data1)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data0, data1, this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const string &data)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data, string(), this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const std::string &data0, const std::string &data1)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data0, data1, this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::appendChild(const QString &data0, int data1)
|
||||
{
|
||||
TreeItem *item = new TreeItem(data0, QString::number(data1), this);
|
||||
m_childItems.append(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::child(int row)
|
||||
{
|
||||
return m_childItems.value(row);
|
||||
}
|
||||
|
||||
int TreeItem::childCount() const
|
||||
{
|
||||
return m_childItems.count();
|
||||
}
|
||||
|
||||
int TreeItem::row() const
|
||||
{
|
||||
if (m_parentItem)
|
||||
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem *>(this));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeItem::columnCount() const
|
||||
{
|
||||
return m_itemData.count();
|
||||
}
|
||||
|
||||
QVariant TreeItem::data(int column) const
|
||||
{
|
||||
return m_itemData.value(column);
|
||||
}
|
||||
|
||||
TreeItem *TreeItem::parent()
|
||||
{
|
||||
return m_parentItem;
|
||||
}
|
||||
|
||||
void TreeItem::clearChilds()
|
||||
{
|
||||
qDeleteAll(m_childItems);
|
||||
m_childItems.clear();
|
||||
}
|
||||
|
||||
void TreeItem::clearData()
|
||||
{
|
||||
m_itemData.clear();
|
||||
}
|
||||
|
||||
const QIcon &TreeItem::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
void TreeItem::setIcon(const QIcon &value)
|
||||
{
|
||||
m_icon = value;
|
||||
}
|
||||
|
||||
FileInfoModel::FileInfoModel(QObject *parent) :
|
||||
QAbstractItemModel(parent),
|
||||
m_fileInfo(0),
|
||||
m_anyNotifications(false),
|
||||
m_criticalNotifications(false)
|
||||
{
|
||||
m_rootItem = new TreeItem(QList<QVariant>() << "Property" << "Value");
|
||||
m_generalItem = m_rootItem->appendChild(QStringLiteral("General information and container/main format"));
|
||||
m_generalItem->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
|
||||
m_audioTracksItem = m_rootItem->appendChild(QStringLiteral("Audio tracks"));
|
||||
m_audioTracksItem->setIcon(QIcon::fromTheme(QStringLiteral("audio-x-generic"), QIcon(QStringLiteral("/images/music"))));
|
||||
m_videoTracksItem = m_rootItem->appendChild(QStringLiteral("Video tracks"));
|
||||
m_videoTracksItem->setIcon(QIcon::fromTheme(QStringLiteral("video-x-generic"), QIcon(QStringLiteral("/images/video"))));
|
||||
m_subtitleTracksItem = m_rootItem->appendChild(QStringLiteral("Subtitle tracks"));
|
||||
m_otherTracksItem = m_rootItem->appendChild(QStringLiteral("Other tracks"));
|
||||
m_tagItem = m_rootItem->appendChild(QStringLiteral("Tag(s)"));
|
||||
m_tagItem->setIcon(QIcon::fromTheme(QStringLiteral("multimedia-player"), QIcon(QStringLiteral("/images/tag"))));
|
||||
}
|
||||
|
||||
FileInfoModel::FileInfoModel(MediaFileInfo *fileInfo, QObject *parent) :
|
||||
FileInfoModel(parent)
|
||||
{
|
||||
show(fileInfo);
|
||||
}
|
||||
|
||||
FileInfoModel::~FileInfoModel()
|
||||
{
|
||||
delete m_rootItem;
|
||||
}
|
||||
|
||||
QVariant FileInfoModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
switch(role) {
|
||||
case Qt::DisplayRole:
|
||||
return static_cast<TreeItem *>(index.internalPointer())->data(index.column());
|
||||
case Qt::DecorationRole:
|
||||
if(index.column() == 0) {
|
||||
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
|
||||
if(!item->icon().isNull())
|
||||
return item->icon();
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags FileInfoModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
|
||||
QVariant FileInfoModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
return m_rootItem->data(section);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex FileInfoModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent)) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
TreeItem *parentItem;
|
||||
if (!parent.isValid()) {
|
||||
parentItem = m_rootItem;
|
||||
} else {
|
||||
parentItem = static_cast<TreeItem *>(parent.internalPointer());
|
||||
}
|
||||
|
||||
if (TreeItem *childItem = parentItem->child(row)) {
|
||||
return createIndex(row, column, childItem);
|
||||
} else {
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex FileInfoModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
|
||||
TreeItem *parentItem = childItem->parent();
|
||||
if (parentItem == m_rootItem) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
|
||||
int FileInfoModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
TreeItem *parentItem;
|
||||
if (parent.column() > 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!parent.isValid()) {
|
||||
parentItem = m_rootItem;
|
||||
} else {
|
||||
parentItem = static_cast<TreeItem *>(parent.internalPointer());
|
||||
}
|
||||
return parentItem->childCount();
|
||||
}
|
||||
|
||||
int FileInfoModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return static_cast<TreeItem *>(parent.internalPointer())->columnCount();
|
||||
} else {
|
||||
return m_rootItem->columnCount();
|
||||
}
|
||||
}
|
||||
|
||||
const MediaFileInfo *FileInfoModel::shownFileInfo() const
|
||||
{
|
||||
return m_fileInfo;
|
||||
}
|
||||
|
||||
MediaFileInfo *FileInfoModel::shownFileInfo()
|
||||
{
|
||||
return m_fileInfo;
|
||||
}
|
||||
|
||||
void FileInfoModel::show(MediaFileInfo *fileInfo)
|
||||
{
|
||||
m_fileInfo = fileInfo;
|
||||
update();
|
||||
}
|
||||
|
||||
void FileInfoModel::update()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
m_anyNotifications = false;
|
||||
m_criticalNotifications = false;
|
||||
m_generalItem->clearChilds();
|
||||
m_audioTracksItem->clearChilds();
|
||||
m_videoTracksItem->clearChilds();
|
||||
m_otherTracksItem->clearChilds();
|
||||
m_tagItem->clearChilds();
|
||||
|
||||
showGeneralInformation();
|
||||
showTracks();
|
||||
showTagInformation();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool FileInfoModel::containsAnyNotifications() const
|
||||
{
|
||||
return m_anyNotifications;
|
||||
}
|
||||
|
||||
bool FileInfoModel::containsCriticalNotifications() const
|
||||
{
|
||||
return m_criticalNotifications;
|
||||
}
|
||||
|
||||
void FileInfoModel::showGeneralInformation()
|
||||
{
|
||||
if(m_fileInfo && m_fileInfo->isContainerParsed()) {
|
||||
AbstractContainer *container = m_fileInfo->container();
|
||||
m_generalItem->appendChild(tr("Path"), m_fileInfo->path());
|
||||
m_generalItem->appendChild(tr("Extension"), m_fileInfo->extension());
|
||||
m_generalItem->appendChild(tr("Size"), ConversionUtilities::dataSizeToString(m_fileInfo->size()));
|
||||
TreeItem *containerItem = m_generalItem->appendChild("Container format", QString::fromLocal8Bit(m_fileInfo->containerFormatName()));
|
||||
QString version;
|
||||
if(container) {
|
||||
if(!container->duration().isNull()) {
|
||||
m_generalItem->appendChild(tr("Duration"), container->duration().toString(TimeSpanOutputFormat::WithMeasures));
|
||||
}
|
||||
if(!container->title().empty()) {
|
||||
m_generalItem->appendChild(tr("Title"), container->title());
|
||||
}
|
||||
if(!container->documentType().empty()) {
|
||||
containerItem->appendChild(tr("Document type"), container->documentType());
|
||||
}
|
||||
version = QString::number(container->version());
|
||||
} else {
|
||||
version = QString::fromLocal8Bit(m_fileInfo->containerFormatSubversion());
|
||||
}
|
||||
containerItem->appendChild(tr("Version"), version);
|
||||
containerItem->appendChild(tr("Abbreviation"), QString::fromLocal8Bit(m_fileInfo->containerFormatAbbreviation()));
|
||||
if(Mp4Container *container = m_fileInfo->mp4Container()) { // show atom structure if its an MP4 file
|
||||
if(Mp4Atom *atom = container->firstElement()) {
|
||||
TreeItem *atomsItem = containerItem->appendChild(tr("Atom structure"));
|
||||
showAtoms(atomsItem, atom);
|
||||
}
|
||||
}
|
||||
if(MatroskaContainer *container = m_fileInfo->matroskaContainer()) { // show EBML elements if its an EBML/Matroska file
|
||||
if(EbmlElement *element = container->firstElement()) {
|
||||
TreeItem *elementItem = containerItem->appendChild(tr("EBML element structure (to first cluster)"));
|
||||
showEbmlElements(elementItem, element);
|
||||
}
|
||||
}
|
||||
showNotifications(m_fileInfo->lastParsingNotifications(), m_generalItem, tr("General parsing notifications"));
|
||||
showNotifications(m_fileInfo->lastMakingNotifications(), m_generalItem, tr("Last saving notifications"));
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfoModel::showAtoms(TreeItem *item, Mp4Atom *atom)
|
||||
{
|
||||
while(atom) {
|
||||
try {
|
||||
atom->parse();
|
||||
if(atom->lastParsingNotifications().size())
|
||||
showNotifications(atom->lastParsingNotifications(), item, tr("Expand to display parsing warnings"));
|
||||
showAtoms(item->appendChild(
|
||||
QString::fromLatin1(atom->idToString().c_str()),
|
||||
tr("@%1, size: %2").arg(atom->startOffset()).arg(atom->totalSize())),
|
||||
atom->firstChild());
|
||||
atom = atom->nextSibling();
|
||||
} catch(ParsingException &) {
|
||||
showNotifications(atom->lastParsingNotifications(), item, tr("Invalid atom found, expand for detail."));
|
||||
return;
|
||||
} catch(ios_base::failure &) {
|
||||
showNotifications(atom->lastParsingNotifications(), item, tr("IO error occured when parsing atom."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfoModel::showEbmlElements(TreeItem *item, EbmlElement *element)
|
||||
{
|
||||
while(element) {
|
||||
try {
|
||||
element->parse();
|
||||
if(element->lastParsingNotifications().size())
|
||||
showNotifications(element->lastParsingNotifications(), item, tr("Expand to display parsing warnings"));
|
||||
showEbmlElements(item->appendChild(
|
||||
QString::fromLatin1(element->idToString().c_str()),
|
||||
tr("@%1, size: %2").arg(element->startOffset()).arg(element->totalSize())),
|
||||
element->firstChild());
|
||||
if(element->id() == MatroskaId::Cluster) {
|
||||
break; // cluster reached; just display the first cluster
|
||||
}
|
||||
element = element->nextSibling();
|
||||
} catch(ParsingException &) {
|
||||
showNotifications(element->lastParsingNotifications(), item, tr("Invalid EBML element found, expand for detail."));
|
||||
return;
|
||||
} catch(ios_base::failure &) {
|
||||
showNotifications(element->lastParsingNotifications(), item, tr("IO error occured when parsing atom."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfoModel::showTracks()
|
||||
{
|
||||
TreeItem *item, *formatItem;
|
||||
int i = 1;
|
||||
for(AbstractTrack *track : m_fileInfo->tracks()) {
|
||||
list<string> identifiers;
|
||||
identifiers.push_back(track->name());
|
||||
identifiers.push_back("ID: " + ConversionUtilities::numberToString<uint32>(track->id()));
|
||||
QString name = QString::fromLocal8Bit(ConversionUtilities::concateStrings(identifiers, ", ", true).c_str());
|
||||
if(name.isEmpty()) {
|
||||
name = tr("Unnamed track");
|
||||
}
|
||||
switch(track->mediaType()) {
|
||||
case MediaType::Audio:
|
||||
item = m_audioTracksItem->appendChild(name);
|
||||
break;
|
||||
case MediaType::Video:
|
||||
item = m_videoTracksItem->appendChild(name);
|
||||
break;
|
||||
case MediaType::Subtitle:
|
||||
item = m_subtitleTracksItem->appendChild(name);
|
||||
break;
|
||||
default:
|
||||
item = m_otherTracksItem->appendChild(name);
|
||||
}
|
||||
if(track->isHeaderValid()) {
|
||||
formatItem = item->appendChild(tr("Format"), QString::fromLocal8Bit(track->formatName()));
|
||||
formatItem->appendChild(tr("Version"), QStringLiteral("%1").arg(track->version()));
|
||||
formatItem->appendChild(tr("Abbreviation"), QString::fromLocal8Bit(track->formatAbbreviation()));
|
||||
if(track->bitrate() > 0.0)
|
||||
item->appendChild(tr("Bitrate"), ConversionUtilities::bitrateToString(track->bitrate()));
|
||||
if(!track->duration().isNull())
|
||||
item->appendChild(tr("Duration"), track->duration().toString(TimeSpanOutputFormat::WithMeasures));
|
||||
if(track->size())
|
||||
item->appendChild(tr("Size"), ConversionUtilities::dataSizeToString(track->size()));
|
||||
if(!track->compressorName().empty())
|
||||
item->appendChild(tr("Compressor"), track->compressorName());
|
||||
if(!track->creationTime().isNull())
|
||||
item->appendChild(tr("Creation time"), track->creationTime().toString());
|
||||
if(!track->modificationTime().isNull())
|
||||
item->appendChild(tr("Modification time"), track->modificationTime().toString());
|
||||
if(track->sampleCount())
|
||||
item->appendChild(tr("Sample count"), track->sampleCount());
|
||||
if(track->samplesPerSecond())
|
||||
item->appendChild(tr("Samples per second"), track->samplesPerSecond());
|
||||
if(track->quality())
|
||||
item->appendChild(tr("Quality"), track->quality());
|
||||
if(!track->language().empty())
|
||||
item->appendChild(tr("Language"), track->language());
|
||||
list<string> labels;
|
||||
if(!track->isEnabled())
|
||||
labels.push_back("disabled");
|
||||
if(track->isDefault())
|
||||
labels.push_back("default");
|
||||
if(track->isForced())
|
||||
labels.push_back("forced");
|
||||
if(track->isEncrypted())
|
||||
labels.push_back("encrypted");
|
||||
string concatedLabels = ConversionUtilities::concateStrings(labels, ", ");
|
||||
if(!concatedLabels.empty())
|
||||
item->appendChild(tr("Language"), concatedLabels);
|
||||
switch(track->mediaType()) {
|
||||
case MediaType::Audio:
|
||||
if(track->bitsPerSample())
|
||||
item->appendChild(tr("Bits per sample"), track->bitsPerSample());
|
||||
if(track->channelCount())
|
||||
item->appendChild(tr("Channel count"), track->channelCount());
|
||||
break;
|
||||
case MediaType::Video:
|
||||
if(!track->pixelSize().isNull())
|
||||
item->appendChild(tr("Size in px"), track->pixelSize().toString());
|
||||
if(!track->displaySize().isNull())
|
||||
item->appendChild(tr("Display size in px"), track->displaySize().toString());
|
||||
if(!track->cropping().isNull())
|
||||
item->appendChild(tr("Cropping in px"), track->cropping().toString());
|
||||
if(track->depth())
|
||||
item->appendChild(tr("Depth"), track->depth());
|
||||
if(track->fps())
|
||||
item->appendChild(tr("Frames per second"), track->fps());
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
} else {
|
||||
item = m_otherTracksItem->appendChild(tr("Invalid/unsupported segment %1").arg(i));
|
||||
item->appendChild(tr("Unable to parse file segment."), tr("See notifications for details."));
|
||||
}
|
||||
showNotifications(track->lastParsingNotifications(), item, tr("Parsing notifications"));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfoModel::showTagInformation()
|
||||
{
|
||||
if(m_fileInfo) {
|
||||
static const QString expand(tr("expand for details"));
|
||||
if(m_fileInfo->hasMp4Tag()) {
|
||||
showTagDetails(m_fileInfo->mp4Tag(), m_tagItem->appendChild(tr("MP4 atoms store tag information"), expand));
|
||||
} else if(m_fileInfo->hasMatroskaTag()) {
|
||||
for(const auto &tag : m_fileInfo->matroskaTags()) {
|
||||
showTagDetails(tag.get(), m_tagItem->appendChild(tr("Matroska container stores tag information"), expand));
|
||||
}
|
||||
}
|
||||
const vector<unique_ptr<Id3v2Tag>> &id3v2Tags = m_fileInfo->id3v2Tags();
|
||||
for(vector<unique_ptr<Id3v2Tag>>::const_iterator i = id3v2Tags.begin(), end = id3v2Tags.end();
|
||||
i != end; ++i) {
|
||||
showTagDetails((*i).get(), m_tagItem->appendChild(tr("ID3v2 tag"), expand));
|
||||
}
|
||||
if(m_fileInfo->hasId3v1Tag())
|
||||
showTagDetails(m_fileInfo->id3v1Tag(), m_tagItem->appendChild(tr("ID3v1 tag"), expand));
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfoModel::showTagDetails(const Tag *tag, TreeItem *item)
|
||||
{
|
||||
// display version
|
||||
//static const QString version(QStringLiteral("%1"));
|
||||
//static const QString unknownVersion(QStringLiteral("unknown or invalid tag"));
|
||||
item->appendChild(tr("Version"), QString::fromLocal8Bit(tag->version().c_str()));
|
||||
|
||||
item->appendChild(tr("Size"), ConversionUtilities::dataSizeToString(tag->size())); // size
|
||||
item->appendChild(tr("Field count"), tag->fieldCount()); // field count
|
||||
|
||||
showNotifications(tag->lastParsingNotifications(), item, tr("Parsing notifications"));
|
||||
showNotifications(tag->lastMakingNotifications(), item, tr("Saving notifications"));
|
||||
}
|
||||
|
||||
void FileInfoModel::showNotifications(const list<Notification> ¬ifications, TreeItem *item, const QString &label, bool showEmptyEntry)
|
||||
{
|
||||
static const QIcon informationIcon = QIcon::fromTheme(QStringLiteral("dialog-information"), QIcon(QStringLiteral("/images/information")));
|
||||
static const QIcon warningIcon = QIcon::fromTheme(QStringLiteral("dialog-warning"), QIcon(QStringLiteral("/images/warning")));
|
||||
static const QIcon errorIcon = QIcon::fromTheme(QStringLiteral("dialog-error"), QIcon(QStringLiteral("/images/error")));
|
||||
static const QIcon debugIcon = QIcon::fromTheme(QStringLiteral("utilities-terminal"), QIcon(QStringLiteral("/images/bug")));
|
||||
|
||||
if(notifications.size()) {
|
||||
m_anyNotifications = true;
|
||||
|
||||
TreeItem *notificationsItem = item->appendChild(label, QStringLiteral("%1").arg(notifications.size()));
|
||||
TreeItem *notificationItem;
|
||||
for(list<Notification>::const_iterator i = notifications.cbegin(), end = notifications.cend(); i != end; ++i) {
|
||||
notificationItem = notificationsItem->appendChild(i->message());
|
||||
switch(i->type()) {
|
||||
case NotificationType::Warning:
|
||||
notificationItem->setIcon(warningIcon);
|
||||
break;
|
||||
case NotificationType::Critical:
|
||||
m_criticalNotifications = true;
|
||||
notificationItem->setIcon(errorIcon);
|
||||
break;
|
||||
case NotificationType::Information:
|
||||
notificationItem->setIcon(informationIcon);
|
||||
break;
|
||||
case NotificationType::Debug:
|
||||
notificationItem->setIcon(debugIcon);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
} else if(showEmptyEntry) {
|
||||
item->appendChild(label, tr("none"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
#ifndef FILEINFOMODEL_H
|
||||
#define FILEINFOMODEL_H
|
||||
|
||||
#include <taginfo/mediafileinfo.h>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
class TreeItem
|
||||
{
|
||||
public:
|
||||
explicit TreeItem(const QList<QVariant> &data, TreeItem *parent = nullptr);
|
||||
explicit TreeItem(const QString &data0, const QString &data1, TreeItem *parent = nullptr);
|
||||
explicit TreeItem(const QString &data0, const std::string &data1, TreeItem *parent = nullptr);
|
||||
explicit TreeItem(const std::string &data0, const std::string &data1, TreeItem *parent = nullptr);
|
||||
~TreeItem();
|
||||
|
||||
void appendChild(TreeItem *child);
|
||||
TreeItem *appendChild(const QList<QVariant> &data);
|
||||
TreeItem *appendChild(const QString &data);
|
||||
TreeItem *appendChild(const QString &data0, const QString &data1);
|
||||
TreeItem *appendChild(const QString &data0, const std::string &data1);
|
||||
TreeItem *appendChild(const std::string &data);
|
||||
TreeItem *appendChild(const std::string &data0, const std::string &data1);
|
||||
TreeItem *appendChild(const QString &data0, int data1);
|
||||
|
||||
TreeItem *child(int row);
|
||||
int childCount() const;
|
||||
int columnCount() const;
|
||||
QVariant data(int column) const;
|
||||
int row() const;
|
||||
TreeItem *parent();
|
||||
void clearChilds();
|
||||
void clearData();
|
||||
const QIcon &icon() const;
|
||||
void setIcon(const QIcon &value);
|
||||
|
||||
private:
|
||||
QList<TreeItem *> m_childItems;
|
||||
QList<QVariant> m_itemData;
|
||||
QIcon m_icon;
|
||||
TreeItem *m_parentItem;
|
||||
|
||||
};
|
||||
|
||||
class FileInfoModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FileInfoModel(QObject *parent = nullptr);
|
||||
explicit FileInfoModel(Media::MediaFileInfo *fileInfo, QObject *parent = nullptr);
|
||||
~FileInfoModel();
|
||||
|
||||
const Media::MediaFileInfo *shownFileInfo() const;
|
||||
Media::MediaFileInfo *shownFileInfo();
|
||||
void show(Media::MediaFileInfo *fileInfo);
|
||||
void update();
|
||||
bool containsAnyNotifications() const;
|
||||
bool containsCriticalNotifications() const;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
private:
|
||||
void showGeneralInformation();
|
||||
void showAtoms(TreeItem *item, Media::Mp4Atom *atom);
|
||||
void showEbmlElements(TreeItem *item, Media::EbmlElement *element);
|
||||
void showTracks();
|
||||
void showTagInformation();
|
||||
void showTagDetails(const Media::Tag *tag, TreeItem *item);
|
||||
void showNotifications(const std::list<Media::Notification> ¬ifications, TreeItem *item, const QString &label = tr("Notifications"), bool showEmptyEntry = true);
|
||||
|
||||
TreeItem *m_rootItem;
|
||||
TreeItem *m_generalItem;
|
||||
TreeItem *m_audioTracksItem;
|
||||
TreeItem *m_videoTracksItem;
|
||||
TreeItem *m_subtitleTracksItem;
|
||||
TreeItem *m_otherTracksItem;
|
||||
TreeItem *m_tagItem;
|
||||
Media::MediaFileInfo *m_fileInfo;
|
||||
bool m_anyNotifications;
|
||||
bool m_criticalNotifications;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FILEINFOMODEL_H
|
|
@ -1,85 +0,0 @@
|
|||
#include "generalfileinfowidget.h"
|
||||
|
||||
#include <martchusutilities/conversion/stringconversion.h>
|
||||
#include <martchusutilities/chrono/timespan.h>
|
||||
|
||||
#include <taginfo/mediafileinfo.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QTreeView>
|
||||
#include <QLabel>
|
||||
|
||||
using namespace std;
|
||||
using namespace ConversionUtilities;
|
||||
using namespace ChronoUtilities;
|
||||
using namespace Media;
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
GeneralFileInfoWidget::GeneralFileInfoWidget(QWidget *parent) :
|
||||
InfoWidgetBase(parent),
|
||||
m_pathLabel(nullptr),
|
||||
m_sizeLabel(nullptr),
|
||||
m_durationLabel(nullptr),
|
||||
m_bitrateLabel(nullptr),
|
||||
m_containerLabel(nullptr),
|
||||
m_mimeTypeLabel(nullptr)
|
||||
{}
|
||||
|
||||
GeneralFileInfoWidget::~GeneralFileInfoWidget()
|
||||
{}
|
||||
|
||||
|
||||
void GeneralFileInfoWidget::update(const MediaFileInfo &fileInfo)
|
||||
{
|
||||
int row = 0;
|
||||
|
||||
// use file name as name
|
||||
setupName(fileInfo.fileName());
|
||||
|
||||
// notifications
|
||||
setupNotifications(fileInfo);
|
||||
|
||||
// path
|
||||
setupRow(row, "Path", m_pathLabel, fileInfo.path());
|
||||
++row;
|
||||
|
||||
// size
|
||||
setupRow(row, "Size", m_sizeLabel, dataSizeToString(fileInfo.size()));
|
||||
++row;
|
||||
|
||||
// overall duration and bitrate
|
||||
TimeSpan duration = fileInfo.duration();
|
||||
if(duration.isNull()) {
|
||||
removeRow(m_durationLabel);
|
||||
removeRow(m_bitrateLabel);
|
||||
} else {
|
||||
setupRow(row, "Duration", m_durationLabel, duration.toString(TimeSpanOutputFormat::WithMeasures));
|
||||
++row;
|
||||
setupRow(row, "Overall avg. bitrate", m_bitrateLabel, bitrateToString(0.0078125 * fileInfo.size() / duration.totalSeconds()));
|
||||
++row;
|
||||
}
|
||||
|
||||
// container format
|
||||
string container(fileInfo.containerFormatName());
|
||||
const char *subversion = fileInfo.containerFormatSubversion();
|
||||
if(*subversion) {
|
||||
container.append(" ");
|
||||
container.append(subversion);
|
||||
}
|
||||
setupRow(row, "Container format", m_containerLabel, container);
|
||||
++row;
|
||||
|
||||
// mime type
|
||||
const char *mimeType = fileInfo.containerMimeType();
|
||||
if(*mimeType) {
|
||||
setupRow(row, "Mime-type", m_mimeTypeLabel, QString::fromLocal8Bit(mimeType));
|
||||
++row;
|
||||
} else {
|
||||
removeRow(m_mimeTypeLabel);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef GENERALFILEINFOWIDGET_H
|
||||
#define GENERALFILEINFOWIDGET_H
|
||||
|
||||
#include "infowidgetbase.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Media {
|
||||
class MediaFileInfo;
|
||||
}
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
class GeneralFileInfoWidget : public InfoWidgetBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GeneralFileInfoWidget(QWidget *parent = nullptr);
|
||||
~GeneralFileInfoWidget();
|
||||
|
||||
void update(const Media::MediaFileInfo &fileInfo);
|
||||
|
||||
private:
|
||||
QLabel *m_pathLabel;
|
||||
QLabel *m_sizeLabel;
|
||||
QLabel *m_durationLabel;
|
||||
QLabel *m_bitrateLabel;
|
||||
QLabel *m_containerLabel;
|
||||
QLabel *m_mimeTypeLabel;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // GENERALFILEINFOWIDGET_H
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
// include configuration from separate header file when building with CMake
|
||||
#ifndef APP_METADATA_AVAIL
|
||||
#include "config.h"
|
||||
#include "resources/config.h"
|
||||
#endif
|
||||
|
||||
#include <qtutilities/resources/qtconfigarguments.h>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# if defined(UNDER_CE)
|
||||
# include <winbase.h>
|
||||
# else
|
||||
# include <windows.h>
|
||||
# endif
|
||||
|
||||
@WINDOWS_ICON_RC_ENTRY@
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @META_VERSION_MAJOR@,@META_VERSION_MINOR@,@META_VERSION_PATCH@,0
|
||||
PRODUCTVERSION @META_VERSION_MAJOR@,@META_VERSION_MINOR@,@META_VERSION_PATCH@,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "@META_APP_AUTHOR@\0"
|
||||
VALUE "FileDescription", "@META_APP_DESCRIPTION@.\0"
|
||||
VALUE "FileVersion", "@META_APP_VERSION@\0"
|
||||
VALUE "LegalCopyright", "by @META_APP_AUTHOR@\0"
|
||||
VALUE "OriginalFilename", "@META_PROJECT_NAME@.@WINDOWS_EXT@\0"
|
||||
VALUE "ProductName", "@META_APP_NAME@\0"
|
||||
VALUE "ProductVersion", "@META_APP_VERSION@\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0409, 1200
|
||||
END
|
||||
END
|
||||
/* End of Version info */
|
|
@ -1,9 +1,10 @@
|
|||
# meta data
|
||||
projectname = tageditor
|
||||
appname = "Tag Editor"
|
||||
appauthor = Martchus
|
||||
appurl = "https://github.com/$${appauthor}/$${projectname}"
|
||||
QMAKE_TARGET_DESCRIPTION = "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis and Matroska."
|
||||
VERSION = 1.2.0
|
||||
VERSION = 1.3.0
|
||||
|
||||
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
|
||||
!include(../../common.pri) {
|
||||
|
@ -12,12 +13,10 @@ VERSION = 1.2.0
|
|||
}
|
||||
}
|
||||
|
||||
# basic configuration: application
|
||||
TEMPLATE = app
|
||||
|
||||
QT += core gui script
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
QT += widgets
|
||||
}
|
||||
QT += core gui widgets script
|
||||
# use webenginewidgets if available; otherwise use webkitwidgets
|
||||
!forcewebkit:qtHaveModule(webenginewidgets) {
|
||||
QT += webenginewidgets
|
||||
DEFINES += TAGEDITOR_USE_WEBENGINE
|
||||
|
@ -25,6 +24,37 @@ greaterThan(QT_MAJOR_VERSION, 4) {
|
|||
QT += webkitwidgets
|
||||
}
|
||||
|
||||
# add project files
|
||||
HEADERS += application/main.h \
|
||||
application/knownfieldmodel.h \
|
||||
application/settings.h \
|
||||
gui/filefilterproxymodel.h \
|
||||
gui/tagfieldedit.h \
|
||||
gui/tagedit.h \
|
||||
gui/mainwindow.h \
|
||||
gui/pathlineedit.h \
|
||||
gui/notificationlabel.h \
|
||||
gui/renamefilesdialog.h \
|
||||
gui/javascripthighlighter.h \
|
||||
gui/picturepreviewselection.h \
|
||||
gui/notificationmodel.h \
|
||||
gui/infowidgetbase.h \
|
||||
gui/settingsdialog.h \
|
||||
renamingutility/filesystemitem.h \
|
||||
renamingutility/filesystemitemmodel.h \
|
||||
renamingutility/filteredfilesystemitemmodel.h \
|
||||
renamingutility/renamingengine.h \
|
||||
renamingutility/scriptfunctions.h \
|
||||
misc/htmlinfo.h \
|
||||
gui/previousvaluehandling.h \
|
||||
gui/initiate.h \
|
||||
cli/mainfeatures.h \
|
||||
misc/utility.h \
|
||||
gui/entertargetdialog.h \
|
||||
gui/attachmentsmodel.h \
|
||||
gui/attachmentsedit.h \
|
||||
gui/codeedit.h
|
||||
|
||||
SOURCES += application/main.cpp \
|
||||
application/knownfieldmodel.cpp \
|
||||
application/settings.cpp \
|
||||
|
@ -55,36 +85,6 @@ SOURCES += application/main.cpp \
|
|||
gui/attachmentsedit.cpp \
|
||||
gui/codeedit.cpp
|
||||
|
||||
HEADERS += application/main.h \
|
||||
application/knownfieldmodel.h \
|
||||
application/settings.h \
|
||||
gui/filefilterproxymodel.h \
|
||||
gui/tagfieldedit.h \
|
||||
gui/tagedit.h \
|
||||
gui/mainwindow.h \
|
||||
gui/pathlineedit.h \
|
||||
gui/notificationlabel.h \
|
||||
gui/renamefilesdialog.h \
|
||||
gui/javascripthighlighter.h \
|
||||
gui/picturepreviewselection.h \
|
||||
gui/notificationmodel.h \
|
||||
gui/infowidgetbase.h \
|
||||
gui/settingsdialog.h \
|
||||
renamingutility/filesystemitem.h \
|
||||
renamingutility/filesystemitemmodel.h \
|
||||
renamingutility/filteredfilesystemitemmodel.h \
|
||||
renamingutility/renamingengine.h \
|
||||
renamingutility/scriptfunctions.h \
|
||||
misc/htmlinfo.h \
|
||||
gui/previousvaluehandling.h \
|
||||
gui/initiate.h \
|
||||
cli/mainfeatures.h \
|
||||
misc/utility.h \
|
||||
gui/entertargetdialog.h \
|
||||
gui/attachmentsmodel.h \
|
||||
gui/attachmentsedit.h \
|
||||
gui/codeedit.h
|
||||
|
||||
FORMS += \
|
||||
gui/id3v2optionpage.ui \
|
||||
gui/id3v1optionpage.ui \
|
||||
|
@ -102,19 +102,27 @@ FORMS += \
|
|||
gui/editortempoptionpage.ui \
|
||||
gui/filelayout.ui
|
||||
|
||||
RESOURCES += resources/icons.qrc \
|
||||
RESOURCES += \
|
||||
resources/icons.qrc \
|
||||
resources/scripts.qrc
|
||||
|
||||
TRANSLATIONS = translations/tageditor_en_US.ts \
|
||||
translations/tageditor_de_DE.ts
|
||||
include(translations.pri)
|
||||
|
||||
win32:include(windowsicon.pri)
|
||||
|
||||
OTHER_FILES += \
|
||||
README.md \
|
||||
LICENSE
|
||||
LICENSE \
|
||||
CMakeLists.txt \
|
||||
resources/config.h.in \
|
||||
resources/windows.rc.in
|
||||
|
||||
# release translations
|
||||
include(translations.pri)
|
||||
|
||||
# make windows icon
|
||||
win32:include(windowsicon.pri)
|
||||
|
||||
# add libs
|
||||
CONFIG(debug, debug|release) {
|
||||
LIBS += -lc++utilitiesd -ltagparserd
|
||||
!no-gui {
|
||||
|
|
Loading…
Reference in New Issue