2015-09-06 20:20:00 +02:00
# include "./htmlinfo.h"
2015-04-22 19:33:53 +02:00
# include <tagparser/signature.h>
# include <tagparser/mediafileinfo.h>
# include <tagparser/abstractcontainer.h>
# include <tagparser/matroska/matroskacontainer.h>
# include <tagparser/matroska/matroskaeditionentry.h>
# include <tagparser/mp4/mp4container.h>
# include <tagparser/abstracttrack.h>
# include <tagparser/abstractattachment.h>
# include <tagparser/notification.h>
# include <qtutilities/resources/resources.h>
# include <c++utilities/chrono/timespan.h>
# include <c++utilities/chrono/datetime.h>
# include <c++utilities/conversion/stringconversion.h>
2017-04-27 22:10:55 +02:00
# if defined(TAGEDITOR_GUI_QTWIDGETS)
2016-04-24 21:07:36 +02:00
# include <QApplication>
# include <QStyle>
2017-04-27 22:10:55 +02:00
# elif defined(TAGEDITOR_GUI_QTQUICK)
2016-04-24 21:07:36 +02:00
# include <QGuiApplication>
2015-04-22 19:33:53 +02:00
# endif
2017-04-27 22:10:55 +02:00
# if defined(TAGEDITOR_GUI_QTWIDGETS) || defined(TAGEDITOR_GUI_QTQUICK)
2016-04-24 21:07:36 +02:00
# include <QFont>
# include <QFontMetrics>
# include <QIcon>
2015-04-22 19:33:53 +02:00
# endif
# include <QString>
2015-11-25 22:09:31 +01:00
# include <QStringBuilder>
2015-04-22 19:33:53 +02:00
# include <QResource>
# include <QBuffer>
# include <QByteArray>
2015-11-25 22:09:31 +01:00
# include <QXmlStreamWriter>
# ifdef QT_DEBUG
2016-04-24 21:07:36 +02:00
# include <QFile>
2015-11-25 22:09:31 +01:00
# endif
2015-04-22 19:33:53 +02:00
# include <list>
2017-04-27 22:10:55 +02:00
# if defined(TAGEDITOR_GUI_QTWIDGETS) || defined(TAGEDITOR_GUI_QTQUICK)
2015-11-25 22:09:31 +01:00
# define APPEND_GUI_RULE(rule, fallback) \
if ( ApplicationInstances : : hasGuiApp ( ) ) { \
2017-04-27 22:10:55 +02:00
res . append ( rule ) ; \
2015-11-25 22:09:31 +01:00
} else { \
2017-04-27 22:10:55 +02:00
res . append ( fallback ) ; \
2015-11-25 22:09:31 +01:00
}
# else
# define APPEND_GUI_RULE(rule, fallback) \
res . append ( fallback ) ;
# endif
2015-04-22 19:33:53 +02:00
using namespace std ;
using namespace ConversionUtilities ;
using namespace ChronoUtilities ;
using namespace Media ;
namespace HtmlInfo {
inline QString qstr ( const char * cstr )
{
2016-12-20 23:53:33 +01:00
return QString : : fromUtf8 ( cstr ) ;
2015-04-22 19:33:53 +02:00
}
inline QString qstr ( const string & stdstr )
{
2016-12-20 23:53:33 +01:00
return QString : : fromUtf8 ( stdstr . data ( ) , static_cast < int > ( stdstr . size ( ) ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
class RowMaker
2015-04-22 19:33:53 +02:00
{
2015-11-25 22:09:31 +01:00
public :
RowMaker ( QXmlStreamWriter & writer ) :
writer ( writer ) ,
m_even ( true )
{ }
2015-04-22 19:33:53 +02:00
2015-11-25 22:09:31 +01:00
void reset ( )
{
m_even = true ;
}
void startRow ( const QString & label , bool head = true )
{
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
if ( ( m_even = ! m_even ) ) {
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " even " ) ) ;
}
writer . writeTextElement ( head ? QStringLiteral ( " th " ) : QStringLiteral ( " td " ) , label ) ;
writer . writeStartElement ( QStringLiteral ( " td " ) ) ;
}
void startRow ( const QString & label , const QString & helpText )
{
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
if ( ( m_even = ! m_even ) ) {
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " even " ) ) ;
}
writer . writeAttribute ( QStringLiteral ( " title " ) , helpText ) ;
writer . writeTextElement ( QStringLiteral ( " th " ) , label ) ;
writer . writeStartElement ( QStringLiteral ( " td " ) ) ;
}
void endRow ( )
{
writer . writeEndElement ( ) ;
writer . writeEndElement ( ) ;
}
void mkRow ( const QString & label , const QString & text , bool head = true )
{
startRow ( label , head ) ;
writer . writeCharacters ( text ) ;
endRow ( ) ;
}
void mkRow ( const QString & label , const QString & helpText , const QString & text )
{
startRow ( label , helpText ) ;
writer . writeCharacters ( text ) ;
endRow ( ) ;
}
2017-08-20 02:01:37 +02:00
void startSubTab ( const QString & subLabel , size_t index , unsigned int level = 0 )
2015-11-25 22:09:31 +01:00
{
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
if ( ( m_even = ! m_even ) ) {
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " even " ) ) ;
}
writer . writeStartElement ( QStringLiteral ( " th " ) ) ;
writer . writeCharacters ( subLabel % QStringLiteral ( " # " ) % QString : : number ( index ) ) ;
if ( level ) {
writer . writeEmptyElement ( QStringLiteral ( " br " ) ) ;
writer . writeCharacters ( QString : : number ( level ) ) ;
}
writer . writeEndElement ( ) ;
writer . writeStartElement ( QStringLiteral ( " td " ) ) ;
writer . writeStartElement ( QStringLiteral ( " table " ) ) ;
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " headervertical " ) ) ;
writer . writeStartElement ( QStringLiteral ( " tbody " ) ) ;
}
void startSubTab ( const QString & subLabel )
{
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
if ( ( m_even = ! m_even ) ) {
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " even " ) ) ;
}
writer . writeTextElement ( QStringLiteral ( " th " ) , subLabel ) ;
writer . writeStartElement ( QStringLiteral ( " td " ) ) ;
writer . writeStartElement ( QStringLiteral ( " table " ) ) ;
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " headervertical " ) ) ;
writer . writeStartElement ( QStringLiteral ( " tbody " ) ) ;
}
void startHorizontalSubTab ( const QString & subLabel , const QStringList & headerLabels )
{
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
if ( ( m_even = ! m_even ) ) {
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " even " ) ) ;
}
writer . writeTextElement ( QStringLiteral ( " th " ) , subLabel ) ;
writer . writeStartElement ( QStringLiteral ( " td " ) ) ;
writer . writeStartElement ( QStringLiteral ( " table " ) ) ;
writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " headerhorizontal " ) ) ;
writer . writeStartElement ( QStringLiteral ( " thead " ) ) ;
writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
for ( const auto & label : headerLabels ) {
writer . writeTextElement ( QStringLiteral ( " th " ) , label ) ;
}
writer . writeEndElement ( ) ;
writer . writeEndElement ( ) ;
writer . writeStartElement ( QStringLiteral ( " tbody " ) ) ;
}
void endSubTab ( )
{
writer . writeEndElement ( ) ;
writer . writeEndElement ( ) ;
writer . writeEndElement ( ) ;
writer . writeEndElement ( ) ;
}
private :
QXmlStreamWriter & writer ;
bool m_even ;
} ;
2015-06-11 00:25:10 +02:00
2015-04-22 19:33:53 +02:00
QString mkFontStyle ( const QFont & font )
{
QString style ;
switch ( font . style ( ) ) {
case QFont : : StyleItalic :
style = QStringLiteral ( " italic " ) ;
break ;
case QFont : : StyleOblique :
style = QStringLiteral ( " oblique " ) ;
break ;
default :
style = QStringLiteral ( " normal " ) ;
}
QString weight ;
switch ( font . weight ( ) ) {
case QFont : : Light :
weight = QStringLiteral ( " light " ) ;
break ;
case QFont : : Bold :
weight = QStringLiteral ( " bold " ) ;
break ;
case QFont : : Black :
weight = QStringLiteral ( " bolder " ) ;
break ;
default :
weight = QStringLiteral ( " normal " ) ;
}
QString size ;
if ( font . pixelSize ( ) > 0 ) {
size = QStringLiteral ( " %1px " ) . arg ( font . pixelSize ( ) ) ;
} else {
size = QStringLiteral ( " %1pt " ) . arg ( font . pointSize ( ) ) ;
}
2015-11-25 22:09:31 +01:00
return QStringLiteral ( " font-family: \" %1 \" , sans-serif; "
2015-04-22 19:33:53 +02:00
" font-style: %2; "
" font-weight: %3; "
" font-size: %4; " ) . arg (
font . family ( ) , style , weight , size ) ;
}
QByteArray mkBase64 ( const QIcon & icon )
{
QByteArray bytes ;
QBuffer buffer ( & bytes ) ;
buffer . open ( QIODevice : : WriteOnly ) ;
icon . pixmap ( 16 , 16 ) . save ( & buffer , " PNG " ) ;
return bytes . toBase64 ( ) ;
}
const QByteArray & mkInfoIconData ( )
{
static const QByteArray data = mkBase64 ( QApplication : : style ( ) - > standardIcon ( QStyle : : SP_MessageBoxInformation ) ) ;
return data ;
}
const QByteArray & mkWarningIconData ( )
{
static const QByteArray data = mkBase64 ( QApplication : : style ( ) - > standardIcon ( QStyle : : SP_MessageBoxWarning ) ) ;
return data ;
}
const QByteArray & mkErrorIconData ( )
{
static const QByteArray data = mkBase64 ( QApplication : : style ( ) - > standardIcon ( QStyle : : SP_MessageBoxCritical ) ) ;
return data ;
}
const QByteArray & mkDebugIconData ( )
{
2015-11-25 22:09:31 +01:00
static const QByteArray data = mkBase64 ( QIcon ( QStringLiteral ( " :/images/bug " ) ) ) ;
2015-04-22 19:33:53 +02:00
return data ;
}
2015-11-25 22:09:31 +01:00
template < class ElementType > void mkElementContent ( QXmlStreamWriter & , ElementType * )
{ }
2015-04-22 19:33:53 +02:00
2015-11-25 22:09:31 +01:00
template < > void mkElementContent ( QXmlStreamWriter & writer , EbmlElement * element )
2015-04-22 19:33:53 +02:00
{
2015-11-25 22:09:31 +01:00
switch ( element - > id ( ) ) {
case MatroskaIds : : SeekID : {
const uint64 seekId = element - > readUInteger ( ) ;
writer . writeCharacters ( QStringLiteral ( " , denoted type: 0x " ) ) ;
writer . writeCharacters ( QString : : number ( seekId , 16 ) ) ;
2017-08-20 02:01:37 +02:00
if ( seekId < = numeric_limits < uint32 > : : max ( ) ) {
const char * const seekIdName = matroskaIdName ( static_cast < uint32 > ( seekId ) ) ;
if ( * seekIdName ) {
writer . writeCharacters ( QStringLiteral ( " \" " ) ) ;
writer . writeCharacters ( QString : : fromLatin1 ( seekIdName ) ) ;
writer . writeCharacters ( QStringLiteral ( " \" " ) ) ;
}
2015-11-25 22:09:31 +01:00
}
break ;
} case MatroskaIds : : SeekPosition : {
writer . writeCharacters ( QStringLiteral ( " , denoted position: " ) ) ;
const uint64 seekPos = element - > readUInteger ( ) ;
const auto seekPosStr = QString : : number ( seekPos ) ;
writer . writeStartElement ( QStringLiteral ( " span " ) ) ;
writer . writeAttribute ( QStringLiteral ( " data-role " ) , QStringLiteral ( " offset " ) ) ;
writer . writeAttribute ( QStringLiteral ( " data-dec " ) , seekPosStr ) ;
writer . writeAttribute ( QStringLiteral ( " data-hex " ) , QString : : number ( seekPos , 16 ) ) ;
writer . writeCharacters ( seekPosStr ) ;
writer . writeEndElement ( ) ;
2017-08-20 02:01:37 +02:00
break ;
2015-11-25 22:09:31 +01:00
} default :
;
}
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
class Generator
2015-04-22 19:33:53 +02:00
{
2015-11-25 22:09:31 +01:00
public :
2015-04-22 19:33:53 +02:00
2015-11-25 22:09:31 +01:00
Generator ( const MediaFileInfo & file , NotificationList & originalNotifications ) :
m_writer ( & m_res ) ,
m_rowMaker ( m_writer ) ,
m_file ( file ) ,
originalNotifications ( originalNotifications )
{ }
2015-08-08 02:33:31 +02:00
2015-11-25 22:09:31 +01:00
QString mkStyle ( )
{
QString res ;
res . append ( QStringLiteral ( " html, body { "
" padding: 1px; "
" margin: 0px; " ) ) ;
# ifndef GUI_NONE
QPalette palette ;
if ( ApplicationInstances : : hasGuiApp ( ) ) {
palette = QGuiApplication : : palette ( ) ;
res . append ( mkFontStyle ( QGuiApplication : : font ( ) ) ) ;
res . append ( QStringLiteral ( " background-color: %1; " ) . arg ( palette . color ( QPalette : : Base ) . name ( ) ) ) ;
res . append ( QStringLiteral ( " color: %1; " ) . arg ( palette . color ( QPalette : : Text ) . name ( ) ) ) ;
2015-06-11 00:25:10 +02:00
} else {
2015-11-25 22:09:31 +01:00
# endif
res . append ( QStringLiteral ( " background-color: #fff; "
" color: #000; " ) ) ;
# ifndef GUI_NONE
2015-06-11 00:25:10 +02:00
}
2015-11-25 22:09:31 +01:00
# endif
res . append ( QStringLiteral ( " } "
" a:link, #structure .parent-node { " ) ) ;
APPEND_GUI_RULE ( QStringLiteral ( " color: %1; " ) . arg ( palette . color ( QPalette : : Link ) . name ( ) ) ,
QStringLiteral ( " color: #337AB7; " ) )
res . append ( QStringLiteral ( " text-decoration: none; "
" } "
" a:focus, a:hover { " ) ) ;
APPEND_GUI_RULE ( QStringLiteral ( " color: %1; " ) . arg ( palette . link ( ) . color ( ) . darker ( palette . color ( QPalette : : Background ) . lightness ( ) > palette . color ( QPalette : : Link ) . lightness ( ) ? 150 : 50 ) . name ( ) ) ,
QStringLiteral ( " color: #23527c; " ) )
res . append ( QStringLiteral ( " text-decoration: underline; "
" } table { "
" border-collapse: collapse; "
" width: 100%; "
" } tr { " ) ) ;
APPEND_GUI_RULE ( QStringLiteral ( " background-color: %1; " ) . arg ( palette . color ( QPalette : : Base ) . name ( ) ) ,
QStringLiteral ( " background-color: #fff; " ) )
res . append ( QStringLiteral ( " } tr.even { " ) ) ;
APPEND_GUI_RULE ( QStringLiteral ( " background-color: %1!important; " ) . arg ( palette . color ( QPalette : : AlternateBase ) . name ( ) ) , QStringLiteral ( " background-color: #fafafa!important; " ) )
res . append ( QStringLiteral ( " } "
" table.headervertical th, table.headervertical td { "
" padding: 2px 5px; "
" text-align: left; "
" vertical-align: top; "
" } "
" table.headervertical > tbody > tr > th { "
" text-align: right; "
" border: none; "
" width: 25%; "
" } "
" table.headerhorizontal > thead > tr > th { "
" text-align: center; "
" border: none; "
" } "
" .more { "
" display: none; "
" } "
" .more tr > th { "
" font-weight: normal; "
" } "
" .nodecollapsed { "
" display: none; "
" } "
" .nodeexpaned { "
" display: block; "
" } "
" table.headerhorizontal > thead > tr > th { "
" font-weight: bold; "
" } "
" td table.headervertical > thead > tr > th { "
" font-weight: normal; "
" border: none; "
" background-color: transparent; "
" } "
" th { "
" cursor: default; "
" } "
" td.warning, td.critical, td.information { "
" width: 18px; "
" background-repeat: no-repeat; "
" background-position:center; "
" } "
" .has-helptext { "
" cursor: help; "
" } "
" #structure_links a { "
" margin-right: 5px; "
" } " ) ) ;
2017-04-27 22:10:55 +02:00
# if defined(TAGEDITOR_GUI_QTWIDGETS)
2015-11-25 22:09:31 +01:00
if ( ApplicationInstances : : hasWidgetsApp ( ) ) {
res . append ( QStringLiteral ( " td.warning {background-image: url(data:image/png;base64, " ) ) ;
res . append ( mkWarningIconData ( ) ) ;
res . append ( QStringLiteral ( " );}td.critical {background-image: url(data:image/png;base64, " ) ) ;
res . append ( mkErrorIconData ( ) ) ;
res . append ( QStringLiteral ( " );}td.information {background-image: url(data:image/png;base64, " ) ) ;
res . append ( mkInfoIconData ( ) ) ;
res . append ( QStringLiteral ( " );} " ) ) ;
2015-09-24 01:15:48 +02:00
}
2015-11-25 22:09:31 +01:00
# endif
res . append ( QStringLiteral ( " ul { "
" margin: 0px; "
" padding: 0px 0px 0px 15px; "
" list-style-type: none; "
" } " ) ) ;
return res ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
QString mkScript ( )
{
QString res ;
res . append ( QStringLiteral ( " function toggleVisibility(link, objid) { "
" var obj = document.getElementById(objid); "
" if(obj.style.display === \" none \" || (obj.style.display === \" \" && obj.className === \" more \" )) { "
" if(obj.nodeName === \" TBODY \" || obj.nodeName === \" tbody \" ) { "
" obj.style.display = \" table-row-group \" ; "
" } else { "
" obj.style.display = \" block \" ; "
" } "
" link.defaultText = link.innerHTML; "
" link.innerHTML = \" " ) ) ;
res . append ( QCoreApplication : : translate ( " HtmlInfo " , " hide " ) ) ;
res . append ( QStringLiteral ( " \" ; "
" } else { "
" obj.style.display = \" none \" ; "
" link.innerHTML = link.defaultText; "
" }} "
" function expandCollapse(parent) { "
" for(var children = parent.children, i = 0, c = children.length; i < c; ++i) { "
" if(children[i].tagName === 'UL' || children[i].tagName === 'ul') { "
" children[i].className = children[i].className === 'nodeexpanded' ? 'nodecollapsed' : 'nodeexpanded'; "
" }}} "
" function expandAll(objid) { "
" var children = document.getElementById(objid).getElementsByTagName('ul'); "
" for(var i = 0; i < children.length; ++i) { "
" children[i].className = 'nodeexpanded'; "
" }} "
" function collapseAll(objid) { "
" var children = document.getElementById(objid).getElementsByTagName('ul'); "
" for(var i = 0; i < children.length; ++i) { "
" if(children[i].parentNode.tagName === 'LI' || children[i].parentNode.tagName === 'li') { "
" children[i].className = 'nodecollapsed'; "
" }}} "
" var baseHex = false; "
" function switchBase(objid) { "
" baseHex = !baseHex; "
" document.getElementById('toggle_hex_link').firstChild.data = baseHex ? 'decimal' : 'hex'; "
" var elements = document.getElementById(objid).getElementsByTagName('span'); "
" for(var i = 0; i < elements.length; ++i) { "
" var element = elements[i]; "
" if(element.getAttribute('data-role') === 'offset') { "
" element.firstChild.data = element.getAttribute(baseHex ? 'data-hex' : 'data-dec'); "
" }}} " ) ) ;
return res ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void startVerticalTable ( )
{
m_writer . writeStartElement ( QStringLiteral ( " table " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " headervertical " ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void startTableSection ( const QString & id )
{
m_writer . writeStartElement ( QStringLiteral ( " tbody " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " id " ) , id ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void startTableSection ( )
{
m_writer . writeStartElement ( QStringLiteral ( " tbody " ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void startExtendedTableSection ( const QString & id )
{
startTableSection ( id ) ;
m_writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " more " ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void mkSpace ( )
{
m_writer . writeCharacters ( QStringLiteral ( " " ) ) ;
2015-04-22 19:33:53 +02:00
}
2017-08-17 19:10:20 +02:00
void mkBreak ( )
{
m_writer . writeStartElement ( QStringLiteral ( " br " ) ) ;
m_writer . writeEndElement ( ) ;
}
2015-11-25 22:09:31 +01:00
void mkDetailsLink ( const QString & id , const QString & text )
{
m_writer . writeStartElement ( QStringLiteral ( " a " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " href " ) , QStringLiteral ( " # " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " onclick " ) , QStringLiteral ( " toggleVisibility(this, ' " ) % id % QStringLiteral ( " '); return false; " ) ) ;
m_writer . writeCharacters ( text ) ;
m_writer . writeEndElement ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void mkTrack ( const AbstractTrack * track , unsigned int trackNumber )
{
RowMaker rowMaker ( m_writer ) ;
rowMaker . startSubTab ( QCoreApplication : : translate ( " HtmlInfo " , " Track " ) , trackNumber ) ;
if ( track - > id ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " ID " ) , QCoreApplication : : translate ( " HtmlInfo " , " The unique number used to identify the track in the container file. " ) , QString : : number ( track - > id ( ) ) ) ;
}
if ( track - > trackNumber ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Number " ) , QCoreApplication : : translate ( " HtmlInfo " , " The index of the track in the container file. " ) , QString : : number ( track - > trackNumber ( ) ) ) ;
}
if ( ! track - > name ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Name " ) , qstr ( track - > name ( ) ) ) ;
}
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Type " ) , qstr ( track - > mediaTypeName ( ) ) ) ;
const char * fmtName = track - > formatName ( ) , * fmtAbbr = track - > formatAbbreviation ( ) ;
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Format " ) , QCoreApplication : : translate ( " HtmlInfo " , " The unabbreviated name of the track's format. " ) , qstr ( fmtName ) ) ;
2016-05-16 21:01:01 +02:00
if ( track - > format ( ) ! = GeneralMediaFormat : : Unknown & & strcmp ( fmtName , fmtAbbr ) ) { // format name and abbreviation differ
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Abbreviation " ) , QCoreApplication : : translate ( " HtmlInfo " , " The abbreviated name of the track's format. " ) , qstr ( fmtAbbr ) ) ;
}
2017-08-20 02:01:37 +02:00
if ( track - > version ( ) ! = 0.0 ) {
2016-02-17 20:23:37 +01:00
switch ( track - > format ( ) . general ) {
case GeneralMediaFormat : : Mpeg4Video :
case GeneralMediaFormat : : Avc :
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Level " ) , QCoreApplication : : translate ( " HtmlInfo " , " The version/level of the track's format. " ) , QChar ( ' L ' ) + QString : : number ( track - > version ( ) ) ) ;
break ;
default :
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Version " ) , QCoreApplication : : translate ( " HtmlInfo " , " The version/level of the track's format. " ) , QString : : number ( track - > version ( ) ) ) ;
}
}
2015-11-25 22:09:31 +01:00
fmtName = track - > format ( ) . extensionName ( ) ;
if ( * fmtName ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Extension " ) , QCoreApplication : : translate ( " HtmlInfo " , " Used format extensions. " ) , qstr ( fmtName ) ) ;
}
if ( ! track - > formatId ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Format/codec ID " ) , QCoreApplication : : translate ( " HtmlInfo " , " The raw format/codec identifier extracted from the container. " ) , qstr ( track - > formatId ( ) ) ) ;
}
if ( track - > size ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Size " ) , qstr ( dataSizeToString ( track - > size ( ) , true ) ) ) ;
}
if ( ! track - > duration ( ) . isNull ( ) ) {
2016-06-14 00:52:03 +02:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Duration " ) , qstr ( track - > duration ( ) . toString ( TimeSpanOutputFormat : : WithMeasures ) ) % QStringLiteral ( " ( " ) % QString : : number ( track - > duration ( ) . totalTicks ( ) ) % QChar ( ' ) ' ) ) ;
2015-11-25 22:09:31 +01:00
}
2017-08-20 02:01:37 +02:00
if ( track - > bitrate ( ) ! = 0.0 ) {
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Avg. bitrate " ) , qstr ( bitrateToString ( track - > bitrate ( ) ) ) ) ;
}
2017-08-20 02:01:37 +02:00
if ( track - > maxBitrate ( ) ! = 0.0 ) {
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Maximum bitrate " ) , qstr ( bitrateToString ( track - > maxBitrate ( ) ) ) ) ;
}
if ( ! track - > creationTime ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Creation time " ) , qstr ( track - > creationTime ( ) . toString ( DateTimeOutputFormat : : DateAndTime , true ) ) ) ;
}
if ( ! track - > modificationTime ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Modification time " ) , qstr ( track - > modificationTime ( ) . toString ( DateTimeOutputFormat : : DateAndTime , true ) ) ) ;
}
if ( ! track - > language ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Language " ) , qstr ( track - > language ( ) ) ) ;
}
if ( ! track - > compressorName ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Compressor name " ) , qstr ( track - > compressorName ( ) ) ) ;
}
if ( track - > samplingFrequency ( ) ) {
if ( track - > extensionSamplingFrequency ( ) ) {
2016-02-17 20:23:37 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Sampling frequency " ) , QString : : number ( track - > extensionSamplingFrequency ( ) ) % QStringLiteral ( " Hz / " ) % QString : : number ( track - > samplingFrequency ( ) ) % QStringLiteral ( " Hz " ) ) ;
2015-11-25 22:09:31 +01:00
} else {
2016-02-17 20:23:37 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Sampling frequency " ) , QString : : number ( track - > samplingFrequency ( ) ) + QStringLiteral ( " Hz " ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
}
if ( track - > sampleCount ( ) ) {
2017-06-27 00:37:56 +02:00
rowMaker . mkRow ( track - > mediaType ( ) = = MediaType : : Video
? QCoreApplication : : translate ( " HtmlInfo " , " Frame count " )
: QCoreApplication : : translate ( " HtmlInfo " , " Sample count " ) ,
QString : : number ( track - > sampleCount ( ) ) ) ;
2015-11-25 22:09:31 +01:00
}
if ( track - > bitsPerSample ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Bits per sample " ) , QString : : number ( track - > bitsPerSample ( ) ) ) ;
}
if ( track - > quality ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Quality " ) , QString : : number ( track - > quality ( ) ) ) ;
}
if ( ! track - > pixelSize ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Pixel size " ) , qstr ( track - > pixelSize ( ) . toString ( ) ) ) ;
}
if ( ! track - > displaySize ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Display size " ) , qstr ( track - > displaySize ( ) . toString ( ) ) ) ;
}
2016-04-24 21:07:36 +02:00
if ( track - > pixelAspectRatio ( ) . isValid ( ) ) {
2016-02-17 20:23:37 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Pixel Aspect Ratio " ) , QString : : number ( track - > pixelAspectRatio ( ) . numerator ) % QStringLiteral ( " : " ) % QString : : number ( track - > pixelAspectRatio ( ) . denominator ) ) ;
}
2015-11-25 22:09:31 +01:00
if ( ! track - > cropping ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Cropping " ) , qstr ( track - > cropping ( ) . toString ( ) ) ) ;
}
if ( ! track - > resolution ( ) . isNull ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Resolution " ) , qstr ( track - > resolution ( ) . toString ( ) ) ) ;
}
if ( track - > channelConfigString ( ) ) {
if ( track - > extensionChannelConfigString ( ) ) {
2016-12-20 23:53:33 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Channel config " ) , QCoreApplication : : translate ( " HtmlInfo " , " Channel configuration " ) , QStringLiteral ( " %1 / %2 " ) . arg ( QString : : fromUtf8 ( track - > extensionChannelConfigString ( ) ) , QString : : fromUtf8 ( track - > channelConfigString ( ) ) ) ) ;
2015-11-25 22:09:31 +01:00
} else {
2016-12-20 23:53:33 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Channel config " ) , QCoreApplication : : translate ( " HtmlInfo " , " Channel configuration " ) , QString : : fromUtf8 ( track - > channelConfigString ( ) ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
} else if ( track - > channelCount ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Channel count " ) , QString : : number ( track - > channelCount ( ) ) ) ;
}
if ( track - > depth ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Bit depth " ) , QString : : number ( track - > depth ( ) ) ) ;
}
if ( track - > fps ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Frames per second " ) , QString : : number ( track - > fps ( ) ) ) ;
}
2016-02-17 20:23:37 +01:00
if ( track - > chromaFormat ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Chroma format " ) , qstr ( track - > chromaFormat ( ) ) ) ;
}
2016-04-24 21:07:36 +02:00
QStringList labels ;
2015-11-25 22:09:31 +01:00
if ( track - > isInterlaced ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " interlaced " ) ;
2015-11-25 22:09:31 +01:00
}
if ( ! track - > isEnabled ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " disabled " ) ;
2015-11-25 22:09:31 +01:00
}
if ( track - > isDefault ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " default " ) ;
2015-11-25 22:09:31 +01:00
}
if ( track - > isForced ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " forced " ) ;
2015-11-25 22:09:31 +01:00
}
if ( track - > hasLacing ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " has lacing " ) ;
2015-11-25 22:09:31 +01:00
}
if ( track - > isEncrypted ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " encrypted " ) ;
2015-04-22 19:33:53 +02:00
}
2016-04-24 21:07:36 +02:00
if ( ! labels . isEmpty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Labeled as " ) , labels . join ( QStringLiteral ( " , " ) ) ) ;
2015-11-25 22:09:31 +01:00
}
rowMaker . endSubTab ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void mkAttachment ( const AbstractAttachment * attachment , unsigned int attachmentNumber )
{
RowMaker rowMaker ( m_writer ) ;
m_rowMaker . startSubTab ( QCoreApplication : : translate ( " HtmlInfo " , " Attachment " ) , attachmentNumber ) ;
if ( attachment - > id ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " ID " ) , QString : : number ( attachment - > id ( ) ) ) ;
}
if ( ! attachment - > name ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Name " ) , qstr ( attachment - > name ( ) ) ) ;
}
if ( attachment - > data ( ) ) {
2017-08-20 02:01:37 +02:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Size " ) , qstr ( dataSizeToString ( static_cast < uint64 > ( attachment - > data ( ) - > size ( ) ) , true ) ) ) ;
2015-11-25 22:09:31 +01:00
}
if ( ! attachment - > mimeType ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Mime-type " ) , qstr ( attachment - > mimeType ( ) ) ) ;
}
if ( ! attachment - > description ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Description " ) , qstr ( attachment - > description ( ) ) ) ;
}
rowMaker . endSubTab ( ) ;
2015-04-22 19:33:53 +02:00
}
2017-08-20 02:01:37 +02:00
void mkChapter ( const AbstractChapter & chapter , size_t chapterNumber , unsigned int level = 0 )
2015-11-25 22:09:31 +01:00
{
RowMaker rowMaker ( m_writer ) ;
rowMaker . startSubTab ( QCoreApplication : : translate ( " HtmlInfo " , " Chapter " ) , chapterNumber + 1 , level ) ;
if ( chapter . id ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " ID " ) , QString : : number ( chapter . id ( ) ) ) ;
}
for ( const LocaleAwareString & name : chapter . names ( ) ) {
static const string delim ( " , " ) ;
2016-04-24 21:07:36 +02:00
const string locale = joinStrings ( initializer_list < string > { joinStrings ( name . languages ( ) , delim , true ) , joinStrings ( name . countries ( ) , delim , true ) } , delim , true ) ;
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Name (%1) " ) . arg ( qstr ( locale ) ) , qstr ( name ) ) ;
}
2016-07-11 21:12:02 +02:00
if ( ! chapter . startTime ( ) . isNegative ( ) ) {
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Start time " ) , qstr ( chapter . startTime ( ) . toString ( TimeSpanOutputFormat : : WithMeasures ) ) ) ;
}
2016-07-11 21:12:02 +02:00
if ( ! chapter . endTime ( ) . isNegative ( ) ) {
2015-11-25 22:09:31 +01:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " End time " ) , qstr ( chapter . endTime ( ) . toString ( TimeSpanOutputFormat : : WithMeasures ) ) ) ;
}
2016-04-24 21:07:36 +02:00
QStringList labels ;
2015-11-25 22:09:31 +01:00
if ( chapter . isHidden ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " hidden " ) ;
2015-11-25 22:09:31 +01:00
}
if ( ! chapter . isEnabled ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " disabled " ) ;
2015-11-25 22:09:31 +01:00
}
2016-04-24 21:07:36 +02:00
if ( ! labels . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Labeled as " ) , labels . join ( QStringLiteral ( " , " ) ) ) ;
2015-11-25 22:09:31 +01:00
}
2016-04-24 21:07:36 +02:00
if ( ! chapter . tracks ( ) . empty ( ) ) {
2015-11-25 22:09:31 +01:00
QStringList trackIds ;
for ( uint64 id : chapter . tracks ( ) ) {
trackIds < < QString : : number ( id ) ;
}
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Tracks " ) , trackIds . join ( QStringLiteral ( " , " ) ) ) ;
}
rowMaker . endSubTab ( ) ;
+ + level ;
for ( size_t i = 0 , nestedChapters = chapter . nestedChapterCount ( ) ; i < nestedChapters ; + + i ) {
mkChapter ( * chapter . nestedChapter ( i ) , i , level ) ;
}
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void mkEdition ( const MatroskaEditionEntry & edition , unsigned int editionNumber )
{
RowMaker rowMaker ( m_writer ) ;
rowMaker . startSubTab ( QCoreApplication : : translate ( " HtmlInfo " , " Edition " ) , editionNumber + 1 ) ;
if ( edition . id ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " ID " ) , QString : : number ( edition . id ( ) ) ) ;
}
2016-04-24 21:07:36 +02:00
QStringList labels ;
2015-11-25 22:09:31 +01:00
if ( edition . isHidden ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " hidden " ) ;
2015-11-25 22:09:31 +01:00
}
if ( edition . isDefault ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " default " ) ;
2015-11-25 22:09:31 +01:00
}
if ( edition . isOrdered ( ) ) {
2016-04-24 21:07:36 +02:00
labels < < QCoreApplication : : translate ( " HtmlInfo " , " ordered " ) ;
2015-11-25 22:09:31 +01:00
}
2016-04-24 21:07:36 +02:00
if ( ! labels . isEmpty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Labeled as " ) , labels . join ( QStringLiteral ( " , " ) ) ) ;
2015-11-25 22:09:31 +01:00
}
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Chapters " ) ,
2017-08-20 02:01:37 +02:00
QCoreApplication : : translate ( " HtmlInfo " , " edition contains %1 chapter(s) " , nullptr , static_cast < int > ( edition . chapters ( ) . size ( ) ) ) . arg ( edition . chapters ( ) . size ( ) ) ) ;
2015-11-25 22:09:31 +01:00
rowMaker . endSubTab ( ) ;
unsigned int chapterNumber = 0 ;
for ( const auto & chapter : edition . chapters ( ) ) {
mkChapter ( * chapter , chapterNumber ) ;
+ + chapterNumber ;
}
2015-09-10 20:00:13 +02:00
}
2015-11-25 22:09:31 +01:00
template < class ElementType , bool isAdditional = false > void mkElementNode ( ElementType * element )
{
m_writer . writeStartElement ( QStringLiteral ( " ul " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " class " ) , element & & element - > parent ( ) ? QStringLiteral ( " nodecollapsed " ) : QStringLiteral ( " nodeexpanded " ) ) ;
while ( element ) {
if ( element - > isParsed ( ) ) {
m_writer . writeStartElement ( QStringLiteral ( " li " ) ) ;
if ( element - > firstChild ( ) ) {
m_writer . writeStartElement ( QStringLiteral ( " span " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " class " ) , QStringLiteral ( " parent-node " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " onclick " ) , QStringLiteral ( " expandCollapse(this.parentElement); " ) ) ;
}
2017-05-30 23:57:54 +02:00
string idString = element - > idToString ( ) ;
if ( ! idString . empty ( ) ) {
2017-08-20 02:01:37 +02:00
m_writer . writeTextElement ( QStringLiteral ( " em " ) , QString : : fromLatin1 ( idString . data ( ) , static_cast < int > ( idString . size ( ) ) ) ) ;
2017-05-30 23:57:54 +02:00
}
2015-11-25 22:09:31 +01:00
m_writer . writeCharacters ( QStringLiteral ( " @ " ) ) ;
const auto startOffsetStr = QString : : number ( element - > startOffset ( ) ) ;
m_writer . writeStartElement ( QStringLiteral ( " span " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-role " ) , QStringLiteral ( " offset " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-dec " ) , startOffsetStr ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-hex " ) , QString : : number ( element - > startOffset ( ) , 16 ) ) ;
m_writer . writeCharacters ( startOffsetStr ) ;
m_writer . writeEndElement ( ) ;
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " , size: " ) ) ;
const auto sizeStr = QString : : number ( element - > totalSize ( ) ) ;
m_writer . writeStartElement ( QStringLiteral ( " span " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-role " ) , QStringLiteral ( " offset " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-dec " ) , sizeStr ) ;
m_writer . writeAttribute ( QStringLiteral ( " data-hex " ) , QString : : number ( element - > totalSize ( ) , 16 ) ) ;
m_writer . writeCharacters ( sizeStr ) ;
m_writer . writeEndElement ( ) ;
mkElementContent ( m_writer , element ) ;
if ( element - > firstChild ( ) ) {
m_writer . writeEndElement ( ) ;
mkElementNode ( element - > firstChild ( ) ) ;
}
element = element - > nextSibling ( ) ;
m_writer . writeEndElement ( ) ;
} else {
if ( ! isAdditional ) {
m_writer . writeStartElement ( QStringLiteral ( " li " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " style " ) , QStringLiteral ( " color: red; " ) ) ;
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " section has not been analyzed " ) ) ;
m_writer . writeEndElement ( ) ;
}
break ;
}
}
m_writer . writeEndElement ( ) ;
2015-09-10 20:00:13 +02:00
}
2015-11-25 22:09:31 +01:00
template < class ContainerType > void mkElementTree ( ContainerType * container )
{
mkElementNode ( container - > firstElement ( ) ) ;
for ( auto & element : container - > additionalElements ( ) ) {
mkElementNode < typename ContainerType : : elementType , true > ( element . get ( ) ) ;
}
2015-09-10 20:00:13 +02:00
}
2015-11-25 22:09:31 +01:00
void mkNotifications ( NotificationList & notifications , bool reparsing = false )
{
if ( notifications . size ( ) ) {
startTableSection ( ) ;
const QString moreId ( reparsing ? QStringLiteral ( " notificationsReparsingMore " ) : QStringLiteral ( " notificationsMore " ) ) ;
2016-04-24 21:07:36 +02:00
m_rowMaker . startRow ( reparsing ? QCoreApplication : : translate ( " HtmlInfo " , " Notifications (reparsing after saving) " ) : QCoreApplication : : translate ( " HtmlInfo " , " Notifications " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " %1 notification(s) available " , 0 , static_cast < int > ( notifications . size ( ) ) ) . arg ( notifications . size ( ) ) ) ;
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show notifications " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
m_rowMaker . startHorizontalSubTab ( QString ( ) , QStringList ( ) < < QString ( ) < < QCoreApplication : : translate ( " HtmlInfo " , " Context " ) < < QCoreApplication : : translate ( " HtmlInfo " , " Message " ) < < QCoreApplication : : translate ( " HtmlInfo " , " Time " ) ) ;
Notification : : sortByTime ( notifications ) ;
for ( const Notification & notification : notifications ) {
m_writer . writeStartElement ( QStringLiteral ( " tr " ) ) ;
m_writer . writeEmptyElement ( QStringLiteral ( " td " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " class " ) , qstr ( notification . typeName ( ) ) ) ;
2016-08-14 22:48:27 +02:00
m_writer . writeTextElement ( QStringLiteral ( " td " ) , qstr ( notification . context ( ) ) ) ;
2015-11-25 22:09:31 +01:00
m_writer . writeTextElement ( QStringLiteral ( " td " ) , qstr ( notification . message ( ) ) ) ;
m_writer . writeTextElement ( QStringLiteral ( " td " ) , qstr ( notification . creationTime ( ) . toString ( DateTimeOutputFormat : : DateAndTime , false ) ) ) ;
m_writer . writeEndElement ( ) ;
}
m_rowMaker . endSubTab ( ) ;
m_writer . writeEndElement ( ) ;
}
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
void mkDoc ( )
{
# ifdef QT_DEBUG
m_writer . setAutoFormatting ( true ) ;
2015-04-22 19:33:53 +02:00
# endif
2015-11-25 22:09:31 +01:00
// <!DOCTYPE ... <html> <head>
m_writer . writeStartDocument ( ) ;
m_writer . writeDTD ( QStringLiteral ( " <!DOCTYPE html PUBLIC \" -//W3C//DTD XHTML 1.0 Strict//EN \" \" http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd \" > " ) ) ;
m_writer . writeStartElement ( QStringLiteral ( " html " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " xmlns " ) , QStringLiteral ( " http://www.w3.org/1999/xhtml " ) ) ;
m_writer . writeStartElement ( QStringLiteral ( " head " ) ) ;
// <title>
m_writer . writeTextElement ( QStringLiteral ( " title " ) , QCoreApplication : : translate ( " HtmlInfo " , " Info for %1 " ) . arg ( qstr ( m_file . fileName ( ) ) ) ) ;
// <style>
m_writer . writeStartElement ( QStringLiteral ( " style " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " type " ) , QStringLiteral ( " text/css " ) ) ;
m_writer . writeCharacters ( mkStyle ( ) ) ;
m_writer . writeEndElement ( ) ;
// <script>
m_writer . writeStartElement ( QStringLiteral ( " script " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " type " ) , QStringLiteral ( " text/javascript " ) ) ;
m_writer . writeCDATA ( mkScript ( ) ) ;
m_writer . writeEndElement ( ) ;
// </head>
m_writer . writeEndElement ( ) ;
// <body> <table>
m_writer . writeStartElement ( QStringLiteral ( " body " ) ) ;
startVerticalTable ( ) ;
2016-04-24 21:07:36 +02:00
// general information
2015-11-25 22:09:31 +01:00
startTableSection ( QStringLiteral ( " general " ) ) ;
m_rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Path " ) , qstr ( m_file . path ( ) ) ) ;
m_rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Size " ) , qstr ( dataSizeToString ( m_file . size ( ) , true ) ) ) ;
2016-04-24 21:07:36 +02:00
const TimeSpan duration = m_file . duration ( ) ;
2015-11-25 22:09:31 +01:00
if ( ! duration . isNull ( ) ) {
m_rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Duration " ) , qstr ( duration . toString ( TimeSpanOutputFormat : : WithMeasures ) ) ) ;
m_rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Overall avg. bitrate " ) , qstr ( bitrateToString ( 0.0078125 * m_file . size ( ) / duration . totalSeconds ( ) ) ) ) ;
2015-04-22 19:33:53 +02:00
}
2016-04-24 21:07:36 +02:00
const char * const mimeType = m_file . mimeType ( ) ;
2015-11-25 22:09:31 +01:00
if ( * mimeType ) {
m_rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Mime-type " ) , qstr ( mimeType ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Container " ) ) ;
m_writer . writeCharacters ( qstr ( m_file . containerFormatName ( ) ) ) ;
2016-04-24 21:07:36 +02:00
const char * const subversion = m_file . containerFormatSubversion ( ) ;
2015-11-25 22:09:31 +01:00
if ( * subversion ) {
mkSpace ( ) ;
m_writer . writeCharacters ( qstr ( subversion ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
AbstractContainer * container = m_file . container ( ) ;
if ( container | | m_file . paddingSize ( ) ) {
mkSpace ( ) ;
mkDetailsLink ( QStringLiteral ( " containerMore " ) , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
// container
if ( container | | m_file . paddingSize ( ) ) {
startExtendedTableSection ( QStringLiteral ( " containerMore " ) ) ;
RowMaker rowMaker ( m_writer ) ;
if ( container ) {
size_t segmentIndex = 0 ;
for ( const auto & title : container - > titles ( ) ) {
if ( segmentIndex ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Title (segment %1) " ) . arg ( + + segmentIndex ) , qstr ( title ) ) ;
} else {
+ + segmentIndex ;
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Title " ) , qstr ( title ) ) ;
}
}
if ( container - > version ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Version " ) , QString : : number ( container - > version ( ) ) ) ;
}
if ( container - > readVersion ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Read version " ) , QString : : number ( container - > readVersion ( ) ) ) ;
}
if ( ! container - > documentType ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Document type " ) , qstr ( container - > documentType ( ) ) ) ;
}
if ( container - > doctypeVersion ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Document version " ) , QString : : number ( container - > doctypeVersion ( ) ) ) ;
}
if ( container - > doctypeReadVersion ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Document read version " ) , QString : : number ( container - > doctypeReadVersion ( ) ) ) ;
}
}
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 ) ) ;
}
m_writer . writeEndElement ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
// tags
auto tags = m_file . tags ( ) ;
if ( ! tags . empty ( ) ) {
startTableSection ( ) ;
const QString moreId ( QStringLiteral ( " tagsMore " ) ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Tags " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " %1 tag(s) assigned " , 0 , static_cast < int > ( tags . size ( ) ) ) . arg ( tags . size ( ) ) ) ;
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
for ( const Tag * tag : tags ) {
RowMaker rowMaker ( m_writer ) ;
rowMaker . startSubTab ( tag - > typeName ( ) ) ;
if ( ! tag - > version ( ) . empty ( ) ) {
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Version " ) , qstr ( tag - > version ( ) ) ) ;
}
if ( tag - > supportsTarget ( ) & & ! tag - > target ( ) . isEmpty ( ) ) {
2016-05-26 02:15:41 +02:00
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Target level " ) , qstr ( tag - > targetString ( ) ) ) ;
2015-11-25 22:09:31 +01:00
}
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Size " ) , qstr ( dataSizeToString ( tag - > size ( ) , true ) ) ) ;
rowMaker . mkRow ( QCoreApplication : : translate ( " HtmlInfo " , " Field count " ) , QString : : number ( tag - > fieldCount ( ) ) ) ;
rowMaker . endSubTab ( ) ;
}
m_writer . writeEndElement ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
// tracks
2016-04-24 21:07:36 +02:00
const auto tracks = m_file . tracks ( ) ;
2015-11-25 22:09:31 +01:00
if ( ! tracks . empty ( ) ) {
startTableSection ( ) ;
const QString moreId ( QStringLiteral ( " tracksMore " ) ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Tracks " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " file has %1 track(s) " , 0 , static_cast < int > ( tracks . size ( ) ) ) . arg ( tracks . size ( ) ) ) ;
2017-08-17 19:10:20 +02:00
const string summary ( m_file . technicalSummary ( ) ) ;
if ( ! summary . empty ( ) ) {
m_writer . writeCharacters ( QStringLiteral ( " : " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QString : : fromUtf8 ( summary . data ( ) , static_cast < int > ( summary . size ( ) ) ) ) ;
2017-08-17 19:10:20 +02:00
mkBreak ( ) ;
}
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
unsigned int trackNumber = 1 ;
for ( const auto * track : tracks ) {
mkTrack ( track , trackNumber ) ;
+ + trackNumber ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
m_writer . writeEndElement ( ) ;
}
// attachments
auto attachments = m_file . attachments ( ) ;
if ( ! attachments . empty ( ) ) {
startTableSection ( ) ;
const QString moreId ( QStringLiteral ( " attachmentsMore " ) ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Attachments " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " %1 attachment(s) assigned " , 0 , static_cast < int > ( attachments . size ( ) ) ) . arg ( attachments . size ( ) ) ) ;
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
unsigned int attachmentNumber = 1 ;
for ( const auto * attachment : attachments ) {
mkAttachment ( attachment , attachmentNumber ) ;
+ + attachmentNumber ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
m_writer . writeEndElement ( ) ;
}
// chapters
if ( container ) {
if ( m_file . containerFormat ( ) = = ContainerFormat : : Matroska ) {
2016-04-24 21:07:36 +02:00
const auto & editionEntries = static_cast < const MatroskaContainer * > ( container ) - > editionEntires ( ) ;
if ( ! editionEntries . empty ( ) ) {
2015-11-25 22:09:31 +01:00
startTableSection ( ) ;
const QString moreId ( QStringLiteral ( " editionsMore " ) ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Editions/chapters " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " file has %1 edition(s) " , 0 , static_cast < int > ( editionEntries . size ( ) ) ) . arg ( editionEntries . size ( ) ) ) ;
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
unsigned int editionNumber = 0 ;
for ( const auto & edition : static_cast < const MatroskaContainer * > ( container ) - > editionEntires ( ) ) {
mkEdition ( * edition , editionNumber ) ;
+ + editionNumber ;
}
m_writer . writeEndElement ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
} else if ( size_t chapterCount = container - > chapterCount ( ) ) {
startTableSection ( ) ;
const QString moreId ( QStringLiteral ( " chaptersMore " ) ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " chapters " ) ) ;
2017-08-20 02:01:37 +02:00
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " file has %1 chapter(s) " , 0 , static_cast < int > ( chapterCount ) ) . arg ( chapterCount ) ) ;
2015-11-25 22:09:31 +01:00
mkSpace ( ) ;
mkDetailsLink ( moreId , QCoreApplication : : translate ( " HtmlInfo " , " show details " ) ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startExtendedTableSection ( moreId ) ;
for ( size_t i = 0 ; i < chapterCount ; + + i ) {
mkChapter ( * container - > chapter ( i ) , i ) ;
}
m_writer . writeEndElement ( ) ;
2015-04-22 19:33:53 +02:00
}
}
2015-11-25 22:09:31 +01:00
// structure
switch ( m_file . containerFormat ( ) ) {
2015-04-22 19:33:53 +02:00
case ContainerFormat : : Mp4 :
2016-03-14 22:04:14 +01:00
case ContainerFormat : : QuickTime :
2015-04-22 19:33:53 +02:00
case ContainerFormat : : Matroska :
2015-11-25 22:09:31 +01:00
case ContainerFormat : : Webm :
case ContainerFormat : : Ebml :
startTableSection ( ) ;
m_rowMaker . startRow ( QCoreApplication : : translate ( " HtmlInfo " , " Structure " ) ) ;
// links to expand, collapse, switch dec/hex
m_writer . writeStartElement ( QStringLiteral ( " span " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " id " ) , QStringLiteral ( " structure_links " ) ) ;
m_writer . writeStartElement ( QStringLiteral ( " a " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " href " ) , QStringLiteral ( " # " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " onclick " ) , QStringLiteral ( " expandAll('structure'); return false; " ) ) ;
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " expand all " ) ) ;
m_writer . writeEndElement ( ) ;
m_writer . writeStartElement ( QStringLiteral ( " a " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " href " ) , QStringLiteral ( " # " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " onclick " ) , QStringLiteral ( " collapseAll('structure'); return false; " ) ) ;
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " collapse all " ) ) ;
m_writer . writeEndElement ( ) ;
m_writer . writeStartElement ( QStringLiteral ( " a " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " id " ) , QStringLiteral ( " toggle_hex_link " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " href " ) , QStringLiteral ( " # " ) ) ;
m_writer . writeAttribute ( QStringLiteral ( " onclick " ) , QStringLiteral ( " switchBase('structure'); return false; " ) ) ;
m_writer . writeCharacters ( QCoreApplication : : translate ( " HtmlInfo " , " hex " ) ) ;
m_writer . writeEndElement ( ) ;
m_writer . writeEndElement ( ) ;
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
startTableSection ( QStringLiteral ( " structure " ) ) ;
m_rowMaker . startRow ( QString ( ) ) ;
switch ( m_file . containerFormat ( ) ) {
case ContainerFormat : : Mp4 :
2016-03-14 22:04:14 +01:00
case ContainerFormat : : QuickTime :
2015-11-25 22:09:31 +01:00
mkElementTree ( static_cast < Mp4Container * > ( m_file . container ( ) ) ) ;
break ;
case ContainerFormat : : Matroska :
case ContainerFormat : : Webm :
case ContainerFormat : : Ebml :
mkElementTree ( static_cast < MatroskaContainer * > ( m_file . container ( ) ) ) ;
break ;
default :
;
}
m_rowMaker . endRow ( ) ;
m_writer . writeEndElement ( ) ;
2017-08-20 02:01:37 +02:00
break ;
2015-04-22 19:33:53 +02:00
default :
;
}
2015-11-25 22:09:31 +01:00
// notifications
auto currentNotifications = m_file . gatherRelatedNotifications ( ) ;
2017-08-20 02:01:37 +02:00
mkNotifications ( currentNotifications , ! originalNotifications . empty ( ) ) ;
if ( ! originalNotifications . empty ( ) ) {
2015-11-25 22:09:31 +01:00
mkNotifications ( originalNotifications ) ;
}
// </table> </body> </html>
// finalize document
m_writer . writeEndDocument ( ) ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
const QByteArray & res ( )
{
return m_res ;
2015-04-22 19:33:53 +02:00
}
2015-11-25 22:09:31 +01:00
private :
QXmlStreamWriter m_writer ;
QByteArray m_res ;
RowMaker m_rowMaker ;
const MediaFileInfo & m_file ;
NotificationList & originalNotifications ;
} ;
/*!
* \ brief Generates technical information for the specified \ a file .
*
* The parse methods of the \ a file must have already been called .
*
* A QGuiApplication instance should be available for setting fonts .
* A QApplication instance should be available for standard icons .
*/
QByteArray generateInfo ( const MediaFileInfo & file , NotificationList & originalNotifications )
{
Generator gen ( file , originalNotifications ) ;
gen . mkDoc ( ) ;
# ifdef QT_DEBUG
QFile test ( QStringLiteral ( " /tmp/test.xhtml " ) ) ;
test . open ( QFile : : WriteOnly | QFile : : Truncate ) ;
test . write ( gen . res ( ) ) ;
# endif
return gen . res ( ) ;
2015-04-22 19:33:53 +02:00
}
}