okular/generators/fictionbook/converter.cpp
2023-12-19 12:58:00 +00:00

1136 lines
33 KiB
C++

/*
SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "converter.h"
#include <QAbstractTextDocumentLayout>
#include <QDate>
#include <QDomElement>
#include <QDomText>
#include <QTextCursor>
#include <QTextDocument>
#include <QTextFrame>
#include <QTextTable>
#include <QUrl>
#include <KLocalizedString>
#include <core/action.h>
#include <core/document.h>
#include "document.h"
using namespace FictionBook;
class Converter::TitleInfo
{
public:
QStringList mGenres;
QString mAuthor;
QString mTitle;
QString mAnnotation;
QString mKeywords;
QDate mDate;
QDomElement mCoverPage;
QString mLanguage;
};
class Converter::DocumentInfo
{
public:
QString mAuthor;
QString mProducer;
QDate mDate;
QString mId;
QString mVersion;
};
Converter::Converter()
: mTextDocument(nullptr)
, mCursor(nullptr)
, mTitleInfo(nullptr)
, mDocumentInfo(nullptr)
{
}
Converter::~Converter()
{
delete mTitleInfo;
delete mDocumentInfo;
}
QTextDocument *Converter::convert(const QString &fileName)
{
Document fbDocument(fileName);
if (!fbDocument.open()) {
Q_EMIT error(fbDocument.lastErrorString(), -1);
return nullptr;
}
mTextDocument = new QTextDocument;
mCursor = new QTextCursor(mTextDocument);
mSectionCounter = 0;
mLocalLinks.clear();
mSectionMap.clear();
const QDomDocument document = fbDocument.content();
/**
* Set the correct page size
*/
mTextDocument->setPageSize(QSizeF(600, 800));
QTextFrameFormat frameFormat;
frameFormat.setMargin(20);
QTextFrame *rootFrame = mTextDocument->rootFrame();
rootFrame->setFrameFormat(frameFormat);
/**
* Parse the content of the document
*/
const QDomElement documentElement = document.documentElement();
if (documentElement.tagName() != QLatin1String("FictionBook")) {
Q_EMIT error(i18n("Document is not a valid FictionBook"), -1);
delete mCursor;
return nullptr;
}
/**
* First we read all images, so we can calculate the size later.
*/
QDomElement element = documentElement.firstChildElement();
while (!element.isNull()) {
if (element.tagName() == QLatin1String("binary")) {
if (!convertBinary(element)) {
delete mCursor;
return nullptr;
}
}
element = element.nextSiblingElement();
}
/**
* Read the rest: description (could be only one) and bodies (one or more)
*/
element = documentElement.firstChildElement();
while (!element.isNull()) {
if (element.tagName() == QLatin1String("description")) {
if (!convertDescription(element)) {
delete mCursor;
return nullptr;
}
if (mTitleInfo && !mTitleInfo->mCoverPage.isNull()) {
convertCover(mTitleInfo->mCoverPage);
mCursor->insertBlock();
}
QTextFrame *topFrame = mCursor->currentFrame();
QTextFrameFormat frameFormat;
frameFormat.setBorder(2);
frameFormat.setPadding(8);
frameFormat.setBackground(Qt::lightGray);
if (mTitleInfo && !mTitleInfo->mTitle.isEmpty()) {
mCursor->insertFrame(frameFormat);
QTextCharFormat charFormat;
charFormat.setFontPointSize(22);
charFormat.setFontWeight(QFont::Bold);
mCursor->insertText(mTitleInfo->mTitle, charFormat);
mCursor->setPosition(topFrame->lastPosition());
}
if (mTitleInfo && !mTitleInfo->mAuthor.isEmpty()) {
frameFormat.setBorder(1);
mCursor->insertFrame(frameFormat);
QTextCharFormat charFormat;
charFormat.setFontPointSize(10);
mCursor->insertText(mTitleInfo->mAuthor, charFormat);
mCursor->setPosition(topFrame->lastPosition());
mCursor->insertBlock();
}
if (mTitleInfo && !mTitleInfo->mAnnotation.isEmpty()) {
frameFormat.setBorder(0);
mCursor->insertFrame(frameFormat);
QTextCharFormat charFormat;
charFormat.setFontPointSize(10);
charFormat.setFontItalic(true);
mCursor->insertText(mTitleInfo->mAnnotation, charFormat);
mCursor->setPosition(topFrame->lastPosition());
mCursor->insertBlock();
}
} else if (element.tagName() == QLatin1String("body")) {
mCursor->insertBlock();
if (!convertBody(element)) {
delete mCursor;
return nullptr;
}
}
element = element.nextSiblingElement();
}
/**
* Add document info.
*/
if (mTitleInfo) {
if (!mTitleInfo->mTitle.isEmpty()) {
Q_EMIT addMetaData(Okular::DocumentInfo::Title, mTitleInfo->mTitle);
}
if (!mTitleInfo->mAuthor.isEmpty()) {
Q_EMIT addMetaData(Okular::DocumentInfo::Author, mTitleInfo->mAuthor);
}
if (!mTitleInfo->mKeywords.isEmpty()) {
Q_EMIT addMetaData(Okular::DocumentInfo::Keywords, mTitleInfo->mKeywords);
}
}
if (mDocumentInfo) {
if (!mDocumentInfo->mProducer.isEmpty()) {
Q_EMIT addMetaData(Okular::DocumentInfo::Producer, mDocumentInfo->mProducer);
}
if (mDocumentInfo->mDate.isValid()) {
Q_EMIT addMetaData(Okular::DocumentInfo::CreationDate, QLocale().toString(mDocumentInfo->mDate, QLocale::ShortFormat));
}
}
QMapIterator<QString, QPair<int, int>> it(mLocalLinks);
while (it.hasNext()) {
it.next();
const QTextBlock block = mSectionMap[it.key()];
if (!block.isValid()) { // local link without existing target
continue;
}
Okular::DocumentViewport viewport = calculateViewport(mTextDocument, block);
Okular::GotoAction *action = new Okular::GotoAction(QString(), viewport);
Q_EMIT addAction(action, it.value().first, it.value().second);
}
delete mCursor;
return mTextDocument;
}
bool Converter::convertBody(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("section")) {
mCursor->insertBlock();
if (!convertSection(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("image")) {
if (!convertImage(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("title")) {
if (!convertTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("epigraph")) {
if (!convertEpigraph(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertDescription(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("title-info")) {
if (!convertTitleInfo(child)) {
return false;
}
}
if (child.tagName() == QLatin1String("document-info")) {
if (!convertDocumentInfo(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertTitleInfo(const QDomElement &element)
{
delete mTitleInfo;
mTitleInfo = new TitleInfo;
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("genre")) {
QString genre;
if (!convertTextNode(child, genre)) {
return false;
}
if (!genre.isEmpty()) {
mTitleInfo->mGenres.append(genre);
}
} else if (child.tagName() == QLatin1String("author")) {
QString firstName, middleName, lastName, dummy;
if (!convertAuthor(child, firstName, middleName, lastName, dummy, dummy)) {
return false;
}
if (mTitleInfo->mAuthor.isEmpty()) {
mTitleInfo->mAuthor = QStringLiteral("%1 %2 %3").arg(firstName, middleName, lastName).simplified();
} else {
mTitleInfo->mAuthor += QStringLiteral(", %1 %2 %3").arg(firstName, middleName, lastName).simplified();
}
} else if (child.tagName() == QLatin1String("book-title")) {
if (!convertTextNode(child, mTitleInfo->mTitle)) {
return false;
}
} else if (child.tagName() == QLatin1String("keywords")) {
QString keywords;
if (!convertTextNode(child, keywords)) {
return false;
}
mTitleInfo->mKeywords = keywords;
} else if (child.tagName() == QLatin1String("annotation")) {
if (!convertAnnotation(child, mTitleInfo->mAnnotation)) {
return false;
}
} else if (child.tagName() == QLatin1String("date")) {
if (!convertDate(child, mTitleInfo->mDate)) {
return false;
}
} else if (child.tagName() == QLatin1String("coverpage")) {
mTitleInfo->mCoverPage = child;
} else if (child.tagName() == QLatin1String("lang")) {
if (!convertTextNode(child, mTitleInfo->mLanguage)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertDocumentInfo(const QDomElement &element)
{
delete mDocumentInfo;
mDocumentInfo = new DocumentInfo;
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("author")) {
QString firstName, middleName, lastName, email, nickname;
if (!convertAuthor(child, firstName, middleName, lastName, email, nickname)) {
return false;
}
mDocumentInfo->mAuthor = QStringLiteral("%1 %2 %3 <%4> (%5)").arg(firstName, middleName, lastName, email, nickname);
} else if (child.tagName() == QLatin1String("program-used")) {
if (!convertTextNode(child, mDocumentInfo->mProducer)) {
return false;
}
} else if (child.tagName() == QLatin1String("date")) {
if (!convertDate(child, mDocumentInfo->mDate)) {
return false;
}
} else if (child.tagName() == QLatin1String("id")) {
if (!convertTextNode(child, mDocumentInfo->mId)) {
return false;
}
} else if (child.tagName() == QLatin1String("version")) {
if (!convertTextNode(child, mDocumentInfo->mVersion)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertAuthor(const QDomElement &element, QString &firstName, QString &middleName, QString &lastName, QString &email, QString &nickname)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("first-name")) {
if (!convertTextNode(child, firstName)) {
return false;
}
} else if (child.tagName() == QLatin1String("middle-name")) {
if (!convertTextNode(child, middleName)) {
return false;
}
} else if (child.tagName() == QLatin1String("last-name")) {
if (!convertTextNode(child, lastName)) {
return false;
}
} else if (child.tagName() == QLatin1String("email")) {
if (!convertTextNode(child, email)) {
return false;
}
} else if (child.tagName() == QLatin1String("nickname")) {
if (!convertTextNode(child, nickname)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertTextNode(const QDomElement &element, QString &data)
{
QDomNode child = element.firstChild();
while (!child.isNull()) {
QDomText text = child.toText();
if (!text.isNull()) {
data = text.data();
}
child = child.nextSibling();
}
return true;
}
bool Converter::convertDate(const QDomElement &element, QDate &date)
{
if (element.hasAttribute(QStringLiteral("value"))) {
date = QDate::fromString(element.attribute(QStringLiteral("value")), Qt::ISODate);
}
return true;
}
bool Converter::convertAnnotation(const QDomElement &element, QString &data)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
QString text = child.text();
if (!text.isNull()) {
data = child.text();
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertSection(const QDomElement &element)
{
if (element.hasAttribute(QStringLiteral("id"))) {
mSectionMap.insert(element.attribute(QStringLiteral("id")), mCursor->block());
}
mSectionCounter++;
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("title")) {
if (!convertTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("epigraph")) {
if (!convertEpigraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("image")) {
if (!convertImage(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("section")) {
if (!convertSection(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("p")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("poem")) {
if (!convertPoem(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("subtitle")) {
if (!convertSubTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("cite")) {
if (!convertCite(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("empty-line")) {
if (!convertEmptyLine(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("code")) {
if (!convertCode(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("table")) {
if (!convertTable(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
mSectionCounter--;
return true;
}
bool Converter::convertTitle(const QDomElement &element)
{
QTextFrame *topFrame = mCursor->currentFrame();
QTextFrameFormat frameFormat;
frameFormat.setBorder(1);
frameFormat.setPadding(8);
frameFormat.setBackground(Qt::lightGray);
mCursor->insertFrame(frameFormat);
QDomElement child = element.firstChildElement();
bool firstParagraph = true;
while (!child.isNull()) {
if (child.tagName() == QLatin1String("p")) {
if (firstParagraph) {
firstParagraph = false;
} else {
mCursor->insertBlock();
}
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat titleFormat(origFormat);
titleFormat.setFontPointSize(22 - (mSectionCounter * 2));
titleFormat.setFontWeight(QFont::Bold);
mCursor->setCharFormat(titleFormat);
if (!convertParagraph(child)) {
return false;
}
mCursor->setCharFormat(origFormat);
Q_EMIT addTitle(mSectionCounter, child.text(), mCursor->block());
} else if (child.tagName() == QLatin1String("empty-line")) {
if (!convertEmptyLine(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
mCursor->setPosition(topFrame->lastPosition());
return true;
}
bool Converter::convertParagraph(const QDomElement &element)
{
QDomNode child = element.firstChild();
while (!child.isNull()) {
if (child.isElement()) {
const QDomElement childElement = child.toElement();
if (childElement.tagName() == QLatin1String("emphasis")) {
if (!convertEmphasis(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("strong")) {
if (!convertStrong(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("style")) {
if (!convertStyle(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("a")) {
if (!convertLink(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("image")) {
if (!convertImage(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("strikethrough")) {
if (!convertStrikethrough(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("code")) {
if (!convertCode(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("sup")) {
if (!convertSuperScript(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("sub")) {
if (!convertSubScript(childElement)) {
return false;
}
}
} else if (child.isText()) {
const QDomText childText = child.toText();
mCursor->insertText(childText.data().simplified());
}
child = child.nextSibling();
}
return true;
}
bool Converter::convertEmphasis(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat italicFormat(origFormat);
italicFormat.setFontItalic(true);
mCursor->setCharFormat(italicFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertStrikethrough(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat strikeoutFormat(origFormat);
strikeoutFormat.setFontStrikeOut(true);
mCursor->setCharFormat(strikeoutFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertStrong(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat boldFormat(origFormat);
boldFormat.setFontWeight(QFont::Bold);
mCursor->setCharFormat(boldFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertStyle(const QDomElement &element)
{
if (!convertParagraph(element)) {
return false;
}
return true;
}
bool Converter::convertBinary(const QDomElement &element)
{
const QString id = element.attribute(QStringLiteral("id"));
const QDomText textNode = element.firstChild().toText();
QByteArray data = textNode.data().toLatin1();
data = QByteArray::fromBase64(data);
mTextDocument->addResource(QTextDocument::ImageResource, QUrl(id), QImage::fromData(data));
return true;
}
bool Converter::convertCover(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("image")) {
if (!convertImage(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertImage(const QDomElement &element)
{
QString href = element.attributeNS(QStringLiteral("http://www.w3.org/1999/xlink"), QStringLiteral("href"));
if (href.startsWith(QLatin1Char('#'))) {
href = href.mid(1);
}
const QImage img = qvariant_cast<QImage>(mTextDocument->resource(QTextDocument::ImageResource, QUrl(href)));
QTextImageFormat format;
format.setName(href);
if (img.width() > 560) {
format.setWidth(560);
}
format.setHeight(img.height());
mCursor->insertImage(format);
return true;
}
bool Converter::convertEpigraph(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("p")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("poem")) {
if (!convertPoem(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("cite")) {
if (!convertCite(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("empty-line")) {
if (!convertEmptyLine(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("text-author")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertPoem(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("title")) {
if (!convertTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("epigraph")) {
if (!convertEpigraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("empty-line")) {
if (!convertEmptyLine(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("stanza")) {
if (!convertStanza(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("text-author")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertSubTitle(const QDomElement &element)
{
QTextFrame *topFrame = mCursor->currentFrame();
QTextFrameFormat frameFormat;
frameFormat.setBorder(1);
frameFormat.setPadding(8);
frameFormat.setBackground(Qt::lightGray);
frameFormat.setTopMargin(16);
mCursor->insertFrame(frameFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setPosition(topFrame->lastPosition());
return true;
}
bool Converter::convertCite(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("p")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("poem")) {
if (!convertParagraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("text-author")) {
QTextBlockFormat format;
format.setTextIndent(10);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("empty-line")) {
if (!convertEmptyLine(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("subtitle")) {
if (!convertSubTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("table")) {
if (!convertTable(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertEmptyLine(const QDomElement &)
{
mCursor->insertText(QStringLiteral("\n\n"));
return true;
}
bool Converter::convertLink(const QDomElement &element)
{
QString href = element.attributeNS(QStringLiteral("http://www.w3.org/1999/xlink"), QStringLiteral("href"));
QString type = element.attributeNS(QStringLiteral("http://www.w3.org/1999/xlink"), QStringLiteral("type"));
if (type == QLatin1String("note")) {
mCursor->insertText(QStringLiteral("["));
}
int startPosition = mCursor->position();
QTextCharFormat origFormat(mCursor->charFormat());
QTextCharFormat format(mCursor->charFormat());
format.setForeground(Qt::blue);
format.setFontUnderline(true);
mCursor->setCharFormat(format);
QDomNode child = element.firstChild();
while (!child.isNull()) {
if (child.isElement()) {
const QDomElement childElement = child.toElement();
if (childElement.tagName() == QLatin1String("emphasis")) {
if (!convertEmphasis(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("strong")) {
if (!convertStrong(childElement)) {
return false;
}
} else if (childElement.tagName() == QLatin1String("style")) {
if (!convertStyle(childElement)) {
return false;
}
}
} else if (child.isText()) {
const QDomText text = child.toText();
if (!text.isNull()) {
mCursor->insertText(text.data());
}
}
child = child.nextSibling();
}
mCursor->setCharFormat(origFormat);
int endPosition = mCursor->position();
if (type == QLatin1String("note")) {
mCursor->insertText(QStringLiteral("]"));
}
if (href.startsWith(QLatin1Char('#'))) { // local link
mLocalLinks.insert(href.mid(1), QPair<int, int>(startPosition, endPosition));
} else {
// external link
Okular::BrowseAction *action = new Okular::BrowseAction(QUrl(href));
Q_EMIT addAction(action, startPosition, endPosition);
}
return true;
}
bool Converter::convertStanza(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("title")) {
if (!convertTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("subtitle")) {
if (!convertSubTitle(child)) {
return false;
}
} else if (child.tagName() == QLatin1String("v")) {
QTextBlockFormat format;
format.setTextIndent(50);
mCursor->insertBlock(format);
if (!convertParagraph(child)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertCode(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat codeFormat(origFormat);
codeFormat.setFontFamilies({QStringLiteral("monospace")});
mCursor->setCharFormat(codeFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertSuperScript(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat superScriptFormat(origFormat);
superScriptFormat.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
mCursor->setCharFormat(superScriptFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertSubScript(const QDomElement &element)
{
QTextCharFormat origFormat = mCursor->charFormat();
QTextCharFormat subScriptFormat(origFormat);
subScriptFormat.setVerticalAlignment(QTextCharFormat::AlignSubScript);
mCursor->setCharFormat(subScriptFormat);
if (!convertParagraph(element)) {
return false;
}
mCursor->setCharFormat(origFormat);
return true;
}
bool Converter::convertTable(const QDomElement &element)
{
QTextFrame *topFrame = mCursor->currentFrame();
QTextTable *table = nullptr;
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == QLatin1String("tr")) {
if (table) {
table->appendRows(1);
} else {
QTextTableFormat tableFormat;
tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None);
table = mCursor->insertTable(1, 1, tableFormat);
}
if (!convertTableRow(child, *table)) {
return false;
}
}
child = child.nextSiblingElement();
}
mCursor->setPosition(topFrame->lastPosition());
return true;
}
bool Converter::convertTableRow(const QDomElement &element, QTextTable &table)
{
QDomElement child = element.firstChildElement();
int column = 0;
while (!child.isNull()) {
if (child.tagName() == QLatin1String("th")) {
if (!convertTableHeaderCell(child, table, column)) {
return false;
}
} else if (child.tagName() == QLatin1String("td")) {
if (!convertTableCell(child, table, column)) {
return false;
}
}
child = child.nextSiblingElement();
}
return true;
}
bool Converter::convertTableHeaderCell(const QDomElement &element, QTextTable &table, int &column)
{
QTextCharFormat charFormat;
charFormat.setFontWeight(QFont::Bold);
return convertTableCellHelper(element, table, column, charFormat);
}
bool Converter::convertTableCell(const QDomElement &element, QTextTable &table, int &column)
{
QTextCharFormat charFormat;
return convertTableCellHelper(element, table, column, charFormat);
}
bool Converter::convertTableCellHelper(const QDomElement &element, QTextTable &table, int &column, const QTextCharFormat &charFormat)
{
int row = table.rows() - 1;
int colspan = qMax(element.attribute(QStringLiteral("colspan")).toInt(), 1);
// TODO: rowspan
// int rowspan = qMax(element.attribute(QStringLiteral("rowspan")).toInt(), 1);
int columnsToAppend = column + colspan - table.columns();
if (columnsToAppend > 0) {
table.appendColumns(columnsToAppend);
}
table.mergeCells(row, column, 1, colspan);
int cellCursorPosition = table.cellAt(row, column).firstPosition();
mCursor->setPosition(cellCursorPosition);
Qt::Alignment alignment;
QString halign = element.attribute(QStringLiteral("halign"));
if (halign == QStringLiteral("center")) {
alignment |= Qt::AlignHCenter;
} else if (halign == QStringLiteral("right")) {
alignment |= Qt::AlignRight;
} else {
alignment |= Qt::AlignLeft;
}
QString valign = element.attribute(QStringLiteral("valign"));
if (valign == QStringLiteral("center")) {
alignment |= Qt::AlignVCenter;
} else if (valign == QStringLiteral("bottom")) {
alignment |= Qt::AlignBottom;
} else {
alignment |= Qt::AlignTop;
}
QTextBlockFormat format;
format.setAlignment(alignment);
mCursor->insertBlock(format, charFormat);
if (!convertParagraph(element)) {
return false;
}
column += colspan;
return true;
}