Merge branch 'master' into pr/1875
This commit is contained in:
@@ -37,6 +37,8 @@ set(OLIVE_SOURCES
|
||||
common/flipmodifiers.cpp
|
||||
common/flipmodifiers.h
|
||||
common/functiontimer.h
|
||||
common/html.cpp
|
||||
common/html.h
|
||||
common/jobtime.cpp
|
||||
common/jobtime.h
|
||||
common/lerp.h
|
||||
@@ -61,6 +63,7 @@ set(OLIVE_SOURCES
|
||||
common/timerange.cpp
|
||||
common/timerange.h
|
||||
common/tohex.h
|
||||
common/util.h
|
||||
common/xmlutils.cpp
|
||||
common/xmlutils.h
|
||||
PARENT_SCOPE
|
||||
|
||||
@@ -139,7 +139,10 @@ void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bo
|
||||
} else {
|
||||
// Copy file
|
||||
if (overwrite && QFile::exists(dest_file_path)) {
|
||||
QFile::remove(dest_file_path);
|
||||
QFile file(dest_file_path);
|
||||
file.setPermissions(file.permissions() | QFileDevice::WriteOwner | QFileDevice::WriteUser |
|
||||
QFileDevice::WriteGroup | QFileDevice::WriteOther);
|
||||
file.remove();
|
||||
}
|
||||
|
||||
QFile::copy(info.absoluteFilePath(), dest_file_path);
|
||||
@@ -147,27 +150,10 @@ void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bo
|
||||
}
|
||||
}
|
||||
|
||||
bool FileFunctions::DirectoryIsValid(const QString &dir, bool try_to_create)
|
||||
bool FileFunctions::DirectoryIsValid(const QDir &d, bool try_to_create_if_not_exists)
|
||||
{
|
||||
// Empty string is invalid
|
||||
if (dir.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDir d(dir);
|
||||
|
||||
// If directory already exists, this is valid
|
||||
if (d.exists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we can create and creation is successful, this is valid
|
||||
if (try_to_create && d.mkpath(".")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, invalid
|
||||
return false;
|
||||
// Return whether the directory exists, or whether it could be created if it doesn't
|
||||
return d.exists() || d.mkpath(QStringLiteral("."));
|
||||
}
|
||||
|
||||
QString FileFunctions::EnsureFilenameExtension(QString fn, const QString &extension)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef FILEFUNCTIONS_H
|
||||
#define FILEFUNCTIONS_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
#include "common/define.h"
|
||||
@@ -52,7 +53,7 @@ public:
|
||||
|
||||
static void CopyDirectory(const QString& source, const QString& dest, bool overwrite = false);
|
||||
|
||||
static bool DirectoryIsValid(const QString& dir, bool try_to_create);
|
||||
static bool DirectoryIsValid(const QDir& dir, bool try_to_create_if_not_exists = true);
|
||||
|
||||
/**
|
||||
* @brief Ensures a given filename has a certain extension
|
||||
|
||||
@@ -0,0 +1,469 @@
|
||||
#include "html.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTextBlock>
|
||||
|
||||
#include "xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QVector<QString> Html::kBlockTags = {
|
||||
QStringLiteral("p"),
|
||||
QStringLiteral("div")
|
||||
};
|
||||
|
||||
inline bool StrEquals(const QString &a, const QStringRef &b)
|
||||
{
|
||||
return !a.compare(b, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
inline bool StrEquals(const QString &a, const QString &b)
|
||||
{
|
||||
return !a.compare(b, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
inline bool StrEquals(const QStringRef &a, const QString &b)
|
||||
{
|
||||
return !a.compare(b, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
inline bool StrEquals(const QStringRef &a, const QStringRef &b)
|
||||
{
|
||||
return !a.compare(b, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
QString Html::DocToHtml(const QTextDocument *doc)
|
||||
{
|
||||
QString html;
|
||||
QXmlStreamWriter writer(&html);
|
||||
|
||||
//writer.setAutoFormatting(true);
|
||||
|
||||
for (auto it=doc->begin(); it!=doc->end(); it=it.next()) {
|
||||
WriteBlock(&writer, it);
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
struct HtmlNode {
|
||||
QString tag;
|
||||
QTextCharFormat format;
|
||||
};
|
||||
|
||||
QTextCharFormat MergeHtmlFormats(const QVector<HtmlNode> &stack)
|
||||
{
|
||||
QTextCharFormat f;
|
||||
|
||||
for (int i=0; i<stack.size(); i++) {
|
||||
f.merge(stack.at(i).format);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void Html::HtmlToDoc(QTextDocument *doc, const QString &html)
|
||||
{
|
||||
// Empty doc
|
||||
doc->clear();
|
||||
bool inside_block = true;
|
||||
|
||||
// Create cursor, which appears to be Qt's official way of inserting blocks and fragments
|
||||
QTextCursor c(doc);
|
||||
|
||||
QString wrapped = QStringLiteral("<html>").append(html).append("</html>");
|
||||
QXmlStreamReader reader(wrapped);
|
||||
|
||||
QVector<HtmlNode> fmt_stack;
|
||||
|
||||
QTextCharFormat default_fmt;
|
||||
default_fmt.setFontWeight(QFont::Normal);
|
||||
fmt_stack.append({QStringLiteral("html"), default_fmt});
|
||||
|
||||
QTextCharFormat current_fmt;
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
|
||||
if (reader.tokenType() == QXmlStreamReader::StartElement) {
|
||||
|
||||
QString tag = reader.name().toString().toLower();
|
||||
|
||||
fmt_stack.append({tag, ReadCharFormat(reader.attributes())});
|
||||
current_fmt = MergeHtmlFormats(fmt_stack);
|
||||
|
||||
if (kBlockTags.contains(tag)) {
|
||||
QTextBlockFormat block_fmt = ReadBlockFormat(reader.attributes());
|
||||
if (inside_block) {
|
||||
c.setBlockFormat(block_fmt);
|
||||
c.setBlockCharFormat(current_fmt);
|
||||
} else {
|
||||
c.insertBlock(block_fmt, current_fmt);
|
||||
inside_block = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader.tokenType() == QXmlStreamReader::Characters) {
|
||||
|
||||
QString characters = reader.text().toString();
|
||||
c.insertText(characters, current_fmt);
|
||||
|
||||
} else if (reader.tokenType() == QXmlStreamReader::EndElement) {
|
||||
|
||||
QString tag = reader.name().toString().toLower();
|
||||
|
||||
for (int i=fmt_stack.size()-1; i>=0; i--) {
|
||||
if (fmt_stack.at(i).tag == tag) {
|
||||
fmt_stack.removeAt(i);
|
||||
current_fmt = MergeHtmlFormats(fmt_stack);
|
||||
|
||||
if (kBlockTags.contains(tag)) {
|
||||
inside_block = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.error()) {
|
||||
qCritical() << "Failed to parse HTML:" << reader.errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void Html::WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block)
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("p"));
|
||||
|
||||
const QTextBlockFormat &fmt = block.blockFormat();
|
||||
|
||||
// Write block alignment
|
||||
if (!(fmt.alignment() & Qt::AlignLeft)) {
|
||||
if (fmt.alignment() & Qt::AlignRight) {
|
||||
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("right"));
|
||||
} else if (fmt.alignment() & Qt::AlignCenter) {
|
||||
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("center"));
|
||||
} else if (fmt.alignment() & Qt::AlignJustify) {
|
||||
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("justify"));
|
||||
}
|
||||
}
|
||||
|
||||
// RTL support
|
||||
if (block.textDirection() == Qt::RightToLeft) {
|
||||
writer->writeAttribute(QStringLiteral("dir"), QStringLiteral("rtl"));
|
||||
}
|
||||
|
||||
// Write CSS attributes
|
||||
QString style;
|
||||
|
||||
if (fmt.lineHeightType() != QTextBlockFormat::SingleHeight) {
|
||||
WriteCSSProperty(&style, QStringLiteral("line-height"), QStringLiteral("%1%").arg(fmt.lineHeight()));
|
||||
}
|
||||
|
||||
//WriteCharFormat(&style, block.charFormat());
|
||||
|
||||
if (!style.isEmpty()) {
|
||||
writer->writeAttribute(QStringLiteral("style"), style);
|
||||
}
|
||||
|
||||
auto it = block.begin();
|
||||
|
||||
if (it == block.end()) {
|
||||
// FIXME: Might not be necessary with our custom HTML implementation
|
||||
QString s;
|
||||
s.append(QChar::Nbsp);
|
||||
writer->writeCharacters(s);
|
||||
} else {
|
||||
for (; it!=block.end(); it++) {
|
||||
WriteFragment(writer, it.fragment());
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // p
|
||||
}
|
||||
|
||||
void Html::WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment)
|
||||
{
|
||||
const QTextCharFormat &fmt = fragment.charFormat();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("span"));
|
||||
|
||||
// Write CSS attributes
|
||||
QString style;
|
||||
|
||||
WriteCharFormat(&style, fmt);
|
||||
|
||||
if (!style.isEmpty()) {
|
||||
writer->writeAttribute(QStringLiteral("style"), style);
|
||||
}
|
||||
|
||||
QStringList lines = fragment.text().split(QChar::LineSeparator);
|
||||
bool first_line = true;
|
||||
foreach (const QString &l, lines) {
|
||||
if (first_line) {
|
||||
first_line = false;
|
||||
} else {
|
||||
writer->writeEmptyElement(QStringLiteral("br"));
|
||||
}
|
||||
writer->writeCharacters(l);
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // span
|
||||
}
|
||||
|
||||
void Html::WriteCSSProperty(QString *style, const QString &key, const QStringList &values)
|
||||
{
|
||||
QString value;
|
||||
foreach (QString v, values) {
|
||||
if (v.contains(' ')) {
|
||||
v = QStringLiteral("'%1'").arg(v);
|
||||
}
|
||||
|
||||
AppendStringAutoSpace(&value, v);
|
||||
}
|
||||
|
||||
AppendStringAutoSpace(style, QStringLiteral("%1: %2;").arg(key, value));
|
||||
}
|
||||
|
||||
void Html::WriteCharFormat(QString *style, const QTextCharFormat &fmt)
|
||||
{
|
||||
if (!fmt.fontFamily().isEmpty()) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-family"), fmt.fontFamily());
|
||||
}
|
||||
|
||||
if (fmt.hasProperty(QTextFormat::FontPointSize)) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-size"), QStringLiteral("%1pt").arg(QString::number(fmt.fontPointSize())));
|
||||
}
|
||||
|
||||
if (fmt.hasProperty(QTextFormat::FontWeight)) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-weight"), QString::number(fmt.fontWeight() * 8));
|
||||
}
|
||||
|
||||
if (fmt.hasProperty(QTextFormat::FontItalic)) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-style"), fmt.fontItalic() ? QStringLiteral("italic") : QStringLiteral("normal"));
|
||||
}
|
||||
|
||||
if (fmt.hasProperty(QTextFormat::FontStyleName)) {
|
||||
WriteCSSProperty(style, QStringLiteral("-ove-font-style"), fmt.fontStyleName().toString());
|
||||
}
|
||||
|
||||
QStringList deco;
|
||||
|
||||
if (fmt.fontUnderline()) {
|
||||
deco.append(QStringLiteral("underline"));
|
||||
}
|
||||
|
||||
if (fmt.fontStrikeOut()) {
|
||||
deco.append(QStringLiteral("line-through"));
|
||||
}
|
||||
|
||||
if (fmt.fontOverline()) {
|
||||
deco.append(QStringLiteral("overline"));
|
||||
}
|
||||
|
||||
if (!deco.isEmpty()) {
|
||||
WriteCSSProperty(style, QStringLiteral("text-decoration"), deco);
|
||||
}
|
||||
|
||||
if (fmt.foreground().style() != Qt::NoBrush) {
|
||||
const QColor &color = fmt.foreground().color();
|
||||
QString cs;
|
||||
|
||||
if (color.alpha() == 255) {
|
||||
cs = color.name();
|
||||
} else if (color.alpha()) {
|
||||
cs = QStringLiteral("rgba(%1, %2, %3, %4)").arg(QString::number(color.red()), QString::number(color.green()), QString::number(color.blue()), QString::number(color.alphaF()));
|
||||
}
|
||||
|
||||
WriteCSSProperty(style, QStringLiteral("color"), cs);
|
||||
}
|
||||
|
||||
if (fmt.fontCapitalization() != QFont::MixedCase) {
|
||||
if (fmt.fontCapitalization() == QFont::SmallCaps) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-variant"), QStringLiteral("small-caps"));
|
||||
// TODO: Add others
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt.fontLetterSpacing() != 0.0) {
|
||||
WriteCSSProperty(style, QStringLiteral("letter-spacing"), QStringLiteral("%1%").arg(QString::number(fmt.fontLetterSpacing())));
|
||||
}
|
||||
|
||||
if (fmt.fontStretch() != 0) {
|
||||
WriteCSSProperty(style, QStringLiteral("font-stretch"), QStringLiteral("%1%").arg(QString::number(fmt.fontStretch())));
|
||||
}
|
||||
}
|
||||
|
||||
QTextCharFormat Html::ReadCharFormat(const QXmlStreamAttributes &attributes)
|
||||
{
|
||||
QTextCharFormat fmt;
|
||||
|
||||
foreach (const QXmlStreamAttribute &attr, attributes) {
|
||||
if (StrEquals(attr.name(), QStringLiteral("style"))) {
|
||||
auto css = GetCSSFromStyle(attr.value().toString());
|
||||
|
||||
for (auto it=css.begin(); it!=css.end(); it++) {
|
||||
const QString &first_val = it.value().first();
|
||||
|
||||
if (it.key() == QStringLiteral("font-family")) {
|
||||
fmt.setFontFamily(first_val);
|
||||
} else if (it.key() == QStringLiteral("font-size")) {
|
||||
if (first_val.endsWith(QStringLiteral("pt"), Qt::CaseInsensitive)) {
|
||||
fmt.setFontPointSize(first_val.chopped(2).toDouble());
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("font-weight")) {
|
||||
fmt.setFontWeight(first_val.toInt()/8);
|
||||
} else if (it.key() == QStringLiteral("font-style")) {
|
||||
fmt.setFontItalic(StrEquals(first_val, QStringLiteral("italic")));
|
||||
} else if (it.key() == QStringLiteral("text-decoration")) {
|
||||
foreach (const QString &v, it.value()) {
|
||||
if (StrEquals(v, QStringLiteral("underline"))) {
|
||||
fmt.setFontUnderline(true);
|
||||
} else if (StrEquals(v, QStringLiteral("line-through"))) {
|
||||
fmt.setFontStrikeOut(true);
|
||||
} else if (StrEquals(v, QStringLiteral("overline"))) {
|
||||
fmt.setFontOverline(true);
|
||||
}
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("color")) {
|
||||
if (first_val.startsWith(QStringLiteral("rgba"), Qt::CaseInsensitive)) {
|
||||
QString vals_only = first_val;
|
||||
vals_only.remove(QStringLiteral("rgba"));
|
||||
vals_only.remove(QStringLiteral("("));
|
||||
vals_only.remove(QStringLiteral(")"));
|
||||
QStringList rgba = vals_only.split(',');
|
||||
if (rgba.size() == 4) {
|
||||
QColor c;
|
||||
c.setRedF(rgba.at(0).toDouble());
|
||||
c.setGreenF(rgba.at(1).toDouble());
|
||||
c.setBlueF(rgba.at(2).toDouble());
|
||||
c.setAlphaF(rgba.at(3).toDouble());
|
||||
fmt.setForeground(c);
|
||||
}
|
||||
} else {
|
||||
fmt.setForeground(QColor(first_val));
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("font-variant")) {
|
||||
if (StrEquals(first_val, QStringLiteral("small-caps"))) {
|
||||
fmt.setFontCapitalization(QFont::SmallCaps);
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("letter-spacing")) {
|
||||
if (first_val.contains(QChar('%'))) {
|
||||
fmt.setFontLetterSpacing(first_val.chopped(1).toDouble());
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("font-stretch")) {
|
||||
if (first_val.contains(QChar('%'))) {
|
||||
fmt.setFontStretch(first_val.chopped(1).toInt());
|
||||
}
|
||||
} else if (it.key() == QStringLiteral("-ove-font-style")) {
|
||||
fmt.setFontStyleName(first_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
QTextBlockFormat Html::ReadBlockFormat(const QXmlStreamAttributes &attributes)
|
||||
{
|
||||
QTextBlockFormat block_fmt;
|
||||
|
||||
foreach (const QXmlStreamAttribute &attr, attributes) {
|
||||
if (StrEquals(attr.name(), QStringLiteral("align"))) {
|
||||
if (StrEquals(attr.value(), QStringLiteral("right"))) {
|
||||
block_fmt.setAlignment(Qt::AlignRight);
|
||||
} else if (StrEquals(attr.value(), QStringLiteral("center"))) {
|
||||
block_fmt.setAlignment(Qt::AlignCenter);
|
||||
} else if (StrEquals(attr.value(), QStringLiteral("justify"))) {
|
||||
block_fmt.setAlignment(Qt::AlignJustify);
|
||||
}
|
||||
} else if (StrEquals(attr.name(), QStringLiteral("dir"))) {
|
||||
if (StrEquals(attr.value(), QStringLiteral("rtl"))) {
|
||||
block_fmt.setLayoutDirection(Qt::RightToLeft);
|
||||
}
|
||||
} else if (StrEquals(attr.name(), QStringLiteral("style"))) {
|
||||
auto css = GetCSSFromStyle(attr.value().toString());
|
||||
|
||||
for (auto it=css.begin(); it!=css.end(); it++) {
|
||||
if (it.key() == QStringLiteral("line-height")) {
|
||||
const QString &first_val = it.value().constFirst();
|
||||
if (first_val.contains(QChar('%'))) {
|
||||
block_fmt.setLineHeight(first_val.chopped(1).toDouble(), QTextBlockFormat::ProportionalHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return block_fmt;
|
||||
}
|
||||
|
||||
void Html::AppendStringAutoSpace(QString *s, const QString &append)
|
||||
{
|
||||
if (!s->isEmpty()) {
|
||||
s->append(QChar(' '));
|
||||
}
|
||||
|
||||
s->append(append);
|
||||
}
|
||||
|
||||
QMap<QString, QStringList> Html::GetCSSFromStyle(const QString &s)
|
||||
{
|
||||
QMap<QString, QStringList> map;
|
||||
|
||||
QStringList list = s.split(QChar(';'));
|
||||
|
||||
foreach (const QString &a, list) {
|
||||
QStringList kv = a.split(QChar(':'));
|
||||
|
||||
if (kv.size() != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// I'm sure there's regex that could do this, but I couldn't figure it out. It needs to split
|
||||
// by space EXCEPT within quotes OR double-quotes, and said quotes should be EXCLUDED from each
|
||||
// match. Also commas should be filtered out.
|
||||
QStringList values;
|
||||
const QString &val = kv.at(1);
|
||||
QChar in_quote = 0;
|
||||
QString current_str;
|
||||
for (int i=0; i<val.size(); i++) {
|
||||
const QChar ¤t_char = val.at(i);
|
||||
|
||||
if (!in_quote.isNull()) {
|
||||
// If inside quotes and character isn't quote, indiscriminately append char
|
||||
if (current_char == in_quote) {
|
||||
in_quote = 0;
|
||||
} else {
|
||||
current_str.append(current_char);
|
||||
}
|
||||
} else if (current_char.isSpace() || current_char == QChar(',')) {
|
||||
// Dump current
|
||||
if (!current_str.isEmpty()) {
|
||||
values.append(current_str);
|
||||
current_str.clear();
|
||||
}
|
||||
} else if (in_quote.isNull() && (current_char == QChar('\'') || current_char == QChar('"'))) {
|
||||
in_quote = current_char;
|
||||
} else {
|
||||
current_str.append(current_char);
|
||||
}
|
||||
}
|
||||
|
||||
if (!current_str.isEmpty()) {
|
||||
values.append(current_str);
|
||||
}
|
||||
|
||||
// Not sure if this will ever happen, but just in case, we will avoid assert failures with this
|
||||
if (values.isEmpty()) {
|
||||
values.append(QString());
|
||||
}
|
||||
|
||||
map[kv.at(0).trimmed().toLower()] = values;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef HTML_H
|
||||
#define HTML_H
|
||||
|
||||
#include <QTextDocument>
|
||||
#include <QTextFragment>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
namespace olive {
|
||||
|
||||
/**
|
||||
* @brief Functions for converting HTML to QTextDocument and vice versa
|
||||
*
|
||||
* Qt does contain its own functions for this, however they have some limitations. Some things that
|
||||
* we want to support (e.g. kerning/spacing and font stretch) are not implemented in Qt's
|
||||
* QTextHtmlExporter and QTextHtmlParser. Additionally, since these functions are not part of Qt's
|
||||
* public API, and make many references to other parts of Qt that are not part of the public API,
|
||||
* there is no way to subclass or extend their functionality without forking Qt as a whole.
|
||||
*
|
||||
* Therefore, it became necessary to write a custom class for the conversion so that we can
|
||||
* ensure support for the features we need.
|
||||
*
|
||||
* If someone wishes to extend this class for more feature support, feel free to open a pull
|
||||
* request. But this is NOT intended to be an exhaustive HTML implementation, and is primarily
|
||||
* designed to store rich text in a standard format for the purpose of text formatting for video.
|
||||
*/
|
||||
class Html {
|
||||
public:
|
||||
static QString DocToHtml(const QTextDocument *doc);
|
||||
|
||||
static void HtmlToDoc(QTextDocument *doc, const QString &html);
|
||||
|
||||
private:
|
||||
static void WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block);
|
||||
|
||||
static void WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment);
|
||||
|
||||
static void WriteCSSProperty(QString *style, const QString &key, const QStringList &value);
|
||||
static void WriteCSSProperty(QString *style, const QString &key, const QString &value)
|
||||
{
|
||||
WriteCSSProperty(style, key, QStringList({value}));
|
||||
}
|
||||
|
||||
static void WriteCharFormat(QString *style, const QTextCharFormat &fmt);
|
||||
|
||||
static QTextCharFormat ReadCharFormat(const QXmlStreamAttributes &attributes);
|
||||
|
||||
static QTextBlockFormat ReadBlockFormat(const QXmlStreamAttributes &attributes);
|
||||
|
||||
static void AppendStringAutoSpace(QString *s, const QString &append);
|
||||
|
||||
static QMap<QString, QStringList> GetCSSFromStyle(const QString &s);
|
||||
|
||||
static const QVector<QString> kBlockTags;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HTML_H
|
||||
@@ -38,6 +38,13 @@ QFrame *QtUtils::CreateHorizontalLine()
|
||||
return horizontal_line;
|
||||
}
|
||||
|
||||
QFrame *QtUtils::CreateVerticalLine()
|
||||
{
|
||||
QFrame *l = CreateHorizontalLine();
|
||||
l->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
||||
return l;
|
||||
}
|
||||
|
||||
int QtUtils::MessageBox(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &message, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
QMessageBox b(parent);
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
|
||||
static QFrame* CreateHorizontalLine();
|
||||
|
||||
static QFrame* CreateVerticalLine();
|
||||
|
||||
static int MessageBox(QWidget *parent, QMessageBox::Icon icon, const QString& title, const QString& message, QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
static QDateTime GetCreationDate(const QFileInfo &info);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
template <typename T>
|
||||
inline T mid(T a, T b)
|
||||
{
|
||||
return (a + b) * 0.5;
|
||||
}
|
||||
|
||||
#endif // UTIL_H
|
||||
Reference in New Issue
Block a user