converter.cpp 26.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
/***************************************************************************
 *   Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

Albert Astals Cid's avatar
Albert Astals Cid committed
10
11
#include "converter.h"

Yuri Chornoivan's avatar
Yuri Chornoivan committed
12
#include <QAbstractTextDocumentLayout>
Albert Astals Cid's avatar
Albert Astals Cid committed
13
14
15
#include <QDate>
#include <QDomElement>
#include <QDomText>
Yuri Chornoivan's avatar
Yuri Chornoivan committed
16
17
18
#include <QTextCursor>
#include <QTextDocument>
#include <QTextFrame>
Albert Astals Cid's avatar
Albert Astals Cid committed
19
#include <QUrl>
20

Laurent Montel's avatar
Laurent Montel committed
21
#include <KLocalizedString>
22

23
24
#include <core/action.h>
#include <core/document.h>
25
26
27
28
29
30
31

#include "document.h"

using namespace FictionBook;

class Converter::TitleInfo
{
Albert Astals Cid's avatar
Albert Astals Cid committed
32
33
34
35
36
37
38
39
public:
    QStringList mGenres;
    QString mAuthor;
    QString mTitle;
    QStringList mKeywords;
    QDate mDate;
    QDomElement mCoverPage;
    QString mLanguage;
40
41
42
43
};

class Converter::DocumentInfo
{
Albert Astals Cid's avatar
Albert Astals Cid committed
44
45
46
47
48
49
public:
    QString mAuthor;
    QString mProducer;
    QDate mDate;
    QString mId;
    QString mVersion;
50
51
};

52
Converter::Converter()
Albert Astals Cid's avatar
Albert Astals Cid committed
53
54
55
56
    : mTextDocument(nullptr)
    , mCursor(nullptr)
    , mTitleInfo(nullptr)
    , mDocumentInfo(nullptr)
57
58
59
60
61
62
63
64
65
{
}

Converter::~Converter()
{
    delete mTitleInfo;
    delete mDocumentInfo;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
66
QTextDocument *Converter::convert(const QString &fileName)
67
{
Albert Astals Cid's avatar
Albert Astals Cid committed
68
69
70
    Document fbDocument(fileName);
    if (!fbDocument.open()) {
        emit error(fbDocument.lastErrorString(), -1);
71
        return nullptr;
Tobias Koenig's avatar
Tobias Koenig committed
72
    }
73

74
    mTextDocument = new QTextDocument;
Albert Astals Cid's avatar
Albert Astals Cid committed
75
    mCursor = new QTextCursor(mTextDocument);
76
    mSectionCounter = 0;
77
78
    mLocalLinks.clear();
    mSectionMap.clear();
79

80
    const QDomDocument document = fbDocument.content();
81
82
83
84

    /**
     * Set the correct page size
     */
Albert Astals Cid's avatar
Albert Astals Cid committed
85
    mTextDocument->setPageSize(QSizeF(600, 800));
86
87

    QTextFrameFormat frameFormat;
Albert Astals Cid's avatar
Albert Astals Cid committed
88
    frameFormat.setMargin(20);
89
90

    QTextFrame *rootFrame = mTextDocument->rootFrame();
Albert Astals Cid's avatar
Albert Astals Cid committed
91
    rootFrame->setFrameFormat(frameFormat);
92
93
94
95
96
97

    /**
     * Parse the content of the document
     */
    const QDomElement documentElement = document.documentElement();

Albert Astals Cid's avatar
Albert Astals Cid committed
98
99
    if (documentElement.tagName() != QLatin1String("FictionBook")) {
        emit error(i18n("Document is not a valid FictionBook"), -1);
100
        delete mCursor;
101
        return nullptr;
102
103
104
105
106
107
    }

    /**
     * First we read all images, so we can calculate the size later.
     */
    QDomElement element = documentElement.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
