1 /***************************************************************************
2 * Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> *
3 * Copyright (C) 2008 by Albert Astals Cid <aacid@kde.org> *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
11 #include "generator.h"
12 #include "generator_p.h"
14 #include <qeventloop.h>
15 #include <QtGui/QPrinter>
22 #include "document_p.h"
27 using namespace Okular
;
29 GeneratorPrivate::GeneratorPrivate()
31 mPixmapGenerationThread( 0 ), mTextPageGenerationThread( 0 ),
32 m_mutex( 0 ), m_threadsMutex( 0 ), mPixmapReady( true ), mTextPageReady( true ),
33 m_closing( false ), m_closingLoop( 0 )
37 GeneratorPrivate::~GeneratorPrivate()
39 if ( mPixmapGenerationThread
)
40 mPixmapGenerationThread
->wait();
42 delete mPixmapGenerationThread
;
44 if ( mTextPageGenerationThread
)
45 mTextPageGenerationThread
->wait();
47 delete mTextPageGenerationThread
;
50 delete m_threadsMutex
;
53 PixmapGenerationThread
* GeneratorPrivate::pixmapGenerationThread()
55 if ( mPixmapGenerationThread
)
56 return mPixmapGenerationThread
;
59 mPixmapGenerationThread
= new PixmapGenerationThread( q
);
60 QObject::connect( mPixmapGenerationThread
, SIGNAL( finished() ),
61 q
, SLOT( pixmapGenerationFinished() ),
62 Qt::QueuedConnection
);
64 return mPixmapGenerationThread
;
67 TextPageGenerationThread
* GeneratorPrivate::textPageGenerationThread()
69 if ( mTextPageGenerationThread
)
70 return mTextPageGenerationThread
;
73 mTextPageGenerationThread
= new TextPageGenerationThread( q
);
74 QObject::connect( mTextPageGenerationThread
, SIGNAL( finished() ),
75 q
, SLOT( textpageGenerationFinished() ),
76 Qt::QueuedConnection
);
78 return mTextPageGenerationThread
;
81 void GeneratorPrivate::pixmapGenerationFinished()
84 PixmapRequest
*request
= mPixmapGenerationThread
->request();
85 mPixmapGenerationThread
->endGeneration();
87 QMutexLocker
locker( threadsLock() );
96 m_closingLoop
->quit();
101 const QImage
& img
= mPixmapGenerationThread
->image();
102 request
->page()->setPixmap( request
->id(), new QPixmap( QPixmap::fromImage( img
) ) );
103 const int pageNumber
= request
->page()->number();
105 q
->signalPixmapRequestDone( request
);
106 if ( mPixmapGenerationThread
->calcBoundingBox() )
107 q
->updatePageBoundingBox( pageNumber
, mPixmapGenerationThread
->boundingBox() );
110 void GeneratorPrivate::textpageGenerationFinished()
113 Page
*page
= mTextPageGenerationThread
->page();
114 mTextPageGenerationThread
->endGeneration();
116 QMutexLocker
locker( threadsLock() );
117 mTextPageReady
= true;
121 delete mTextPageGenerationThread
->textPage();
125 m_closingLoop
->quit();
130 if ( mTextPageGenerationThread
->textPage() )
132 TextPage
*tp
= mTextPageGenerationThread
->textPage();
133 page
->setTextPage( tp
);
134 q
->signalTextGenerationDone( page
, tp
);
138 QMutex
* GeneratorPrivate::threadsLock()
140 if ( !m_threadsMutex
)
141 m_threadsMutex
= new QMutex();
142 return m_threadsMutex
;
145 QVariant
GeneratorPrivate::metaData( const QString
&, const QVariant
& ) const
150 QImage
GeneratorPrivate::image( PixmapRequest
* )
156 Generator::Generator( QObject
*parent
, const QVariantList
&args
)
157 : QObject( parent
), d_ptr( new GeneratorPrivate() )
163 Generator::Generator( GeneratorPrivate
&dd
, QObject
*parent
, const QVariantList
&args
)
164 : QObject( parent
), d_ptr( &dd
)
170 Generator::~Generator()
175 bool Generator::loadDocumentFromData( const QByteArray
&, QVector
< Page
* > & )
180 bool Generator::closeDocument()
186 d
->threadsLock()->lock();
187 if ( !( d
->mPixmapReady
&& d
->mTextPageReady
) )
190 d
->m_closingLoop
= &loop
;
192 d
->threadsLock()->unlock();
196 d
->m_closingLoop
= 0;
200 d
->threadsLock()->unlock();
203 bool ret
= doCloseDocument();
205 d
->m_closing
= false;
210 bool Generator::canGeneratePixmap() const
212 Q_D( const Generator
);
213 return d
->mPixmapReady
;
216 void Generator::generatePixmap( PixmapRequest
*request
)
219 d
->mPixmapReady
= false;
221 if ( hasFeature( Threaded
) )
223 d
->pixmapGenerationThread()->startGeneration( request
, !request
->page()->isBoundingBoxKnown() );
226 * We create the text page for every page that is visible to the
227 * user, so he can use the text extraction tools without a delay.
229 if ( hasFeature( TextExtraction
) && !request
->page()->hasTextPage() && canGenerateTextPage() ) {
230 d
->mTextPageReady
= false;
231 d
->textPageGenerationThread()->startGeneration( request
->page() );
237 const QImage
& img
= image( request
);
238 request
->page()->setPixmap( request
->id(), new QPixmap( QPixmap::fromImage( img
) ) );
239 const bool bboxKnown
= request
->page()->isBoundingBoxKnown();
240 const int pageNumber
= request
->page()->number();
242 d
->mPixmapReady
= true;
244 signalPixmapRequestDone( request
);
246 updatePageBoundingBox( pageNumber
, Utils::imageBoundingBox( &img
) );
249 bool Generator::canGenerateTextPage() const
251 Q_D( const Generator
);
252 return d
->mTextPageReady
;
255 void Generator::generateTextPage( Page
*page
)
258 TextPage
*tp
= textPage( page
);
259 page
->setTextPage( tp
);
260 d
->mTextPageReady
= true;
261 signalTextGenerationDone( page
, tp
);
264 QImage
Generator::image( PixmapRequest
*request
)
267 return d
->image( request
);
270 TextPage
* Generator::textPage( Page
* )
275 const DocumentInfo
* Generator::generateDocumentInfo()
280 const DocumentSynopsis
* Generator::generateDocumentSynopsis()
285 FontInfo::List
Generator::fontsForPage( int )
287 return FontInfo::List();
290 const QList
<EmbeddedFile
*> * Generator::embeddedFiles() const
295 Generator::PageSizeMetric
Generator::pagesSizeMetric() const
300 bool Generator::isAllowed( Permission
) const
305 void Generator::rotationChanged( Rotation
, Rotation
)
309 PageSize::List
Generator::pageSizes() const
311 return PageSize::List();
314 void Generator::pageSizeChanged( const PageSize
&, const PageSize
& )
318 bool Generator::print( QPrinter
& )
323 QVariant
Generator::metaData( const QString
&key
, const QVariant
&option
) const
325 Q_D( const Generator
);
326 return d
->metaData( key
, option
);
329 ExportFormat::List
Generator::exportFormats() const
331 return ExportFormat::List();
334 bool Generator::exportTo( const QString
&, const ExportFormat
& )
339 bool Generator::hasFeature( GeneratorFeature feature
) const
341 Q_D( const Generator
);
342 return d
->m_features
.contains( feature
);
345 void Generator::signalPixmapRequestDone( PixmapRequest
* request
)
349 d
->m_document
->requestDone( request
);
356 void Generator::signalTextGenerationDone( Page
*page
, TextPage
*textPage
)
360 d
->m_document
->textGenerationDone( page
);
365 const Document
* Generator::document() const
367 Q_D( const Generator
);
370 return d
->m_document
->m_parent
;
375 void Generator::setFeature( GeneratorFeature feature
, bool on
)
379 d
->m_features
.insert( feature
);
381 d
->m_features
.remove( feature
);
384 QVariant
Generator::documentMetaData( const QString
&key
, const QVariant
&option
) const
386 Q_D( const Generator
);
387 if ( !d
->m_document
)
390 return d
->m_document
->documentMetaData( key
, option
);
393 QMutex
* Generator::userMutex() const
395 Q_D( const Generator
);
398 d
->m_mutex
= new QMutex();
403 void Generator::updatePageBoundingBox( int page
, const NormalizedRect
& boundingBox
)
406 if ( d
->m_document
) // still connected to document?
407 d
->m_document
->setPageBoundingBox( page
, boundingBox
);
410 void Generator::requestFontData(const Okular::FontInfo
& /*font*/, QByteArray
* /*data*/)
415 PixmapRequest::PixmapRequest( int id
, int pageNumber
, int width
, int height
, int priority
, bool asynchronous
)
416 : d( new PixmapRequestPrivate
)
419 d
->mPageNumber
= pageNumber
;
422 d
->mPriority
= priority
;
423 d
->mAsynchronous
= asynchronous
;
427 PixmapRequest::~PixmapRequest()
432 int PixmapRequest::id() const
437 int PixmapRequest::pageNumber() const
439 return d
->mPageNumber
;
442 int PixmapRequest::width() const
447 int PixmapRequest::height() const
452 int PixmapRequest::priority() const
457 bool PixmapRequest::asynchronous() const
459 return d
->mAsynchronous
;
462 Page
* PixmapRequest::page() const
467 void PixmapRequestPrivate::swap()
469 qSwap( mWidth
, mHeight
);
472 class Okular::ExportFormatPrivate
: public QSharedData
475 ExportFormatPrivate( const QString
&description
, const KMimeType::Ptr
&mimeType
, const KIcon
&icon
= KIcon() )
476 : QSharedData(), mDescription( description
), mMimeType( mimeType
), mIcon( icon
)
479 ~ExportFormatPrivate()
483 QString mDescription
;
484 KMimeType::Ptr mMimeType
;
488 ExportFormat::ExportFormat()
489 : d( new ExportFormatPrivate( QString(), KMimeType::Ptr() ) )
493 ExportFormat::ExportFormat( const QString
&description
, const KMimeType::Ptr
&mimeType
)
494 : d( new ExportFormatPrivate( description
, mimeType
) )
498 ExportFormat::ExportFormat( const KIcon
&icon
, const QString
&description
, const KMimeType::Ptr
&mimeType
)
499 : d( new ExportFormatPrivate( description
, mimeType
, icon
) )
503 ExportFormat::~ExportFormat()
507 ExportFormat::ExportFormat( const ExportFormat
&other
)
512 ExportFormat
& ExportFormat::operator=( const ExportFormat
&other
)
514 if ( this == &other
)
522 QString
ExportFormat::description() const
524 return d
->mDescription
;
527 KMimeType::Ptr
ExportFormat::mimeType() const
532 KIcon
ExportFormat::icon() const
537 bool ExportFormat::isNull() const
539 return d
->mMimeType
.isNull() || d
->mDescription
.isNull();
542 ExportFormat
ExportFormat::standardFormat( StandardExportFormat type
)
547 return ExportFormat( KIcon( "text-x-generic" ), i18n( "Plain &Text..." ), KMimeType::mimeType( "text/plain" ) );
550 return ExportFormat( KIcon( "application-pdf" ), i18n( "PDF" ), KMimeType::mimeType( "application/pdf" ) );
552 case OpenDocumentText
:
554 KIcon( "application-vnd.oasis.opendocument.text" ),
555 i18nc( "This is the document format", "OpenDocument Text" ),
556 KMimeType::mimeType( "application/vnd.oasis.opendocument.text" ) );
559 return ExportFormat( KIcon( "text-html" ), i18nc( "This is the document format", "HTML" ), KMimeType::mimeType( "text/html" ) );
562 return ExportFormat();
565 bool ExportFormat::operator==( const ExportFormat
&other
) const
570 bool ExportFormat::operator!=( const ExportFormat
&other
) const
575 QDebug
operator<<( QDebug str
, const Okular::PixmapRequest
&req
)
577 QString s
= QString( "%1 PixmapRequest (id: %2) (%3x%4), prio %5, pageNo %6" )
578 .arg( QString( req
.asynchronous() ? "Async" : "Sync" ) )
582 .arg( req
.priority() )
583 .arg( req
.pageNumber() );
584 str
<< qPrintable( s
);
588 #include "generator.moc"