diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt index a98916e10..6ec0edc67 100644 --- a/generators/CMakeLists.txt +++ b/generators/CMakeLists.txt @@ -72,3 +72,5 @@ endif(JPEG_FOUND AND ZLIB_FOUND) if(EPUB_FOUND) add_subdirectory(epub) endif(EPUB_FOUND) + +add_subdirectory(mobipocket) \ No newline at end of file diff --git a/generators/mobipocket/CMakeLists.txt b/generators/mobipocket/CMakeLists.txt new file mode 100644 index 000000000..df0d7ff2e --- /dev/null +++ b/generators/mobipocket/CMakeLists.txt @@ -0,0 +1,28 @@ +find_package(KDE4 REQUIRED) +find_package(Okular REQUIRED) +include_directories(${KDE4_INCLUDES} ${QT_INCLUDES} + ${CMAKE_CURRENT_SOURCE_DIR} + ${OKULAR_INCLUDE_DIR} + ${PROJECT_SOURCE_DIR}/../libs/mobipocket + ) + +########### next target ############### + +set(okularGenerator_mobi_PART_SRCS + ${PROJECT_SOURCE_DIR}/../libs/mobipocket/mobipocket.cpp + ${PROJECT_SOURCE_DIR}/../libs/mobipocket/decompressor.cpp + mobidocument.cpp + generator_mobi.cpp + converter.cpp +) + +kde4_add_plugin(okularGenerator_mobi ${okularGenerator_mobi_PART_SRCS}) + +target_link_libraries(okularGenerator_mobi ${OKULAR_LIBRARIES} ${mobi_LIBRARIES} ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY}) + +install(TARGETS okularGenerator_mobi DESTINATION ${PLUGIN_INSTALL_DIR}) + +########### install files ############### + +install( FILES libokularGenerator_mobi.desktop okularMobi.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES okularApplication_mobi.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) diff --git a/generators/mobipocket/converter.cpp b/generators/mobipocket/converter.cpp new file mode 100644 index 000000000..51049030a --- /dev/null +++ b/generators/mobipocket/converter.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ + +#include "converter.h" + +#include +#include +#include +#include +#include +#include +#include +#include "mobipocket.h" + +#include +#include + +using namespace Mobi; + +Converter::Converter() +{ + +} + +Converter::~Converter() +{ +} + +void Converter::handleMetadata(const QMap metadata) +{ + QMapIterator it(metadata); + while (it.hasNext()) { + it.next(); + switch (it.key()) { + case Mobipocket::Document::Title: addMetaData(Okular::DocumentInfo::Title, it.value()); break; + case Mobipocket::Document::Author: addMetaData(Okular::DocumentInfo::Author, it.value()); break; + case Mobipocket::Document::Description: addMetaData(Okular::DocumentInfo::Description, it.value()); break; + case Mobipocket::Document::Subject: addMetaData(Okular::DocumentInfo::Subject, it.value()); break; + case Mobipocket::Document::Copyright: addMetaData(Okular::DocumentInfo::Copyright, it.value()); break; + } + } +} + +QTextDocument* Converter::convert( const QString &fileName ) +{ + MobiDocument* newDocument=new MobiDocument(fileName); + if (!newDocument->mobi()->isValid()) { + emit error(i18n("Error while opening the Mobipocket document."), -1); + delete newDocument; + return NULL; + } + if (newDocument->mobi()->hasDRM()) { + emit error(i18n("This book is protected by DRM and can be displayed only on designated device"), -1); + delete newDocument; + return NULL; + } + + handleMetadata(newDocument->mobi()->metadata()); + newDocument->setPageSize(QSizeF(600, 800)); + + QTextFrameFormat frameFormat; + frameFormat.setMargin( 20 ); + QTextFrame *rootFrame = newDocument->rootFrame(); + rootFrame->setFrameFormat( frameFormat ); + QMap > links; + QMap targets; + + // go over whole document and add all tags to links or targets map + for (QTextBlock it = newDocument->begin(); it != newDocument->end(); it = it.next()) + for (QTextBlock::iterator fit=it.begin(); !fit.atEnd(); ++fit) { + QTextFragment frag=fit.fragment(); + QTextCharFormat format=frag.charFormat(); + if (!format.isAnchor()) continue; + //link + if (!format.anchorHref().isEmpty()) links[format.anchorHref()]= + QPair(frag.position(), frag.position()+frag.length()); + if (!format.anchorNames().isEmpty()) { + // link targets + Q_FOREACH(const QString& name, format.anchorNames()) + targets['#'+name]=it; + } + } + + // create link actions + QMapIterator > it(links); + while (it.hasNext()) { + it.next(); + QUrl u(it.key()); + // external or internal link + if (!u.isRelative()) emit addAction(new Okular::BrowseAction(it.key()), it.value().first, it.value().second); + else { + // is there valid target? + if (!targets.contains( it.key() ) || !targets[it.key()].isValid()) continue; + emit addAction(new Okular::GotoAction(QString(), calculateViewport( newDocument, targets[it.key()] )), + it.value().first, it.value().second); + } + + } + + return newDocument; +} diff --git a/generators/mobipocket/converter.h b/generators/mobipocket/converter.h new file mode 100644 index 000000000..038fcc444 --- /dev/null +++ b/generators/mobipocket/converter.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ +#ifndef MOBI_CONVERTER_H +#define MOBI_CONVERTER_H + +#include +#include + +#include "mobidocument.h" +#include "mobipocket.h" + + +namespace Mobi { + class Converter : public Okular::TextDocumentConverter + { + public: + Converter(); + ~Converter(); + + virtual QTextDocument *convert( const QString &fileName ); + private: + void handleMetadata(const QMap metadata); + }; +} + +#endif diff --git a/generators/mobipocket/generator_mobi.cpp b/generators/mobipocket/generator_mobi.cpp new file mode 100644 index 000000000..0e658f15e --- /dev/null +++ b/generators/mobipocket/generator_mobi.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ely Levy * + * * + * 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. * + ***************************************************************************/ +#include "generator_mobi.h" + +#include "converter.h" + +#include + +static KAboutData createAboutData() +{ + KAboutData aboutData( + "okular_mobi", + "okular_mobi", + ki18n("Mobipocket Backend"), + "0.1", + ki18n("A mobipocket backend"), + KAboutData::License_GPL, + ki18n("© 2008-2009 Jakub Stachowski") + ); + aboutData.addAuthor(ki18n("Jakub Stachowski"), KLocalizedString(), + "qbast@go2.pl"); + + return aboutData; +} + +OKULAR_EXPORT_PLUGIN( MobiGenerator, createAboutData() ) + +MobiGenerator::MobiGenerator( QObject *parent, const QVariantList &args ) +: Okular::TextDocumentGenerator( new Mobi::Converter, parent, args ) +{ +} diff --git a/generators/mobipocket/generator_mobi.h b/generators/mobipocket/generator_mobi.h new file mode 100644 index 000000000..db4a2b727 --- /dev/null +++ b/generators/mobipocket/generator_mobi.h @@ -0,0 +1,20 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ely Levy * + * * + * 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. * + ***************************************************************************/ +#ifndef OKULAR_GENERATOR_MOBI_H +#define OKULAR_GENERATOR_MOBI_H +#include + +class MobiGenerator : public Okular::TextDocumentGenerator +{ + public: + MobiGenerator( QObject *parent, const QVariantList &args ); + ~MobiGenerator() {} +}; + +#endif diff --git a/generators/mobipocket/libokularGenerator_mobi.desktop b/generators/mobipocket/libokularGenerator_mobi.desktop new file mode 100644 index 000000000..3844bd508 --- /dev/null +++ b/generators/mobipocket/libokularGenerator_mobi.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +Name=Mobipocket document +Name[el]=Έγγραφο Mobipocket +Name[es]=Documento Mobipocket +Name[et]=Mobipocketi dokument +Name[fr]=Document mobipocket +Name[ga]=Cáipéis Mobipocket +Name[ja]=Mobipocket 文書 +Name[nds]=Mobipocket-Dokment +Name[nl]=Mobipocket-document +Name[pt]=Documento Mobipocket +Name[pt_BR]=Documento Mobipocket +Name[sv]=Mobipocket-dokument +Name[tr]=Mobipocket belgesi +Name[uk]=Документ Mobipocket +Name[x-test]=xxMobipocket documentxx +Name[zh_CN]=Mobipocket 文档 +Name[zh_TW]=Mobipocket 文件 +Comment=Mobipocket backend for Okular +Comment[el]=Σύστημα υποστήριξης Mobipocket για το Okular +Comment[es]=Motor de Mobipocket para Okular +Comment[et]=Okulari Mobipocketi taustaprogramm +Comment[fr]=Moteur Mobipocket pour Okular +Comment[ga]=Inneall Mobipocket le haghaidh Okular +Comment[ja]=Okular の Mobipocket 用バックエンド +Comment[nds]=Mobipocket-Hülppropgramm för Okular +Comment[nl]=Mobipocket-backend voor Okular +Comment[pt]=Interface do Mobipocket para o Okular +Comment[pt_BR]=Infraestrutura Mobipocket para o Okular +Comment[sv]=Mobipocket-gränssnitt för Okular +Comment[tr]=Okular için Mobipocket arka ucu +Comment[uk]=Сервер Mobipocket для Okular +Comment[x-test]=xxMobipocket backend for Okularxx +Comment[zh_CN]=Okular Mobipocket 后端 +Comment[zh_TW]=Okular 的 Mobipocket 後端介面 +X-KDE-ServiceTypes=okular/Generator +MimeType=application/x-mobipocket-ebook; +X-KDE-Library=okularGenerator_mobi +X-KDE-Priority=1 +X-KDE-okularAPIVersion=1 +X-KDE-okularHasInternalSettings=false diff --git a/generators/mobipocket/mobidocument.cpp b/generators/mobipocket/mobidocument.cpp new file mode 100644 index 000000000..c22888718 --- /dev/null +++ b/generators/mobipocket/mobidocument.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ +#include "mobidocument.h" +#include "mobipocket.h" +#include "qfilestream.h" +#include +#include +#include + +using namespace Mobi; + +MobiDocument::MobiDocument(const QString &fileName) : QTextDocument() +{ + file = new Mobipocket::QFileStream(fileName); + doc = new Mobipocket::Document(file); + if (doc->isValid()) setHtml(fixMobiMarkup(doc->text())); +} + +MobiDocument::~MobiDocument() +{ + delete doc; + delete file; +} + +QVariant MobiDocument::loadResource(int type, const QUrl &name) +{ + if (type!=QTextDocument::ImageResource || name.scheme()!=QString("pdbrec")) return QVariant(); + bool ok; + quint16 recnum=name.path().mid(1).toUShort(&ok); + if (!ok || recnum>=doc->imageCount()) return QVariant(); + + QVariant resource; + resource.setValue(doc->getImage(recnum-1)); + addResource(type, name, resource); + + return resource; +} + +// starting from 'pos', find position in the string that is not inside a tag +int outsideTag(const QString& data, int pos) +{ + for (int i=pos-1;i>=0;i--) { + if (data[i]=='>') return pos; + if (data[i]=='<') return i; + } + return pos; +} + +QString MobiDocument::fixMobiMarkup(const QString& data) +{ + QString ret=data; + QMap anchorPositions; + static QRegExp anchors(" it(anchorPositions); + while (it.hasNext()) { + it.next(); + // link pointing outside the document, ignore + if ( (it.key()+offset) >= ret.size()) continue; + int fixedpos=outsideTag(ret, it.key()+offset); + ret.insert(fixedpos,QString(" ")); + // inserting anchor shifts all offsets after the anchor + offset+=21+it.value().size(); + } + + // replace links referencing filepos with normal internal links + ret.replace(anchors," where recindex is number of + // record containing image + static QRegExp imgs("", Qt::CaseInsensitive); + + imgs.setMinimal(true); + ret.replace(imgs,""); + ret.replace("","