108
109
110
    while (!element.isNull()) {
        if (element.tagName() == QLatin1String("binary")) {
            if (!convertBinary(element)) {
111
                delete mCursor;
112
                return nullptr;
113
            }
114
115
116
117
118
119
120
121
122
        }

        element = element.nextSiblingElement();
    }

    /**
     * Read the rest...
     */
    element = documentElement.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
123
124
125
    while (!element.isNull()) {
        if (element.tagName() == QLatin1String("description")) {
            if (!convertDescription(element)) {
126
                delete mCursor;
127
                return nullptr;
128
            }
Albert Astals Cid's avatar
Albert Astals Cid committed
129
130
131
        } else if (element.tagName() == QLatin1String("body")) {
            if (mTitleInfo && !mTitleInfo->mCoverPage.isNull()) {
                convertCover(mTitleInfo->mCoverPage);
132
133
134
135
136
137
                mCursor->insertBlock();
            }

            QTextFrame *topFrame = mCursor->currentFrame();

            QTextFrameFormat frameFormat;
Albert Astals Cid's avatar
Albert Astals Cid committed
138
139
140
            frameFormat.setBorder(2);
            frameFormat.setPadding(8);
            frameFormat.setBackground(Qt::lightGray);
141

Albert Astals Cid's avatar
Albert Astals Cid committed
142
143
            if (mTitleInfo && !mTitleInfo->mTitle.isEmpty()) {
                mCursor->insertFrame(frameFormat);
144
145

                QTextCharFormat charFormat;
Albert Astals Cid's avatar
Albert Astals Cid committed
146
147
148
                charFormat.setFontPointSize(22);
                charFormat.setFontWeight(QFont::Bold);
                mCursor->insertText(mTitleInfo->mTitle, charFormat);
149

Albert Astals Cid's avatar
Albert Astals Cid committed
150
                mCursor->setPosition(topFrame->lastPosition());
151
152
            }

Albert Astals Cid's avatar
Albert Astals Cid committed
153
154
155
            if (mTitleInfo && !mTitleInfo->mAuthor.isEmpty()) {
                frameFormat.setBorder(1);
                mCursor->insertFrame(frameFormat);
156
157

                QTextCharFormat charFormat;
Albert Astals Cid's avatar
Albert Astals Cid committed
158
159
                charFormat.setFontPointSize(10);
                mCursor->insertText(mTitleInfo->mAuthor, charFormat);
160

Albert Astals Cid's avatar
Albert Astals Cid committed
161
                mCursor->setPosition(topFrame->lastPosition());
162
163
164
165
166
                mCursor->insertBlock();
            }

            mCursor->insertBlock();

Albert Astals Cid's avatar
Albert Astals Cid committed
167
            if (!convertBody(element)) {
168
                delete mCursor;
169
                return nullptr;
170
            }
171
172
173
174
175
        }

        element = element.nextSiblingElement();
    }

176
    /**
177
     * Add document info.
178
     */
Albert Astals Cid's avatar
Albert Astals Cid committed
179
180
181
    if (mTitleInfo) {
        if (!mTitleInfo->mTitle.isEmpty())
            emit addMetaData(Okular::DocumentInfo::Title, mTitleInfo->mTitle);
182

Albert Astals Cid's avatar
Albert Astals Cid committed
183
184
        if (!mTitleInfo->mAuthor.isEmpty())
            emit addMetaData(Okular::DocumentInfo::Author, mTitleInfo->mAuthor);
185
186
    }

Albert Astals Cid's avatar
Albert Astals Cid committed
187
188
189
    if (mDocumentInfo) {
        if (!mDocumentInfo->mProducer.isEmpty())
            emit addMetaData(Okular::DocumentInfo::Producer, mDocumentInfo->mProducer);
190

Albert Astals Cid's avatar
Albert Astals Cid committed
191
192
        if (mDocumentInfo->mDate.isValid())
            emit addMetaData(Okular::DocumentInfo::CreationDate, QLocale().toString(mDocumentInfo->mDate, QLocale::ShortFormat));
193
194
    }

