mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 14:14:10 +00:00
1136 lines
33 KiB
C++
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;
|
|
}
|