File indexing completed on 2024-05-12 04:34:02

0001 /*
0002     SPDX-FileCopyrightText: 2008 Jakub Stachowski <qbast@go2.pl>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "converter.h"
0008 
0009 #include <QAbstractTextDocumentLayout>
0010 #include <QDebug>
0011 #include <QFile>
0012 #include <QTextBlock>
0013 #include <QTextDocument>
0014 #include <QTextDocumentFragment>
0015 #include <QTextFrame>
0016 
0017 #include <KLocalizedString>
0018 #include <core/action.h>
0019 
0020 using namespace Mobi;
0021 
0022 Converter::Converter()
0023 {
0024 }
0025 
0026 Converter::~Converter()
0027 {
0028 }
0029 
0030 void Converter::handleMetadata(const QMap<Mobipocket::Document::MetaKey, QString> &metadata)
0031 {
0032     QMapIterator<Mobipocket::Document::MetaKey, QString> it(metadata);
0033     while (it.hasNext()) {
0034         it.next();
0035         switch (it.key()) {
0036         case Mobipocket::Document::Title:
0037             Q_EMIT addMetaData(Okular::DocumentInfo::Title, it.value());
0038             break;
0039         case Mobipocket::Document::Author:
0040             Q_EMIT addMetaData(Okular::DocumentInfo::Author, it.value());
0041             break;
0042         case Mobipocket::Document::Description:
0043             Q_EMIT addMetaData(Okular::DocumentInfo::Description, it.value());
0044             break;
0045         case Mobipocket::Document::Subject:
0046             Q_EMIT addMetaData(Okular::DocumentInfo::Subject, it.value());
0047             break;
0048         case Mobipocket::Document::Copyright:
0049             Q_EMIT addMetaData(Okular::DocumentInfo::Copyright, it.value());
0050             break;
0051         }
0052     }
0053 }
0054 
0055 QTextDocument *Converter::convert(const QString &fileName)
0056 {
0057     MobiDocument *newDocument = new MobiDocument(fileName);
0058     if (!newDocument->mobi()->isValid()) {
0059         Q_EMIT error(i18n("Error while opening the Mobipocket document."), -1);
0060         delete newDocument;
0061         return nullptr;
0062     }
0063     if (newDocument->mobi()->hasDRM()) {
0064         Q_EMIT error(i18n("This book is protected by DRM and can be displayed only on designated device"), -1);
0065         delete newDocument;
0066         return nullptr;
0067     }
0068 
0069     handleMetadata(newDocument->mobi()->metadata());
0070     newDocument->setPageSize(QSizeF(600, 800));
0071 
0072     QTextFrameFormat frameFormat;
0073     frameFormat.setMargin(20);
0074     QTextFrame *rootFrame = newDocument->rootFrame();
0075     rootFrame->setFrameFormat(frameFormat);
0076     QMap<QString, QPair<int, int>> links;
0077     QMap<QString, QTextBlock> targets;
0078 
0079     // go over whole document and add all <a> tags to links or targets map
0080     for (QTextBlock it = newDocument->begin(); it != newDocument->end(); it = it.next()) {
0081         for (QTextBlock::iterator fit = it.begin(); !fit.atEnd(); ++fit) {
0082             QTextFragment frag = fit.fragment();
0083             QTextCharFormat format = frag.charFormat();
0084             if (!format.isAnchor()) {
0085                 continue;
0086             }
0087             // link
0088             if (!format.anchorHref().isEmpty()) {
0089                 links[format.anchorHref()] = QPair<int, int>(frag.position(), frag.position() + frag.length());
0090             }
0091             const QStringList anchors = format.anchorNames();
0092             if (!anchors.isEmpty()) {
0093                 // link targets
0094                 for (const QString &name : anchors) {
0095                     targets[QLatin1Char('#') + name] = it;
0096                 }
0097             }
0098         }
0099     }
0100 
0101     // create link actions
0102     QMapIterator<QString, QPair<int, int>> it(links);
0103     while (it.hasNext()) {
0104         it.next();
0105         QUrl u(it.key());
0106         // external or internal link
0107         if (!u.isRelative()) {
0108             Q_EMIT addAction(new Okular::BrowseAction(QUrl(it.key())), it.value().first, it.value().second);
0109         } else {
0110             // is there valid target?
0111             if (!targets.contains(it.key()) || !targets[it.key()].isValid()) {
0112                 continue;
0113             }
0114             Q_EMIT addAction(new Okular::GotoAction(QString(), calculateViewport(newDocument, targets[it.key()])), it.value().first, it.value().second);
0115         }
0116     }
0117 
0118     return newDocument;
0119 }