mirror of
https://invent.kde.org/graphics/okular
synced 2024-08-27 03:30:20 +00:00
Add generator plugin for the FictionBook format (http://en.wikipedia.org/wiki/FictionBook),
you can find documents e.g. under http://www.fictionbook.ru svn path=/trunk/playground/graphics/okular/; revision=620876
This commit is contained in:
parent
2538e1fce0
commit
53c97a481b
|
@ -28,3 +28,4 @@ add_subdirectory(xps)
|
|||
|
||||
add_subdirectory(ooo)
|
||||
|
||||
add_subdirectory(fictionbook)
|
||||
|
|
26
generators/fictionbook/CMakeLists.txt
Normal file
26
generators/fictionbook/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
include_directories(
|
||||
${CMAKE_BINARY_DIR}/okular
|
||||
${CMAKE_SOURCE_DIR}/okular
|
||||
)
|
||||
|
||||
|
||||
########### next target ###############
|
||||
|
||||
set(okularGenerator_fb_PART_SRCS
|
||||
converter.cpp
|
||||
document.cpp
|
||||
generator_fb.cpp
|
||||
)
|
||||
|
||||
kde4_automoc(${okularGenerator_fb_PART_SRCS})
|
||||
|
||||
kde4_add_plugin(okularGenerator_fb WITH_PREFIX ${okularGenerator_fb_PART_SRCS})
|
||||
|
||||
target_link_libraries(okularGenerator_fb ${POPPLER_LIBRARY} okularcore ${KDE4_KDEPRINT_LIBS} m )
|
||||
|
||||
install(TARGETS okularGenerator_fb DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||
|
||||
|
||||
########### install files ###############
|
||||
|
||||
install( FILES libokularGenerator_fb.desktop okularFb.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
826
generators/fictionbook/converter.cpp
Normal file
826
generators/fictionbook/converter.cpp
Normal file
|
@ -0,0 +1,826 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QtCore/QStack>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtGui/QAbstractTextDocumentLayout>
|
||||
#include <QtGui/QTextCursor>
|
||||
#include <QtGui/QTextDocument>
|
||||
#include <QtGui/QTextFrame>
|
||||
#include <QtXml/QDomElement>
|
||||
#include <QtXml/QDomText>
|
||||
|
||||
#include <kglobal.h>
|
||||
#include <klocale.h>
|
||||
|
||||
#include <okular/core/document.h>
|
||||
|
||||
#include "converter.h"
|
||||
#include "document.h"
|
||||
|
||||
using namespace FictionBook;
|
||||
|
||||
class Converter::TitleInfo
|
||||
{
|
||||
public:
|
||||
QStringList mGenres;
|
||||
QString mAuthor;
|
||||
QString mTitle;
|
||||
QStringList mKeywords;
|
||||
QDate mDate;
|
||||
QDomElement mCoverPage;
|
||||
QString mLanguage;
|
||||
};
|
||||
|
||||
class Converter::DocumentInfo
|
||||
{
|
||||
public:
|
||||
QString mAuthor;
|
||||
QString mProducer;
|
||||
QDate mDate;
|
||||
QString mId;
|
||||
QString mVersion;
|
||||
};
|
||||
|
||||
Converter::Converter( const Document *document )
|
||||
: mDocument( document ), mTextDocument( 0 ), mCursor( 0 ),
|
||||
mTitleInfo( 0 ), mDocumentInfo( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Converter::~Converter()
|
||||
{
|
||||
delete mTitleInfo;
|
||||
delete mDocumentInfo;
|
||||
}
|
||||
|
||||
bool Converter::convert()
|
||||
{
|
||||
delete mTextDocument;
|
||||
delete mCursor;
|
||||
|
||||
mTextDocument = new QTextDocument;
|
||||
mCursor = new QTextCursor( mTextDocument );
|
||||
mSectionCounter = 0;
|
||||
mLinkInfosGenerated = false;
|
||||
|
||||
const QDomDocument document = mDocument->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" ) ) {
|
||||
qDebug( "Not a valid FictionBook!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
element = element.nextSiblingElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the rest...
|
||||
*/
|
||||
element = documentElement.firstChildElement();
|
||||
while ( !element.isNull() ) {
|
||||
if ( element.tagName() == QLatin1String( "description" ) ) {
|
||||
if ( !convertDescription( element ) )
|
||||
return false;
|
||||
} else if ( element.tagName() == QLatin1String( "body" ) ) {
|
||||
if ( !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->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->mAuthor.isEmpty() ) {
|
||||
frameFormat.setBorder( 1 );
|
||||
mCursor->insertFrame( frameFormat );
|
||||
|
||||
QTextCharFormat charFormat;
|
||||
charFormat.setFontPointSize( 10 );
|
||||
mCursor->insertText( mTitleInfo->mAuthor, charFormat );
|
||||
|
||||
mCursor->setPosition( topFrame->lastPosition() );
|
||||
mCursor->insertBlock();
|
||||
}
|
||||
|
||||
mCursor->insertBlock();
|
||||
|
||||
if ( !convertBody( element ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
element = element.nextSiblingElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
mTitleInfo->mAuthor = QString( "%1 %2 %3" ).arg( firstName, middleName, lastName );
|
||||
} 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.split( ' ', QString::SkipEmptyParts );
|
||||
} 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 = QString( "%1 %2 %3 <%4> (%5)" )
|
||||
.arg( firstName ).arg( middleName ).arg( lastName )
|
||||
.arg( email ).arg( 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( "value" ) )
|
||||
date = QDate::fromString( element.attribute( "value" ), Qt::ISODate );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter::convertSection( const QDomElement &element )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
while ( !child.isNull() ) {
|
||||
if ( child.tagName() == QLatin1String( "p" ) ) {
|
||||
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 );
|
||||
|
||||
HeaderInfo headerInfo;
|
||||
headerInfo.block = mCursor->block();
|
||||
headerInfo.text = child.text();
|
||||
headerInfo.level = mSectionCounter;
|
||||
mHeaderInfos.append( headerInfo );
|
||||
|
||||
} 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 ( child.isText() ) {
|
||||
const QDomText childText = child.toText();
|
||||
mCursor->insertText( childText.data() );
|
||||
}
|
||||
|
||||
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::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( "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( "http://www.w3.org/1999/xlink", "href" );
|
||||
|
||||
if ( href.startsWith( '#' ) )
|
||||
href = href.mid( 1 );
|
||||
|
||||
const QImage img = qVariantValue<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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
child = child.nextSiblingElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter::convertSubTitle( const QDomElement &element )
|
||||
{
|
||||
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( "empty-line" ) ) {
|
||||
if ( !convertEmptyLine( child ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
child = child.nextSiblingElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter::convertEmptyLine( const QDomElement &element )
|
||||
{
|
||||
mCursor->insertText( "\n\n" );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter::convertLink( const QDomElement &element )
|
||||
{
|
||||
QString href = element.attributeNS( "http://www.w3.org/1999/xlink", "href" );
|
||||
QString type = element.attributeNS( "http://www.w3.org/1999/xlink", "type" );
|
||||
|
||||
if ( type == "note" )
|
||||
mCursor->insertText( "[" );
|
||||
|
||||
LinkPosition pos;
|
||||
pos.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 );
|
||||
|
||||
pos.endPosition = mCursor->position();
|
||||
pos.url = href;
|
||||
|
||||
if ( type == "note" )
|
||||
mCursor->insertText( "]" );
|
||||
|
||||
mLinkPositions.append( pos );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextDocument *Converter::textDocument() const
|
||||
{
|
||||
return mTextDocument;
|
||||
}
|
||||
|
||||
Okular::DocumentInfo Converter::documentInfo() const
|
||||
{
|
||||
Okular::DocumentInfo info;
|
||||
|
||||
if ( mTitleInfo ) {
|
||||
if ( !mTitleInfo->mTitle.isEmpty() )
|
||||
info.set( "title", mTitleInfo->mTitle, i18n( "Title" ) );
|
||||
|
||||
if ( !mTitleInfo->mAuthor.isEmpty() )
|
||||
info.set( "author", mTitleInfo->mAuthor, i18n( "Author" ) );
|
||||
}
|
||||
|
||||
if ( mDocumentInfo ) {
|
||||
if ( !mDocumentInfo->mProducer.isEmpty() )
|
||||
info.set( "producer", mDocumentInfo->mProducer, i18n( "Producer" ) );
|
||||
|
||||
if ( !mDocumentInfo->mProducer.isEmpty() )
|
||||
info.set( "creator", mDocumentInfo->mAuthor, i18n( "Creator" ) );
|
||||
|
||||
if ( mDocumentInfo->mDate.isValid() )
|
||||
info.set( "creationDate",
|
||||
KGlobal::locale()->formatDate( mDocumentInfo->mDate, true ),
|
||||
i18n( "Created" ) );
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Okular::DocumentSynopsis Converter::tableOfContents() const
|
||||
{
|
||||
const QSizeF pageSize = mTextDocument->pageSize();
|
||||
|
||||
QStack<QDomNode> parentNodeStack;
|
||||
|
||||
Okular::DocumentSynopsis tableOfContents;
|
||||
QDomNode parentNode = tableOfContents;
|
||||
|
||||
int level = 1000;
|
||||
for ( int i = 0; i < mHeaderInfos.count(); ++i )
|
||||
level = qMin( level, mHeaderInfos[ i ].level );
|
||||
|
||||
for ( int i = 0; i < mHeaderInfos.count(); ++i ) {
|
||||
const HeaderInfo headerInfo = mHeaderInfos[ i ];
|
||||
|
||||
const QRectF rect = mTextDocument->documentLayout()->blockBoundingRect( headerInfo.block );
|
||||
|
||||
int page = qRound( rect.y() ) / qRound( pageSize.height() );
|
||||
int offset = qRound( rect.y() ) % qRound( pageSize.height() );
|
||||
|
||||
Okular::DocumentViewport viewport( page );
|
||||
viewport.rePos.normalizedX = (double)rect.x() / (double)pageSize.width();
|
||||
viewport.rePos.normalizedY = (double)offset / (double)pageSize.height();
|
||||
viewport.rePos.enabled = true;
|
||||
viewport.rePos.pos = Okular::DocumentViewport::Center;
|
||||
|
||||
QDomElement item = tableOfContents.createElement( headerInfo.text );
|
||||
item.setAttribute( "Viewport", viewport.toString() );
|
||||
|
||||
int newLevel = headerInfo.level;
|
||||
if ( newLevel == level ) {
|
||||
parentNode.appendChild( item );
|
||||
} else if ( newLevel > level ) {
|
||||
parentNodeStack.push( parentNode );
|
||||
parentNode = parentNode.lastChildElement();
|
||||
parentNode.appendChild( item );
|
||||
level = newLevel;
|
||||
} else {
|
||||
for ( int i = level; i > newLevel; i-- ) {
|
||||
level--;
|
||||
parentNode = parentNodeStack.pop();
|
||||
}
|
||||
|
||||
parentNode.appendChild( item );
|
||||
}
|
||||
}
|
||||
|
||||
return tableOfContents;
|
||||
}
|
||||
|
||||
void Converter::calculateBoundingRect( int startPosition, int endPosition, QRectF &rect, int &page )
|
||||
{
|
||||
const QSizeF pageSize = mTextDocument->pageSize();
|
||||
|
||||
const QTextBlock startBlock = mTextDocument->findBlock( startPosition );
|
||||
const QRectF startBoundingRect = mTextDocument->documentLayout()->blockBoundingRect( startBlock );
|
||||
|
||||
const QTextBlock endBlock = mTextDocument->findBlock( endPosition );
|
||||
const QRectF endBoundingRect = mTextDocument->documentLayout()->blockBoundingRect( endBlock );
|
||||
|
||||
QTextLayout *startLayout = startBlock.layout();
|
||||
QTextLayout *endLayout = endBlock.layout();
|
||||
|
||||
int startPos = startPosition - startBlock.position();
|
||||
int endPos = endPosition - endBlock.position();
|
||||
const QTextLine startLine = startLayout->lineForTextPosition( startPos );
|
||||
const QTextLine endLine = endLayout->lineForTextPosition( endPos );
|
||||
|
||||
double x = startBoundingRect.x() + startLine.cursorToX( startPos );
|
||||
double y = startBoundingRect.y() + startLine.y();
|
||||
double r = endBoundingRect.x() + endLine.cursorToX( endPos );
|
||||
double b = endBoundingRect.y() + endLine.y() + endLine.height();
|
||||
|
||||
int offset = qRound( y ) % qRound( pageSize.height() );
|
||||
|
||||
page = qRound( y ) / qRound( pageSize.height() );
|
||||
rect = QRectF( x / pageSize.width(), offset / pageSize.height(),
|
||||
(r - x) / pageSize.width(), (b - y) / pageSize.height() );
|
||||
}
|
||||
|
||||
Converter::LinkInfo::List Converter::links()
|
||||
{
|
||||
if ( !mLinkInfosGenerated )
|
||||
createLinkInfos();
|
||||
|
||||
return mLinkInfos;
|
||||
}
|
||||
|
||||
void Converter::createLinkInfos()
|
||||
{
|
||||
for ( int i = 0; i < mLinkPositions.count(); ++i ) {
|
||||
const LinkPosition linkPosition = mLinkPositions[ i ];
|
||||
|
||||
LinkInfo info;
|
||||
info.url = linkPosition.url;
|
||||
|
||||
calculateBoundingRect( linkPosition.startPosition, linkPosition.endPosition,
|
||||
info.boundingRect, info.page );
|
||||
|
||||
mLinkInfos.append( info );
|
||||
}
|
||||
}
|
||||
|
118
generators/fictionbook/converter.h
Normal file
118
generators/fictionbook/converter.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FICTIONBOOK_CONVERTER_H
|
||||
#define FICTIONBOOK_CONVERTER_H
|
||||
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtGui/QTextBlock>
|
||||
#include <QtGui/QTextCharFormat>
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
#include <okular/core/document.h>
|
||||
|
||||
class QDomElement;
|
||||
class QDomText;
|
||||
|
||||
namespace FictionBook {
|
||||
|
||||
class Document;
|
||||
|
||||
class Converter
|
||||
{
|
||||
public:
|
||||
Converter( const Document *document );
|
||||
~Converter();
|
||||
|
||||
bool convert();
|
||||
|
||||
QTextDocument *textDocument() const;
|
||||
|
||||
Okular::DocumentInfo documentInfo() const;
|
||||
Okular::DocumentSynopsis tableOfContents() const;
|
||||
|
||||
class LinkInfo
|
||||
{
|
||||
public:
|
||||
typedef QList<LinkInfo> List;
|
||||
|
||||
int page;
|
||||
QRectF boundingRect;
|
||||
QString url;
|
||||
};
|
||||
|
||||
LinkInfo::List links();
|
||||
|
||||
private:
|
||||
bool convertBody( const QDomElement &element );
|
||||
bool convertDescription( const QDomElement &element );
|
||||
bool convertSection( const QDomElement &element );
|
||||
bool convertTitle( const QDomElement &element );
|
||||
bool convertParagraph( const QDomElement &element );
|
||||
bool convertBinary( const QDomElement &element );
|
||||
bool convertCover( const QDomElement &element );
|
||||
bool convertImage( const QDomElement &element );
|
||||
bool convertEpigraph( const QDomElement &element );
|
||||
bool convertPoem( const QDomElement &element );
|
||||
bool convertSubTitle( const QDomElement &element );
|
||||
bool convertCite( const QDomElement &element );
|
||||
bool convertEmptyLine( const QDomElement &element );
|
||||
bool convertLink( const QDomElement &element );
|
||||
bool convertEmphasis( const QDomElement &element );
|
||||
bool convertStrong( const QDomElement &element );
|
||||
bool convertStyle( const QDomElement &element );
|
||||
|
||||
|
||||
bool convertTitleInfo( const QDomElement &element );
|
||||
bool convertDocumentInfo( const QDomElement &element );
|
||||
bool convertAuthor( const QDomElement &element,
|
||||
QString &firstName, QString &middleName, QString &lastName,
|
||||
QString &email, QString &nickname );
|
||||
bool convertDate( const QDomElement &element, QDate &date );
|
||||
bool convertTextNode( const QDomElement &element, QString &data );
|
||||
|
||||
void calculateBoundingRect( int, int, QRectF&, int& );
|
||||
void createLinkInfos();
|
||||
|
||||
const Document *mDocument;
|
||||
QTextDocument *mTextDocument;
|
||||
QTextCursor *mCursor;
|
||||
|
||||
class TitleInfo;
|
||||
TitleInfo *mTitleInfo;
|
||||
|
||||
class DocumentInfo;
|
||||
DocumentInfo *mDocumentInfo;
|
||||
|
||||
struct HeaderInfo
|
||||
{
|
||||
QTextBlock block;
|
||||
QString text;
|
||||
int level;
|
||||
};
|
||||
QList<HeaderInfo> mHeaderInfos;
|
||||
|
||||
struct LinkPosition
|
||||
{
|
||||
int startPosition;
|
||||
int endPosition;
|
||||
QString url;
|
||||
};
|
||||
|
||||
QList<LinkPosition> mLinkPositions;
|
||||
LinkInfo::List mLinkInfos;
|
||||
|
||||
bool mLinkInfosGenerated;
|
||||
|
||||
int mSectionCounter;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
73
generators/fictionbook/document.cpp
Normal file
73
generators/fictionbook/document.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <kzip.h>
|
||||
|
||||
#include "document.h"
|
||||
|
||||
using namespace FictionBook;
|
||||
|
||||
Document::Document( const QString &fileName )
|
||||
: mFileName( fileName )
|
||||
{
|
||||
}
|
||||
|
||||
bool Document::open()
|
||||
{
|
||||
QIODevice *device;
|
||||
|
||||
QFile file( mFileName );
|
||||
KZip zip( mFileName );
|
||||
if ( mFileName.endsWith( ".fb" ) || mFileName.endsWith( ".fb2" ) ) {
|
||||
if ( !file.open( QIODevice::ReadOnly ) )
|
||||
return false;
|
||||
|
||||
device = &file;
|
||||
} else {
|
||||
if ( !zip.open( QIODevice::ReadOnly ) )
|
||||
return false;
|
||||
|
||||
const KArchiveDirectory *directory = zip.directory();
|
||||
if ( !directory )
|
||||
return false;
|
||||
|
||||
const QStringList entries = directory->entries();
|
||||
|
||||
QString documentFile;
|
||||
for ( int i = 0; i < entries.count(); ++i ) {
|
||||
if ( entries[ i ].endsWith( ".fb2" ) ) {
|
||||
documentFile = entries[ i ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( documentFile.isEmpty() )
|
||||
return false;
|
||||
|
||||
const KArchiveFile *entry = static_cast<const KArchiveFile*>( directory->entry( documentFile ) );
|
||||
device = entry->device();
|
||||
}
|
||||
|
||||
QString errorMsg;
|
||||
int errorRow, errorColumn;
|
||||
|
||||
if ( !mDocument.setContent( device, true, &errorMsg, &errorRow, &errorColumn ) ) {
|
||||
qDebug( "%s at (%d,%d)", qPrintable( errorMsg ), errorRow, errorColumn );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QDomDocument Document::content() const
|
||||
{
|
||||
return mDocument;
|
||||
}
|
36
generators/fictionbook/document.h
Normal file
36
generators/fictionbook/document.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FICTIONBOOK_DOCUMENT_H
|
||||
#define FICTIONBOOK_DOCUMENT_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
namespace FictionBook {
|
||||
|
||||
class Document
|
||||
{
|
||||
public:
|
||||
Document( const QString &fileName );
|
||||
|
||||
bool open();
|
||||
|
||||
QDomDocument content() const;
|
||||
|
||||
private:
|
||||
QString mFileName;
|
||||
QDomDocument mDocument;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
269
generators/fictionbook/generator_fb.cpp
Normal file
269
generators/fictionbook/generator_fb.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtGui/QAbstractTextDocumentLayout>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QTextDocument>
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kprinter.h>
|
||||
|
||||
#include <okular/core/link.h>
|
||||
#include <okular/core/page.h>
|
||||
#include <okular/core/textpage.h>
|
||||
|
||||
#include "converter.h"
|
||||
#include "document.h"
|
||||
#include "generator_fb.h"
|
||||
|
||||
OKULAR_EXPORT_PLUGIN(FictionBookGenerator)
|
||||
|
||||
static void calculateBoundingRect( QTextDocument *document, int startPosition, int endPosition, QRectF &rect, int &page )
|
||||
{
|
||||
const QSizeF pageSize = document->pageSize();
|
||||
|
||||
const QTextBlock startBlock = document->findBlock( startPosition );
|
||||
const QRectF startBoundingRect = document->documentLayout()->blockBoundingRect( startBlock );
|
||||
|
||||
const QTextBlock endBlock = document->findBlock( endPosition );
|
||||
const QRectF endBoundingRect = document->documentLayout()->blockBoundingRect( endBlock );
|
||||
|
||||
QTextLayout *startLayout = startBlock.layout();
|
||||
QTextLayout *endLayout = endBlock.layout();
|
||||
|
||||
int startPos = startPosition - startBlock.position();
|
||||
int endPos = endPosition - endBlock.position();
|
||||
const QTextLine startLine = startLayout->lineForTextPosition( startPos );
|
||||
const QTextLine endLine = endLayout->lineForTextPosition( endPos );
|
||||
|
||||
double x = startBoundingRect.x() + startLine.cursorToX( startPos );
|
||||
double y = startBoundingRect.y() + startLine.y();
|
||||
double r = endBoundingRect.x() + endLine.cursorToX( endPos );
|
||||
double b = endBoundingRect.y() + endLine.y() + endLine.height();
|
||||
|
||||
int offset = qRound( y ) % qRound( pageSize.height() );
|
||||
|
||||
page = qRound( y ) / qRound( pageSize.height() );
|
||||
rect = QRectF( x / pageSize.width(), offset / pageSize.height(),
|
||||
(r - x) / pageSize.width(), (b - y) / pageSize.height() );
|
||||
}
|
||||
|
||||
static void calculatePositions( QTextDocument *document, int page, int &start, int &end )
|
||||
{
|
||||
const QAbstractTextDocumentLayout *layout = document->documentLayout();
|
||||
const QSizeF pageSize = document->pageSize();
|
||||
double margin = document->rootFrame()->frameFormat().margin();
|
||||
|
||||
/**
|
||||
* Take the upper left and lower left corner including the margin
|
||||
*/
|
||||
start = layout->hitTest( QPointF( margin, (page * pageSize.height()) + margin ), Qt::FuzzyHit );
|
||||
end = layout->hitTest( QPointF( margin, ((page + 1) * pageSize.height()) - margin ), Qt::FuzzyHit );
|
||||
}
|
||||
|
||||
FictionBookGenerator::FictionBookGenerator()
|
||||
: Okular::Generator(), mDocument( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
FictionBookGenerator::~FictionBookGenerator()
|
||||
{
|
||||
delete mDocument;
|
||||
mDocument = 0;
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::loadDocument( const QString & fileName, QVector<Okular::Page*> & pagesVector )
|
||||
{
|
||||
FictionBook::Document document( fileName );
|
||||
if ( !document.open() )
|
||||
return false;
|
||||
|
||||
FictionBook::Converter converter( &document );
|
||||
|
||||
if ( !converter.convert() )
|
||||
return false;
|
||||
|
||||
mDocument = converter.textDocument();
|
||||
mDocumentInfo = converter.documentInfo();
|
||||
mDocumentSynopsis = converter.tableOfContents();
|
||||
mLinks = converter.links();
|
||||
|
||||
pagesVector.resize( mDocument->pageCount() );
|
||||
|
||||
const QSize size = mDocument->pageSize().toSize();
|
||||
for ( int i = 0; i < mDocument->pageCount(); ++i ) {
|
||||
Okular::Page * page = new Okular::Page( i, size.width(), size.height(), Okular::Rotation0 );
|
||||
pagesVector[ i ] = page;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::closeDocument()
|
||||
{
|
||||
delete mDocument;
|
||||
mDocument = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::canGeneratePixmap( bool ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void FictionBookGenerator::generatePixmap( Okular::PixmapRequest * request )
|
||||
{
|
||||
const QSize size = mDocument->pageSize().toSize();
|
||||
|
||||
QPixmap *pixmap = new QPixmap( request->width(), request->height() );
|
||||
pixmap->fill( Qt::white );
|
||||
|
||||
QPainter p;
|
||||
p.begin( pixmap );
|
||||
|
||||
qreal width = request->width();
|
||||
qreal height = request->height();
|
||||
|
||||
p.scale( width / (qreal)size.width(), height / (qreal)size.height() );
|
||||
|
||||
QRect rect;
|
||||
rect = QRect( 0, request->pageNumber() * size.height(), size.width(), size.height() );
|
||||
p.translate( QPoint( 0, request->pageNumber() * size.height() * -1 ) );
|
||||
mDocument->drawContents( &p, rect );
|
||||
p.end();
|
||||
|
||||
request->page()->setPixmap( request->id(), pixmap );
|
||||
|
||||
/**
|
||||
* Add link information
|
||||
*/
|
||||
QLinkedList<Okular::ObjectRect*> objects;
|
||||
for ( int i = 0; i < mLinks.count(); ++i ) {
|
||||
if ( mLinks[ i ].page == request->pageNumber() ) {
|
||||
const QRectF rect = mLinks[ i ].boundingRect;
|
||||
objects.append( new Okular::ObjectRect( rect.left(), rect.top(), rect.right(), rect.bottom(), false,
|
||||
Okular::ObjectRect::Link, new Okular::LinkBrowse( mLinks[ i ].url ) ) );
|
||||
}
|
||||
}
|
||||
request->page()->setObjectRects( objects );
|
||||
|
||||
signalRequestDone( request );
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::canGenerateTextPage() const
|
||||
{
|
||||
qDebug( "tokoe: can generate text page called" );
|
||||
return true;
|
||||
}
|
||||
|
||||
void FictionBookGenerator::generateSyncTextPage( Okular::Page * page )
|
||||
{
|
||||
qDebug( "tokoe: generate sync text page called" );
|
||||
page->setTextPage( createTextPage( page->number() ) );
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::print( KPrinter& printer )
|
||||
{
|
||||
QPainter p( &printer );
|
||||
|
||||
const QSize size = mDocument->pageSize().toSize();
|
||||
for ( int i = 0; i < mDocument->pageCount(); ++i ) {
|
||||
if ( i != 0 )
|
||||
printer.newPage();
|
||||
|
||||
QRect rect( 0, i * size.height(), size.width(), size.height() );
|
||||
p.translate( QPoint( 0, i * size.height() * -1 ) );
|
||||
mDocument->drawContents( &p, rect );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Okular::DocumentInfo* FictionBookGenerator::generateDocumentInfo()
|
||||
{
|
||||
return &mDocumentInfo;
|
||||
}
|
||||
|
||||
const Okular::DocumentSynopsis* FictionBookGenerator::generateDocumentSynopsis()
|
||||
{
|
||||
if ( !mDocumentSynopsis.hasChildNodes() )
|
||||
return 0;
|
||||
else
|
||||
return &mDocumentSynopsis;
|
||||
}
|
||||
|
||||
Okular::ExportFormat::List FictionBookGenerator::exportFormats( ) const
|
||||
{
|
||||
static Okular::ExportFormat::List formats;
|
||||
if ( formats.isEmpty() ) {
|
||||
formats.append( Okular::ExportFormat( i18n( "PDF" ), KMimeType::mimeType( "application/pdf" ) ) );
|
||||
formats.append( Okular::ExportFormat( i18n( "Plain Text" ), KMimeType::mimeType( "text/plain" ) ) );
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
bool FictionBookGenerator::exportTo( const QString &fileName, const Okular::ExportFormat &format )
|
||||
{
|
||||
if ( format.mimeType()->name() == QLatin1String( "application/pdf" ) ) {
|
||||
QFile file( fileName );
|
||||
if ( !file.open( QIODevice::WriteOnly ) )
|
||||
return false;
|
||||
|
||||
QPrinter printer( QPrinter::HighResolution );
|
||||
printer.setOutputFormat( QPrinter::PdfFormat );
|
||||
printer.setOutputFileName( fileName );
|
||||
mDocument->print( &printer );
|
||||
|
||||
return true;
|
||||
} else if ( format.mimeType()->name() == QLatin1String( "text/plain" ) ) {
|
||||
QFile file( fileName );
|
||||
if ( !file.open( QIODevice::WriteOnly ) )
|
||||
return false;
|
||||
|
||||
QTextStream out( &file );
|
||||
out << mDocument->toPlainText();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Okular::TextPage* FictionBookGenerator::createTextPage( int pageNumber ) const
|
||||
{
|
||||
Okular::TextPage *textPage = new Okular::TextPage;
|
||||
|
||||
int start, end;
|
||||
|
||||
calculatePositions( mDocument, pageNumber, start, end );
|
||||
|
||||
QTextCursor cursor( mDocument );
|
||||
for ( int i = start; i < end - 1; ++i ) {
|
||||
cursor.setPosition( i );
|
||||
cursor.setPosition( i + 1, QTextCursor::KeepAnchor );
|
||||
|
||||
QString text = cursor.selectedText();
|
||||
if ( text.length() == 1 && text[ 0 ].isPrint() ) {
|
||||
QRectF rect;
|
||||
calculateBoundingRect( mDocument, i, i + 1, rect, pageNumber );
|
||||
|
||||
textPage->append( text, new Okular::NormalizedRect( rect.left(), rect.top(), rect.right(), rect.bottom() ) );
|
||||
}
|
||||
}
|
||||
|
||||
return textPage;
|
||||
}
|
||||
|
||||
#include "generator_fb.moc"
|
||||
|
60
generators/fictionbook/generator_fb.h
Normal file
60
generators/fictionbook/generator_fb.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _OKULAR_GENERATOR_FB_H_
|
||||
#define _OKULAR_GENERATOR_FB_H_
|
||||
|
||||
#include <okular/core/document.h>
|
||||
#include <okular/core/generator.h>
|
||||
|
||||
#include "converter.h"
|
||||
|
||||
class QTextDocument;
|
||||
|
||||
class FictionBookGenerator : public Okular::Generator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FictionBookGenerator();
|
||||
virtual ~FictionBookGenerator();
|
||||
|
||||
// [INHERITED] load a document and fill up the pagesVector
|
||||
bool loadDocument( const QString & fileName, QVector<Okular::Page*> & pagesVector );
|
||||
bool closeDocument();
|
||||
|
||||
// [INHERITED] perform actions on document / pages
|
||||
bool canGeneratePixmap( bool async ) const;
|
||||
void generatePixmap( Okular::PixmapRequest * request );
|
||||
bool canGenerateTextPage() const;
|
||||
void generateSyncTextPage( Okular::Page * page );
|
||||
|
||||
bool supportsSearching() const { return true; };
|
||||
|
||||
// [INHERITED] print document using already configured kprinter
|
||||
bool print( KPrinter& printer );
|
||||
|
||||
// [INHERITED] text exporting
|
||||
Okular::ExportFormat::List exportFormats() const;
|
||||
bool exportTo( const QString &fileName, const Okular::ExportFormat &format );
|
||||
|
||||
const Okular::DocumentInfo* generateDocumentInfo();
|
||||
const Okular::DocumentSynopsis* generateDocumentSynopsis();
|
||||
|
||||
private:
|
||||
Okular::TextPage* createTextPage( int ) const;
|
||||
|
||||
QTextDocument *mDocument;
|
||||
Okular::DocumentInfo mDocumentInfo;
|
||||
Okular::DocumentSynopsis mDocumentSynopsis;
|
||||
|
||||
FictionBook::Converter::LinkInfo::List mLinks;
|
||||
};
|
||||
|
||||
#endif
|
11
generators/fictionbook/libokularGenerator_fb.desktop
Normal file
11
generators/fictionbook/libokularGenerator_fb.desktop
Normal file
|
@ -0,0 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Type=Service
|
||||
Name=FictionBook document
|
||||
Comment=FictionBook backend for okular
|
||||
ServiceTypes=okular/Generator
|
||||
MimeType=application/x-fb
|
||||
X-KDE-Library=libokularGenerator_fb
|
||||
X-KDE-Priority=1
|
||||
X-KDE-okularAPIVersion=1
|
||||
X-KDE-okularHasInternalSettings=false
|
8
generators/fictionbook/okularFb.desktop
Normal file
8
generators/fictionbook/okularFb.desktop
Normal file
|
@ -0,0 +1,8 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Icon=okular
|
||||
Name=okular
|
||||
ServiceTypes=KParts/ReadOnlyPart
|
||||
X-KDE-Library=libokularpart
|
||||
Type=Service
|
||||
MimeType=application/x-fb
|
Loading…
Reference in a new issue