Albert Astals Cid's avatar
Albert Astals Cid committed
195
196
    QMapIterator<QString, QPair<int, int>> it(mLocalLinks);
    while (it.hasNext()) {
197
198
        it.next();

Albert Astals Cid's avatar
Albert Astals Cid committed
199
200
201
        const QTextBlock block = mSectionMap[it.key()];
        if (!block.isValid()) // local link without existing target
            continue;
202

Albert Astals Cid's avatar
Albert Astals Cid committed
203
        Okular::DocumentViewport viewport = calculateViewport(mTextDocument, block);
204

Albert Astals Cid's avatar
Albert Astals Cid committed
205
        Okular::GotoAction *action = new Okular::GotoAction(QString(), viewport);
206

Albert Astals Cid's avatar
Albert Astals Cid committed
207
        emit addAction(action, it.value().first, it.value().second);
208
209
    }

210
211
    delete mCursor;

212
    return mTextDocument;
213
214
}

Albert Astals Cid's avatar
Albert Astals Cid committed
215
bool Converter::convertBody(const QDomElement &element)
216
217
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
218
219
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("section")) {
220
            mCursor->insertBlock();
Albert Astals Cid's avatar
Albert Astals Cid committed
221
            if (!convertSection(child))
222
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
223
224
        } else if (child.tagName() == QLatin1String("image")) {
            if (!convertImage(child))
225
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
226
227
        } else if (child.tagName() == QLatin1String("title")) {
            if (!convertTitle(child))
228
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
229
230
        } else if (child.tagName() == QLatin1String("epigraph")) {
            if (!convertEpigraph(child))
231
232
233
234
235
236
237
238
239
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
240
bool Converter::convertDescription(const QDomElement &element)
241
242
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
243
244
245
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("title-info")) {
            if (!convertTitleInfo(child))
246
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
247
248
249
        }
        if (child.tagName() == QLatin1String("document-info")) {
            if (!convertDocumentInfo(child))
250
251
252
253
254
255
256
257
258
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
259
bool Converter::convertTitleInfo(const QDomElement &element)
260
261
262
263
264
{
    delete mTitleInfo;
    mTitleInfo = new TitleInfo;

    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
265
266
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("genre")) {
267
            QString genre;
Albert Astals Cid's avatar
Albert Astals Cid committed
268
            if (!convertTextNode(child, genre))
269
270
                return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
271
272
273
            if (!genre.isEmpty())
                mTitleInfo->mGenres.append(genre);
        } else if (child.tagName() == QLatin1String("author")) {
274
275
            QString firstName, middleName, lastName, dummy;

Albert Astals Cid's avatar
Albert Astals Cid committed
276
            if (!convertAuthor(child, firstName, middleName, lastName, dummy, dummy))
277
278
                return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
279
280
281
            mTitleInfo->mAuthor = QStringLiteral("%1 %2 %3").arg(firstName, middleName, lastName);
        } else if (child.tagName() == QLatin1String("book-title")) {
            if (!convertTextNode(child, mTitleInfo->mTitle))
282
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
283
        } else if (child.tagName() == QLatin1String("keywords")) {
284
            QString keywords;
Albert Astals Cid's avatar
Albert Astals Cid committed
285
            if (!convertTextNode(child, keywords))
286
287
                return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
288
289
290
            mTitleInfo->mKeywords = keywords.split(QLatin1Char(' '), QString::SkipEmptyParts);
        } else if (child.tagName() == QLatin1String("date")) {
            if (!convertDate(child, mTitleInfo->mDate))
291
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
292
        } else if (child.tagName() == QLatin1String("coverpage")) {
293
            mTitleInfo->mCoverPage = child;
Albert Astals Cid's avatar
Albert Astals Cid committed
294
295
        } else if (child.tagName() == QLatin1String("lang")) {
            if (!convertTextNode(child, mTitleInfo->mLanguage))
296
297
298
299
300
301
302
303
                return false;
        }
        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
304
bool Converter::convertDocumentInfo(const QDomElement &element)
305
306
307
308
309
{
    delete mDocumentInfo;
    mDocumentInfo = new DocumentInfo;

    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
310
311
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("author")) {
312
313
            QString firstName, middleName, lastName, email, nickname;

Albert Astals Cid's avatar
Albert Astals Cid committed
314
            if (!convertAuthor(child, firstName, middleName, lastName, email, nickname))
315
316
                return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
317
318
319
            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))