"); + return ret; +} diff --git a/generators/mobipocket/mobidocument.h b/generators/mobipocket/mobidocument.h new file mode 100644 index 000000000..1d1b9bf55 --- /dev/null +++ b/generators/mobipocket/mobidocument.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ +#ifndef MOBI_DOCUMENT_H +#define MOBI_DOCUMENT_H + +#include +#include +#include + +class QFile; +namespace Mobipocket { +class Document; +class QFileStream; +} + +namespace Mobi { + + class MobiDocument : public QTextDocument { + + public: + MobiDocument(const QString &fileName); + ~MobiDocument(); + + Mobipocket::Document* mobi() const { return doc; } + + protected: + virtual QVariant loadResource(int type, const QUrl &name); + + private: + QString fixMobiMarkup(const QString& data); + Mobipocket::Document *doc; + Mobipocket::QFileStream* file; + }; + +} +#endif diff --git a/generators/mobipocket/okularApplication_mobi.desktop b/generators/mobipocket/okularApplication_mobi.desktop new file mode 100644 index 000000000..042f25e5d --- /dev/null +++ b/generators/mobipocket/okularApplication_mobi.desktop @@ -0,0 +1,28 @@ +[Desktop Entry] +MimeType=application/x-mobipocket-ebook; +Terminal=false +Name=Okular +Name[x-test]=xxOkularxx +GenericName=Document Viewer +GenericName[el]=Προβολέας εγγράφων +GenericName[es]=Visor de documentos +GenericName[et]=Dokumentide näitaja +GenericName[fr]=Visonneuse de document +GenericName[ga]=Amharcán Cáipéisí +GenericName[ja]=文書ビューア +GenericName[nds]=Dokmentkieker +GenericName[nl]=Documentviewer +GenericName[pt]=Visualizador de Documentos +GenericName[pt_BR]=Visualizador de documentos +GenericName[sv]=Dokumentvisning +GenericName[tr]=Belge Gösterici +GenericName[uk]=Переглядач документів +GenericName[x-test]=xxDocument Viewerxx +GenericName[zh_CN]=文档查看器 +GenericName[zh_TW]=文件檢視器 +Exec=okular %U %i -caption "%c" +Icon=okular +Type=Application +InitialPreference=1 +Categories=Qt;KDE;Graphics;Viewer; +NoDisplay=true diff --git a/generators/mobipocket/okularMobi.desktop b/generators/mobipocket/okularMobi.desktop new file mode 100644 index 000000000..c0b15caa0 --- /dev/null +++ b/generators/mobipocket/okularMobi.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Icon=okular +Name=Okular +Name[x-test]=xxOkularxx +X-KDE-ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=okularpart +Type=Service +MimeType=application/x-mobipocket-ebook;