00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "generator.h"
00011 #include "generator_p.h"
00012
00013 #include <qeventloop.h>
00014 #include <QtGui/QPrinter>
00015
00016 #include <kdebug.h>
00017 #include <kicon.h>
00018 #include <klocale.h>
00019
00020 #include "document.h"
00021 #include "document_p.h"
00022 #include "page.h"
00023 #include "textpage.h"
00024
00025 using namespace Okular;
00026
00027 GeneratorPrivate::GeneratorPrivate()
00028 : m_document( 0 ),
00029 mPixmapGenerationThread( 0 ), mTextPageGenerationThread( 0 ),
00030 m_mutex( 0 ), m_threadsMutex( 0 ), mPixmapReady( true ), mTextPageReady( true ),
00031 m_closing( false ), m_closingLoop( 0 )
00032 {
00033 }
00034
00035 GeneratorPrivate::~GeneratorPrivate()
00036 {
00037 if ( mPixmapGenerationThread )
00038 mPixmapGenerationThread->wait();
00039
00040 delete mPixmapGenerationThread;
00041
00042 if ( mTextPageGenerationThread )
00043 mTextPageGenerationThread->wait();
00044
00045 delete mTextPageGenerationThread;
00046
00047 delete m_mutex;
00048 delete m_threadsMutex;
00049 }
00050
00051 PixmapGenerationThread* GeneratorPrivate::pixmapGenerationThread()
00052 {
00053 if ( mPixmapGenerationThread )
00054 return mPixmapGenerationThread;
00055
00056 Q_Q( Generator );
00057 mPixmapGenerationThread = new PixmapGenerationThread( q );
00058 QObject::connect( mPixmapGenerationThread, SIGNAL( finished() ),
00059 q, SLOT( pixmapGenerationFinished() ),
00060 Qt::QueuedConnection );
00061
00062 return mPixmapGenerationThread;
00063 }
00064
00065 TextPageGenerationThread* GeneratorPrivate::textPageGenerationThread()
00066 {
00067 if ( mTextPageGenerationThread )
00068 return mTextPageGenerationThread;
00069
00070 Q_Q( Generator );
00071 mTextPageGenerationThread = new TextPageGenerationThread( q );
00072 QObject::connect( mTextPageGenerationThread, SIGNAL( finished() ),
00073 q, SLOT( textpageGenerationFinished() ),
00074 Qt::QueuedConnection );
00075
00076 return mTextPageGenerationThread;
00077 }
00078
00079 void GeneratorPrivate::pixmapGenerationFinished()
00080 {
00081 Q_Q( Generator );
00082 PixmapRequest *request = mPixmapGenerationThread->request();
00083 mPixmapGenerationThread->endGeneration();
00084
00085 QMutexLocker locker( threadsLock() );
00086 mPixmapReady = true;
00087
00088 if ( m_closing )
00089 {
00090 delete request;
00091 if ( mTextPageReady )
00092 {
00093 locker.unlock();
00094 m_closingLoop->quit();
00095 }
00096 return;
00097 }
00098
00099 request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( mPixmapGenerationThread->image() ) ) );
00100
00101 q->signalPixmapRequestDone( request );
00102 }
00103
00104 void GeneratorPrivate::textpageGenerationFinished()
00105 {
00106 Page *page = mTextPageGenerationThread->page();
00107 mTextPageGenerationThread->endGeneration();
00108
00109 QMutexLocker locker( threadsLock() );
00110 mTextPageReady = true;
00111
00112 if ( m_closing )
00113 {
00114 delete mTextPageGenerationThread->textPage();
00115 if ( mPixmapReady )
00116 {
00117 locker.unlock();
00118 m_closingLoop->quit();
00119 }
00120 return;
00121 }
00122
00123 if ( mTextPageGenerationThread->textPage() )
00124 page->setTextPage( mTextPageGenerationThread->textPage() );
00125 }
00126
00127 QMutex* GeneratorPrivate::threadsLock()
00128 {
00129 if ( !m_threadsMutex )
00130 m_threadsMutex = new QMutex();
00131 return m_threadsMutex;
00132 }
00133
00134
00135 Generator::Generator( QObject *parent, const QVariantList &args )
00136 : QObject( parent ), d_ptr( new GeneratorPrivate() )
00137 {
00138 d_ptr->q_ptr = this;
00139 Q_UNUSED( args )
00140 }
00141
00142 Generator::Generator( GeneratorPrivate &dd, QObject *parent, const QVariantList &args )
00143 : QObject( parent ), d_ptr( &dd )
00144 {
00145 d_ptr->q_ptr = this;
00146 Q_UNUSED( args )
00147 }
00148
00149 Generator::~Generator()
00150 {
00151 delete d_ptr;
00152 }
00153
00154 bool Generator::loadDocumentFromData( const QByteArray &, QVector< Page * > & )
00155 {
00156 return false;
00157 }
00158
00159 bool Generator::closeDocument()
00160 {
00161 Q_D( Generator );
00162
00163 d->m_closing = true;
00164
00165 d->threadsLock()->lock();
00166 if ( !( d->mPixmapReady && d->mTextPageReady ) )
00167 {
00168 QEventLoop loop;
00169 d->m_closingLoop = &loop;
00170
00171 d->threadsLock()->unlock();
00172
00173 loop.exec();
00174
00175 d->m_closingLoop = 0;
00176 }
00177 else
00178 {
00179 d->threadsLock()->unlock();
00180 }
00181
00182 bool ret = doCloseDocument();
00183
00184 d->m_closing = false;
00185
00186 return ret;
00187 }
00188
00189 bool Generator::canGeneratePixmap() const
00190 {
00191 Q_D( const Generator );
00192 return d->mPixmapReady;
00193 }
00194
00195 void Generator::generatePixmap( PixmapRequest *request )
00196 {
00197 Q_D( Generator );
00198 d->mPixmapReady = false;
00199
00200 if ( hasFeature( Threaded ) )
00201 {
00202 d->pixmapGenerationThread()->startGeneration( request );
00203
00208 if ( hasFeature( TextExtraction ) && !request->page()->hasTextPage() && canGenerateTextPage() ) {
00209 d->mTextPageReady = false;
00210 d->textPageGenerationThread()->startGeneration( request->page() );
00211 }
00212
00213 return;
00214 }
00215
00216 request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( image( request ) ) ) );
00217
00218 d->mPixmapReady = true;
00219
00220 signalPixmapRequestDone( request );
00221 }
00222
00223 bool Generator::canGenerateTextPage() const
00224 {
00225 Q_D( const Generator );
00226 return d->mTextPageReady;
00227 }
00228
00229 void Generator::generateTextPage( Page *page )
00230 {
00231 Q_D( Generator );
00232 page->setTextPage( textPage( page ) );
00233 d->mTextPageReady = true;
00234 }
00235
00236 QImage Generator::image( PixmapRequest * )
00237 {
00238 return QImage();
00239 }
00240
00241 TextPage* Generator::textPage( Page* )
00242 {
00243 return 0;
00244 }
00245
00246 const DocumentInfo * Generator::generateDocumentInfo()
00247 {
00248 return 0;
00249 }
00250
00251 const DocumentSynopsis * Generator::generateDocumentSynopsis()
00252 {
00253 return 0;
00254 }
00255
00256 FontInfo::List Generator::fontsForPage( int )
00257 {
00258 return FontInfo::List();
00259 }
00260
00261 const QList<EmbeddedFile*> * Generator::embeddedFiles() const
00262 {
00263 return 0;
00264 }
00265
00266 Generator::PageSizeMetric Generator::pagesSizeMetric() const
00267 {
00268 return None;
00269 }
00270
00271 bool Generator::isAllowed( Permission ) const
00272 {
00273 return true;
00274 }
00275
00276 void Generator::rotationChanged( Rotation, Rotation )
00277 {
00278 }
00279
00280 PageSize::List Generator::pageSizes() const
00281 {
00282 return PageSize::List();
00283 }
00284
00285 void Generator::pageSizeChanged( const PageSize &, const PageSize & )
00286 {
00287 }
00288
00289 bool Generator::print( QPrinter& )
00290 {
00291 return false;
00292 }
00293
00294 QVariant Generator::metaData( const QString&, const QVariant& ) const
00295 {
00296 return QVariant();
00297 }
00298
00299 ExportFormat::List Generator::exportFormats() const
00300 {
00301 return ExportFormat::List();
00302 }
00303
00304 bool Generator::exportTo( const QString&, const ExportFormat& )
00305 {
00306 return false;
00307 }
00308
00309 bool Generator::hasFeature( GeneratorFeature feature ) const
00310 {
00311 Q_D( const Generator );
00312 return d->m_features.contains( feature );
00313 }
00314
00315 void Generator::signalPixmapRequestDone( PixmapRequest * request )
00316 {
00317 Q_D( Generator );
00318 if ( d->m_document )
00319 d->m_document->requestDone( request );
00320 else
00321 {
00322 delete request;
00323 }
00324 }
00325
00326 const Document * Generator::document() const
00327 {
00328 Q_D( const Generator );
00329 return d->m_document->m_parent;
00330 }
00331
00332 void Generator::setFeature( GeneratorFeature feature, bool on )
00333 {
00334 Q_D( Generator );
00335 if ( on )
00336 d->m_features.insert( feature );
00337 else
00338 d->m_features.remove( feature );
00339 }
00340
00341 QVariant Generator::documentMetaData( const QString &key, const QVariant &option ) const
00342 {
00343 Q_D( const Generator );
00344 if ( !d->m_document )
00345 return QVariant();
00346
00347 return d->m_document->documentMetaData( key, option );
00348 }
00349
00350 QMutex* Generator::userMutex() const
00351 {
00352 Q_D( const Generator );
00353 if ( !d->m_mutex )
00354 {
00355 d->m_mutex = new QMutex();
00356 }
00357 return d->m_mutex;
00358 }
00359
00360
00361 PixmapRequest::PixmapRequest( int id, int pageNumber, int width, int height, int priority, bool asynchronous )
00362 : d( new PixmapRequestPrivate )
00363 {
00364 d->mId = id;
00365 d->mPageNumber = pageNumber;
00366 d->mWidth = width;
00367 d->mHeight = height;
00368 d->mPriority = priority;
00369 d->mAsynchronous = asynchronous;
00370 }
00371
00372 PixmapRequest::~PixmapRequest()
00373 {
00374 delete d;
00375 }
00376
00377 int PixmapRequest::id() const
00378 {
00379 return d->mId;
00380 }
00381
00382 int PixmapRequest::pageNumber() const
00383 {
00384 return d->mPageNumber;
00385 }
00386
00387 int PixmapRequest::width() const
00388 {
00389 return d->mWidth;
00390 }
00391
00392 int PixmapRequest::height() const
00393 {
00394 return d->mHeight;
00395 }
00396
00397 int PixmapRequest::priority() const
00398 {
00399 return d->mPriority;
00400 }
00401
00402 bool PixmapRequest::asynchronous() const
00403 {
00404 return d->mAsynchronous;
00405 }
00406
00407 Page* PixmapRequest::page() const
00408 {
00409 return d->mPage;
00410 }
00411
00412 void PixmapRequestPrivate::swap()
00413 {
00414 qSwap( mWidth, mHeight );
00415 }
00416
00417 class Okular::ExportFormatPrivate : public QSharedData
00418 {
00419 public:
00420 ExportFormatPrivate( const QString &description, const KMimeType::Ptr &mimeType, const KIcon &icon = KIcon() )
00421 : QSharedData(), mDescription( description ), mMimeType( mimeType ), mIcon( icon )
00422 {
00423 }
00424 ~ExportFormatPrivate()
00425 {
00426 }
00427
00428 QString mDescription;
00429 KMimeType::Ptr mMimeType;
00430 KIcon mIcon;
00431 };
00432
00433 ExportFormat::ExportFormat()
00434 : d( new ExportFormatPrivate( QString(), KMimeType::Ptr() ) )
00435 {
00436 }
00437
00438 ExportFormat::ExportFormat( const QString &description, const KMimeType::Ptr &mimeType )
00439 : d( new ExportFormatPrivate( description, mimeType ) )
00440 {
00441 }
00442
00443 ExportFormat::ExportFormat( const KIcon &icon, const QString &description, const KMimeType::Ptr &mimeType )
00444 : d( new ExportFormatPrivate( description, mimeType, icon ) )
00445 {
00446 }
00447
00448 ExportFormat::~ExportFormat()
00449 {
00450 }
00451
00452 ExportFormat::ExportFormat( const ExportFormat &other )
00453 : d( other.d )
00454 {
00455 }
00456
00457 ExportFormat& ExportFormat::operator=( const ExportFormat &other )
00458 {
00459 if ( this == &other )
00460 return *this;
00461
00462 d = other.d;
00463
00464 return *this;
00465 }
00466
00467 QString ExportFormat::description() const
00468 {
00469 return d->mDescription;
00470 }
00471
00472 KMimeType::Ptr ExportFormat::mimeType() const
00473 {
00474 return d->mMimeType;
00475 }
00476
00477 KIcon ExportFormat::icon() const
00478 {
00479 return d->mIcon;
00480 }
00481
00482 bool ExportFormat::isNull() const
00483 {
00484 return d->mMimeType.isNull() || d->mDescription.isNull();
00485 }
00486
00487 ExportFormat ExportFormat::standardFormat( StandardExportFormat type )
00488 {
00489 switch ( type )
00490 {
00491 case PlainText:
00492 return ExportFormat( KIcon( "text-x-generic" ), i18n( "Plain &Text..." ), KMimeType::mimeType( "text/plain" ) );
00493 break;
00494 case PDF:
00495 return ExportFormat( KIcon( "application-pdf" ), i18n( "PDF" ), KMimeType::mimeType( "application/pdf" ) );
00496 break;
00497 }
00498 return ExportFormat();
00499 }
00500
00501 bool ExportFormat::operator==( const ExportFormat &other ) const
00502 {
00503 return d == other.d;
00504 }
00505
00506 bool ExportFormat::operator!=( const ExportFormat &other ) const
00507 {
00508 return d != other.d;
00509 }
00510
00511 QDebug operator<<( QDebug str, const Okular::PixmapRequest &req )
00512 {
00513 QString s = QString( "%1 PixmapRequest (id: %2) (%3x%4), prio %5, pageNo %6" )
00514 .arg( QString( req.asynchronous() ? "Async" : "Sync" ) )
00515 .arg( req.id() )
00516 .arg( req.width() )
00517 .arg( req.height() )
00518 .arg( req.priority() )
00519 .arg( req.pageNumber() );
00520 str << qPrintable( s );
00521 return str;
00522 }
00523
00524 #include "generator.moc"