320
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
321
322
        } else if (child.tagName() == QLatin1String("date")) {
            if (!convertDate(child, mDocumentInfo->mDate))
323
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
324
325
        } else if (child.tagName() == QLatin1String("id")) {
            if (!convertTextNode(child, mDocumentInfo->mId))
326
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
327
328
        } else if (child.tagName() == QLatin1String("version")) {
            if (!convertTextNode(child, mDocumentInfo->mVersion))
329
330
331
332
333
334
335
336
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}
Albert Astals Cid's avatar
Albert Astals Cid committed
337
bool Converter::convertAuthor(const QDomElement &element, QString &firstName, QString &middleName, QString &lastName, QString &email, QString &nickname)
338
339
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
340
341
342
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("first-name")) {
            if (!convertTextNode(child, firstName))
343
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
344
345
        } else if (child.tagName() == QLatin1String("middle-name")) {
            if (!convertTextNode(child, middleName))
346
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
347
348
        } else if (child.tagName() == QLatin1String("last-name")) {
            if (!convertTextNode(child, lastName))
349
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
350
351
        } else if (child.tagName() == QLatin1String("email")) {
            if (!convertTextNode(child, email))
352
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
353
354
        } else if (child.tagName() == QLatin1String("nickname")) {
            if (!convertTextNode(child, nickname))
355
356
357
358
359
360
361
362
363
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
364
bool Converter::convertTextNode(const QDomElement &element, QString &data)
365
366
{
    QDomNode child = element.firstChild();
Albert Astals Cid's avatar
Albert Astals Cid committed
367
    while (!child.isNull()) {
368
        QDomText text = child.toText();
Albert Astals Cid's avatar
Albert Astals Cid committed
369
        if (!text.isNull())
370
371
372
373
374
375
376
377
            data = text.data();

        child = child.nextSibling();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
378
bool Converter::convertDate(const QDomElement &element, QDate &date)
379
{
Albert Astals Cid's avatar
Albert Astals Cid committed
380
381
    if (element.hasAttribute(QStringLiteral("value")))
        date = QDate::fromString(element.attribute(QStringLiteral("value")), Qt::ISODate);
382
383
384
385

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
386
bool Converter::convertSection(const QDomElement &element)
387
{
Albert Astals Cid's avatar
Albert Astals Cid committed
388
389
    if (element.hasAttribute(QStringLiteral("id")))
        mSectionMap.insert(element.attribute(QStringLiteral("id")), mCursor->block());
390

391
392
393
    mSectionCounter++;

    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
394
395
396
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("title")) {
            if (!convertTitle(child))
397
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
398
399
        } else if (child.tagName() == QLatin1String("epigraph")) {
            if (!convertEpigraph(child))
400
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
401
402
        } else if (child.tagName() == QLatin1String("image")) {
            if (!convertImage(child))
403
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
404
405
        } else if (child.tagName() == QLatin1String("section")) {
            if (!convertSection(child))
406
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
407
        } else if (child.tagName() == QLatin1String("p")) {
408
            QTextBlockFormat format;
Albert Astals Cid's avatar
Albert Astals Cid committed
409
410
411
            format.setTextIndent(10);
            mCursor->insertBlock(format);
            if (!convertParagraph(child))
412
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
413
414
        } else if (child.tagName() == QLatin1String("poem")) {
            if (!convertPoem(child))
415
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
416
417
        } else if (child.tagName() == QLatin1String("subtitle")) {
            if (!convertSubTitle(child))
418
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
419
420
        } else if (child.tagName() == QLatin1String("cite")) {
            if (!convertCite(child))
421
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
422
423
        } else if (child.tagName() == QLatin1String("empty-line")) {
            if (!convertEmptyLine(child))
424
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
425
426
        } else if (child.tagName() == QLatin1String("code")) {
            if (!convertCode(child))
427
                return false;
428
429
430
431
432
433
434
435
436
437
        }

        child = child.nextSiblingElement();
    }

    mSectionCounter--;

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
438
bool Converter::convertTitle(const QDomElement &element)
439
440
441
442
{
    QTextFrame *topFrame = mCursor->currentFrame();

    QTextFrameFormat frameFormat;
Albert Astals Cid's avatar
Albert Astals Cid committed
443
444
445
    frameFormat.setBorder(1);
    frameFormat.setPadding(8);
    frameFormat.setBackground(Qt::lightGray);
446

Albert Astals Cid's avatar
Albert Astals Cid committed
447
    mCursor->insertFrame(frameFormat);
448
449

    QDomElement child = element.firstChildElement();
450
451

    bool firstParagraph = true;
Albert Astals Cid's avatar
Albert Astals Cid committed
452
453
454
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("p")) {
            if (firstParagraph)
455
456
457
458
                firstParagraph = false;
            else
                mCursor->insertBlock();

459
460
            QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
461
462
463
464
            QTextCharFormat titleFormat(origFormat);
            titleFormat.setFontPointSize(22 - (mSectionCounter * 2));
            titleFormat.setFontWeight(QFont::Bold);
            mCursor->setCharFormat(titleFormat);
465

Albert Astals Cid's avatar
Albert Astals Cid committed
466
            if (!convertParagraph(child))
467
468
                return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
469
            mCursor->setCharFormat(origFormat);
470

Albert Astals Cid's avatar
Albert Astals Cid committed
471
            emit addTitle(mSectionCounter, child.text(), mCursor->block());
472

Albert Astals Cid's avatar
Albert Astals Cid committed
473
474
        } else if (child.tagName() == QLatin1String("empty-line")) {
            if (!convertEmptyLine(child))
475
476
477
478
479
480
                return false;
        }

        child = child.nextSiblingElement();
    }

Albert Astals Cid's avatar
Albert Astals Cid committed
481
    mCursor->setPosition(topFrame->lastPosition());
482
483
484
485

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
486
bool Converter::convertParagraph(const QDomElement &element)
487
488
{
    QDomNode child = element.firstChild();
Albert Astals Cid's avatar
Albert Astals Cid committed
489
490
    while (!child.isNull()) {
        if (child.isElement()) {
491
            const QDomElement childElement = child.toElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
492
493
            if (childElement.tagName() == QLatin1String("emphasis")) {
                if (!convertEmphasis(childElement))
494
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
495
496
            } else if (childElement.tagName() == QLatin1String("strong")) {
                if (!convertStrong(childElement))
497
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
498
499
            } else if (childElement.tagName() == QLatin1String("style")) {
                if (!convertStyle(childElement))
500
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
501
502
            } else if (childElement.tagName() == QLatin1String("a")) {
                if (!convertLink(childElement))
503
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
504
505
            } else if (childElement.tagName() == QLatin1String("image")) {
                if (!convertImage(childElement))
506
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
507
508
            } else if (childElement.tagName() == QLatin1String("strikethrough")) {
                if (!convertStrikethrough(childElement))
509
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
510
511
            } else if (childElement.tagName() == QLatin1String("code")) {
                if (!convertCode(childElement))
512
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
513
514
            } else if (childElement.tagName() == QLatin1String("sup")) {
                if (!convertSuperScript(childElement))
515
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
516
517
            } else if (childElement.tagName() == QLatin1String("sub")) {
                if (!convertSubScript(childElement))
518
                    return false;
519
            }
Albert Astals Cid's avatar
Albert Astals Cid committed
520
        } else if (child.isText()) {
521
            const QDomText childText = child.toText();
Albert Astals Cid's avatar
Albert Astals Cid committed
522
            mCursor->insertText(childText.data());
523
524
525
526
527
528
529
530
        }

        child = child.nextSibling();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
531
bool Converter::convertEmphasis(const QDomElement &element)
532
533
534
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
535
536
537
    QTextCharFormat italicFormat(origFormat);
    italicFormat.setFontItalic(true);
    mCursor->setCharFormat(italicFormat);
538

Albert Astals Cid's avatar
Albert Astals Cid committed
539
    if (!convertParagraph(element))
540
541
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
542
    mCursor->setCharFormat(origFormat);
543
544
545
546

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
547
bool Converter::convertStrikethrough(const QDomElement &element)
548
549
550
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
551
552
553
    QTextCharFormat strikeoutFormat(origFormat);
    strikeoutFormat.setFontStrikeOut(true);
    mCursor->setCharFormat(strikeoutFormat);
554

Albert Astals Cid's avatar
Albert Astals Cid committed
555
    if (!convertParagraph(element))
556
557
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
558
    mCursor->setCharFormat(origFormat);
559
560
561
562

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
563
bool Converter::convertStrong(const QDomElement &element)
564
565
566
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
567
568
569
    QTextCharFormat boldFormat(origFormat);
    boldFormat.setFontWeight(QFont::Bold);
    mCursor->setCharFormat(boldFormat);
570

Albert Astals Cid's avatar
Albert Astals Cid committed
571
    if (!convertParagraph(element))
572
573
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
574
    mCursor->setCharFormat(origFormat);
575
576
577
578

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
579
bool Converter::convertStyle(const QDomElement &element)
580
{
Albert Astals Cid's avatar
Albert Astals Cid committed
581
    if (!convertParagraph(element))
582
583
584
585
586
        return false;

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
587
bool Converter::convertBinary(const QDomElement &element)
588
{
Albert Astals Cid's avatar
Albert Astals Cid committed
589
    const QString id = element.attribute(QStringLiteral("id"));
590
591
592

    const QDomText textNode = element.firstChild().toText();
    QByteArray data = textNode.data().toLatin1();
Albert Astals Cid's avatar
Albert Astals Cid committed
593
    data = QByteArray::fromBase64(data);
594

Albert Astals Cid's avatar
Albert Astals Cid committed
595
    mTextDocument->addResource(QTextDocument::ImageResource, QUrl(id), QImage::fromData(data));
596
597
598
599

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
600
bool Converter::convertCover(const QDomElement &element)
601
602
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
603
604
605
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("image")) {
            if (!convertImage(child))
606
607
608
609
610
611
612
613
614
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
615
bool Converter::convertImage(const QDomElement &element)
616
{
Albert Astals Cid's avatar
Albert Astals Cid committed
617
    QString href = element.attributeNS(QStringLiteral("http://www.w3.org/1999/xlink"), QStringLiteral("href"));
618

Albert Astals Cid's avatar
Albert Astals Cid committed
619
620
    if (href.startsWith(QLatin1Char('#')))
        href = href.mid(1);
621

Albert Astals Cid's avatar
Albert Astals Cid committed
622
    const QImage img = qvariant_cast<QImage>(mTextDocument->resource(QTextDocument::ImageResource, QUrl(href)));
623
624

    QTextImageFormat format;
Albert Astals Cid's avatar
Albert Astals Cid committed
625
    format.setName(href);
626

Albert Astals Cid's avatar
Albert Astals Cid committed
627
628
    if (img.width() > 560)
        format.setWidth(560);
629

Albert Astals Cid's avatar
Albert Astals Cid committed
630
    format.setHeight(img.height());
631

Albert Astals Cid's avatar
Albert Astals Cid committed
632
    mCursor->insertImage(format);
633
634
635
636

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
637
bool Converter::convertEpigraph(const QDomElement &element)
638
639
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
640
641
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("p")) {
642
            QTextBlockFormat format;
Albert Astals Cid's avatar
Albert Astals Cid committed
643
644
645
            format.setTextIndent(10);
            mCursor->insertBlock(format);
            if (!convertParagraph(child))
646
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
647
648
        } else if (child.tagName() == QLatin1String("poem")) {
            if (!convertPoem(child))
649
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
650
651
        } else if (child.tagName() == QLatin1String("cite")) {
            if (!convertCite(child))
652
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
653
654
        } else if (child.tagName() == QLatin1String("empty-line")) {
            if (!convertEmptyLine(child))
655
656
657
658
659
660
661
662
663
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
664
bool Converter::convertPoem(const QDomElement &element)
665
666
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
667
668
669
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("title")) {
            if (!convertTitle(child))
670
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
671
672
        } else if (child.tagName() == QLatin1String("epigraph")) {
            if (!convertEpigraph(child))
673
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
674
675
        } else if (child.tagName() == QLatin1String("empty-line")) {
            if (!convertEmptyLine(child))
676
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
677
678
        } else if (child.tagName() == QLatin1String("stanza")) {
            if (!convertStanza(child))
679
                return false;
680
681
682
683
684
685
686
687
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
688
bool Converter::convertSubTitle(const QDomElement &element)
689
{
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    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());

706
707
708
    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
709
bool Converter::convertCite(const QDomElement &element)
710
711
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
712
713
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("p")) {
714
            QTextBlockFormat format;
Albert Astals Cid's avatar
Albert Astals Cid committed
715
716
717
            format.setTextIndent(10);
            mCursor->insertBlock(format);
            if (!convertParagraph(child))
718
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
719
720
        } else if (child.tagName() == QLatin1String("poem")) {
            if (!convertParagraph(child))
721
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
722
723
        } else if (child.tagName() == QLatin1String("empty-line")) {
            if (!convertEmptyLine(child))
724
                return false;
725
726
727
        } else if (child.tagName() == QLatin1String("subtitle")) {
            if (!convertSubTitle(child))
                return false;
728
729
730
731
732
733
734
735
        }

        child = child.nextSiblingElement();
    }

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
736
bool Converter::convertEmptyLine(const QDomElement &)
737
{
Albert Astals Cid's avatar
Albert Astals Cid committed
738
    mCursor->insertText(QStringLiteral("\n\n"));
739
740
741
    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
742
bool Converter::convertLink(const QDomElement &element)
743
{
Albert Astals Cid's avatar
Albert Astals Cid committed
744
745
    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"));
746

Albert Astals Cid's avatar
Albert Astals Cid committed
747
748
    if (type == QLatin1String("note"))
        mCursor->insertText(QStringLiteral("["));
749

750
    int startPosition = mCursor->position();
751

Albert Astals Cid's avatar
Albert Astals Cid committed
752
    QTextCharFormat origFormat(mCursor->charFormat());
753

Albert Astals Cid's avatar
Albert Astals Cid committed
754
755
756
757
    QTextCharFormat format(mCursor->charFormat());
    format.setForeground(Qt::blue);
    format.setFontUnderline(true);
    mCursor->setCharFormat(format);
758
759

    QDomNode child = element.firstChild();
Albert Astals Cid's avatar
Albert Astals Cid committed
760
761
    while (!child.isNull()) {
        if (child.isElement()) {
762
            const QDomElement childElement = child.toElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
763
764
            if (childElement.tagName() == QLatin1String("emphasis")) {
                if (!convertEmphasis(childElement))
765
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
766
767
            } else if (childElement.tagName() == QLatin1String("strong")) {
                if (!convertStrong(childElement))
768
                    return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
769
770
            } else if (childElement.tagName() == QLatin1String("style")) {
                if (!convertStyle(childElement))
771
772
                    return false;
            }
Albert Astals Cid's avatar
Albert Astals Cid committed
773
        } else if (child.isText()) {
774
            const QDomText text = child.toText();
Albert Astals Cid's avatar
Albert Astals Cid committed
775
776
            if (!text.isNull()) {
                mCursor->insertText(text.data());
777
778
779
780
781
            }
        }

        child = child.nextSibling();
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
782
    mCursor->setCharFormat(origFormat);
783

784
    int endPosition = mCursor->position();
785

Albert Astals Cid's avatar
Albert Astals Cid committed
786
787
    if (type == QLatin1String("note"))
        mCursor->insertText(QStringLiteral("]"));
788

Albert Astals Cid's avatar
Albert Astals Cid committed
789
790
    if (href.startsWith(QLatin1Char('#'))) { // local link
        mLocalLinks.insert(href.mid(1), QPair<int, int>(startPosition, endPosition));
791
792
    } else {
        // external link
Albert Astals Cid's avatar
Albert Astals Cid committed
793
794
        Okular::BrowseAction *action = new Okular::BrowseAction(QUrl(href));
        emit addAction(action, startPosition, endPosition);
795
    }
796
797
798

    return true;
}
799

Albert Astals Cid's avatar
Albert Astals Cid committed
800
bool Converter::convertStanza(const QDomElement &element)
801
802
{
    QDomElement child = element.firstChildElement();
Albert Astals Cid's avatar
Albert Astals Cid committed
803
804
805
    while (!child.isNull()) {
        if (child.tagName() == QLatin1String("title")) {
            if (!convertTitle(child))
806
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
807
808
        } else if (child.tagName() == QLatin1String("subtitle")) {
            if (!convertSubTitle(child))
809
                return false;
Albert Astals Cid's avatar
Albert Astals Cid committed
810
        } else if (child.tagName() == QLatin1String("v")) {
811
            QTextBlockFormat format;
Albert Astals Cid's avatar
Albert Astals Cid committed
812
813
814
            format.setTextIndent(50);
            mCursor->insertBlock(format);
            if (!convertParagraph(child))
815
816
817
818
819
820
821
822
                return false;
        }

        child = child.nextSiblingElement();
    }

    return true;
}
823

Albert Astals Cid's avatar
Albert Astals Cid committed
824
bool Converter::convertCode(const QDomElement &element)
825
826
827
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
828
829
830
    QTextCharFormat codeFormat(origFormat);
    codeFormat.setFontFamily(QStringLiteral("monospace"));
    mCursor->setCharFormat(codeFormat);
831

Albert Astals Cid's avatar
Albert Astals Cid committed
832
    if (!convertParagraph(element))
833
834
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
835
    mCursor->setCharFormat(origFormat);
836
837
838
839

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
840
bool Converter::convertSuperScript(const QDomElement &element)
841
842
843
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
844
845
846
    QTextCharFormat superScriptFormat(origFormat);
    superScriptFormat.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
    mCursor->setCharFormat(superScriptFormat);
847

Albert Astals Cid's avatar
Albert Astals Cid committed
848
    if (!convertParagraph(element))
849
850
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
851
    mCursor->setCharFormat(origFormat);
852
853
854
855

    return true;
}

Albert Astals Cid's avatar
Albert Astals Cid committed
856
bool Converter::convertSubScript(const QDomElement &element)
857
858
859
{
    QTextCharFormat origFormat = mCursor->charFormat();

Albert Astals Cid's avatar
Albert Astals Cid committed
860
861
862
    QTextCharFormat subScriptFormat(origFormat);
    subScriptFormat.setVerticalAlignment(QTextCharFormat::AlignSubScript);
    mCursor->setCharFormat(subScriptFormat);
863

Albert Astals Cid's avatar
Albert Astals Cid committed
864
    if (!convertParagraph(element))
865
866
        return false;

Albert Astals Cid's avatar
Albert Astals Cid committed
867
    mCursor->setCharFormat(origFormat);
868
869
870

    return true;
}