Commit d22b2f18 authored by Tobias Koenig's avatar Tobias Koenig

A rather big change:

 * Hide as much private API as possible in Generator, PixmapRequest and ExportEntry/Format
 * Renamed ExportEntry to ExportFormat and made it value based
 * Removed canExportToText() and exportToText() from Generator API and implemented this
   functionality in exportFormats()/exportTo() in the generators
 * Removed the orientation parameter from PixmapRequest and let the Document handle the rotation
   of the page (pixmap) instead

CCMAIL:okular-devel@kde.org

svn path=/trunk/playground/graphics/okular/; revision=599058
parent 46a1ddc0
......@@ -595,22 +595,40 @@ QStringList Document::paperSizes() const
bool Document::canExportToText() const
{
return generator ? generator->canExportToText() : false;
if ( !generator )
return false;
const ExportFormat::List formats = generator->exportFormats();
for ( int i = 0; i < formats.count(); ++i ) {
if ( formats[ i ].mimeType()->name() == QLatin1String( "text/plain" ) )
return true;
}
return false;
}
bool Document::exportToText( const QString& fileName ) const
{
return generator ? generator->exportToText( fileName ) : false;
if ( !generator )
return false;
const ExportFormat::List formats = generator->exportFormats();
for ( int i = 0; i < formats.count(); ++i ) {
if ( formats[ i ].mimeType()->name() == QLatin1String( "text/plain" ) )
return generator->exportTo( fileName, formats[ i ] );
}
return false;
}
QList<ExportEntry*> Document::exportFormats() const
ExportFormat::List Document::exportFormats() const
{
return generator ? generator->exportFormats() : QList<ExportEntry*>();
return generator ? generator->exportFormats() : ExportFormat::List();
}
bool Document::exportTo( const QString& fileName, const KMimeType::Ptr& mime ) const
bool Document::exportTo( const QString& fileName, const ExportFormat& format ) const
{
return generator ? generator->exportTo( fileName, mime ) : false;
return generator ? generator->exportTo( fileName, format ) : false;
}
bool Document::historyAtBegin() const
......@@ -676,11 +694,11 @@ void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests )
}
// 1. [CLEAN STACK] remove previous requests of requesterID
int requesterID = requests.first()->id;
int requesterID = requests.first()->id();
QLinkedList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end();
while ( sIt != sEnd )
{
if ( (*sIt)->id == requesterID )
if ( (*sIt)->id() == requesterID )
{
// delete request and remove it from stack
delete *sIt;
......@@ -697,24 +715,24 @@ void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests )
{
// set the 'page field' (see PixmapRequest) and check if it is valid
PixmapRequest * request = *rIt;
kWarning() << "request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << endl;
if ( !(request->page = pages_vector[ request->pageNumber ]) )
kWarning() << "request id=" << request->id() << " " <<request->width() << "x" << request->height() << "@" << request->pageNumber() << endl;
if ( pages_vector.value( request->pageNumber() ) == 0 )
{
// skip requests referencing an invalid page (must not happen)
delete request;
continue;
}
};
request->documentRotation = d->rotation;
request->setPage( pages_vector.value( request->pageNumber() ) );
if ( !request->async )
request->priority = 0;
if ( !request->asynchronous() )
request->setPriority( 0 );
if ( request->async && threadingDisabled )
request->async = false;
if ( request->asynchronous() && threadingDisabled )
request->setAsynchronous( false );
// add request to the 'stack' at the right place
if ( !request->priority )
if ( !request->priority() )
// add priority zero requests to the top of the stack
d->pixmapRequestsStack.append( request );
else
......@@ -722,7 +740,7 @@ void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests )
// insert in stack sorted by priority
sIt = d->pixmapRequestsStack.begin();
sEnd = d->pixmapRequestsStack.end();
while ( sIt != sEnd && (*sIt)->priority >= request->priority )
while ( sIt != sEnd && (*sIt)->priority() >= request->priority() )
++sIt;
d->pixmapRequestsStack.insert( sIt, request );
}
......@@ -1398,7 +1416,7 @@ bool Document::print( KPrinter &printer )
void Document::requestDone( PixmapRequest * req )
{
#ifndef NDEBUG
if ( !generator->canGeneratePixmap( req->async ) )
if ( !generator->canGeneratePixmap( req->asynchronous() ) )
kDebug() << "requestDone with generator not in READY state." << endl;
#endif
......@@ -1406,7 +1424,7 @@ void Document::requestDone( PixmapRequest * req )
QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
for ( ; aIt != aEnd; ++aIt )
if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id )
if ( (*aIt)->page == req->pageNumber() && (*aIt)->id == req->id() )
{
AllocatedPixmap * p = *aIt;
d->allocatedPixmapsFifo.erase( aIt );
......@@ -1416,14 +1434,14 @@ void Document::requestDone( PixmapRequest * req )
}
// [MEM] 1.2 append memory allocation descriptor to the FIFO
int memoryBytes = 4 * req->width * req->height;
AllocatedPixmap * memoryPage = new AllocatedPixmap( req->id, req->pageNumber, memoryBytes );
int memoryBytes = 4 * req->width() * req->height();
AllocatedPixmap * memoryPage = new AllocatedPixmap( req->id(), req->pageNumber(), memoryBytes );
d->allocatedPixmapsFifo.append( memoryPage );
d->allocatedPixmapsTotalMemory += memoryBytes;
// 2. notify an observer that its pixmap changed
if ( d->observers.contains( req->id ) )
d->observers[ req->id ]->notifyPageChanged( req->pageNumber, DocumentObserver::Pixmap );
if ( d->observers.contains( req->id() ) )
d->observers[ req->id() ]->notifyPageChanged( req->pageNumber(), DocumentObserver::Pixmap );
// 3. delete request
delete req;
......@@ -1445,22 +1463,22 @@ void Document::sendGeneratorRequest()
d->pixmapRequestsStack.pop_back();
}
// request only if page isn't already present or request has invalid id
else if ( r->page->hasPixmap( r->id, r->width, r->height ) || r->id <= 0 || r->id >= MAX_OBSERVER_ID)
else if ( r->page()->hasPixmap( r->id(), r->width(), r->height() ) || r->id() <= 0 || r->id() >= MAX_OBSERVER_ID)
{
d->pixmapRequestsStack.pop_back();
delete r;
}
else if ( (long)r->width * (long)r->height > 20000000L )
else if ( (long)r->width() * (long)r->height() > 20000000L )
{
d->pixmapRequestsStack.pop_back();
if ( !d->warnedOutOfMemory )
{
kWarning() << "Running out of memory on page " << r->pageNumber
<< " (" << r->width << "x" << r->height << " px);" << endl;
kWarning() << "Running out of memory on page " << r->pageNumber()
<< " (" << r->width() << "x" << r->height() << " px);" << endl;
kWarning() << "this message will be reported only once." << endl;
d->warnedOutOfMemory = true;
}
delete r;
delete r;
}
else
request = r;
......@@ -1471,14 +1489,14 @@ void Document::sendGeneratorRequest()
return;
// [MEM] preventive memory freeing
int pixmapBytes = 4 * request->width * request->height;
int pixmapBytes = 4 * request->width() * request->height();
if ( pixmapBytes > (1024 * 1024) )
cleanupPixmapMemory( pixmapBytes );
// submit the request to the generator
if ( generator->canGeneratePixmap( request->async ) )
if ( generator->canGeneratePixmap( request->asynchronous() ) )
{
kWarning() << "sending request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << " async == " << request->async << endl;
kWarning() << "sending request id=" << request->id() << " " <<request->width() << "x" << request->height() << "@" << request->pageNumber() << " async == " << request->asynchronous() << endl;
d->pixmapRequestsStack.removeAll ( request );
generator->generatePixmap ( request );
}
......@@ -1817,6 +1835,28 @@ void Document::slotTimedMemoryCheck()
void Document::slotRotation( int rotation )
{
// tell the pages to rotate
QVector< Okular::Page * >::iterator pIt = pages_vector.begin();
QVector< Okular::Page * >::iterator pEnd = pages_vector.end();
for ( ; pIt != pEnd; ++pIt )
(*pIt)->rotateAt( rotation );
// clear 'memory allocation' descriptors
QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
for ( ; aIt != aEnd; ++aIt )
delete *aIt;
d->allocatedPixmapsFifo.clear();
d->allocatedPixmapsTotalMemory = 0;
// notify the generator that the current rotation has changed
generator->rotationChanged( rotation, d->rotation );
// set the new rotation
d->rotation = rotation;
foreachObserver( notifySetup( pages_vector, true ) );
foreachObserver( notifyContentsCleared (DocumentObserver::Pixmap | DocumentObserver::Highlights | DocumentObserver::Annotations));
kDebug() << "Rotated: " << rotation << endl;
/*
if ( generator->supportsRotation() )
{
// tell the pages to rotate
......@@ -1838,10 +1878,11 @@ void Document::slotRotation( int rotation )
foreachObserver( notifySetup( pages_vector, true ) );
foreachObserver( notifyContentsCleared (DocumentObserver::Pixmap | DocumentObserver::Highlights | DocumentObserver::Annotations));
// foreachObserver( notifyViewportChanged( false /*disables smoothMove*/ ));
// foreachObserver( notifyViewportChanged( false ));
// foreachObserver( notifyPageChanged( ) );
kDebug() << "Rotated: " << rotation << endl;
}
*/
}
void Document::slotPaperSizes( int newsize )
......
......@@ -38,7 +38,7 @@ class DocumentObserver;
class DocumentSynopsis;
class DocumentViewport;
class EmbeddedFile;
class ExportEntry;
class ExportFormat;
class Generator;
class Link;
class NotifyRequest;
......@@ -111,8 +111,8 @@ class OKULAR_EXPORT Document : public QObject
QStringList paperSizes() const;
bool canExportToText() const;
bool exportToText( const QString& fileName ) const;
QList<ExportEntry*> exportFormats() const;
bool exportTo( const QString& fileName, const KMimeType::Ptr& mime ) const;
QList<ExportFormat> exportFormats() const;
bool exportTo( const QString& fileName, const ExportFormat& format ) const;
bool historyAtBegin() const;
bool historyAtEnd() const;
QString getMetaData( const QString & key, const QString & option = QString() ) const;
......
......@@ -8,18 +8,31 @@
***************************************************************************/
#include <kdebug.h>
#include <kicon.h>
#include "generator.h"
using namespace Okular;
class Generator::Private
{
public:
Private()
: m_document( 0 )
{
}
Document * m_document;
};
Generator::Generator()
: m_document( 0 )
: d( new Private )
{
}
Generator::~Generator()
{
delete d;
}
bool Generator::canGenerateTextPage() const
......@@ -126,56 +139,191 @@ void Generator::addPages( KConfigDialog* )
{
}
bool Generator::canExportToText() const
ExportFormat::List Generator::exportFormats() const
{
return false;
return ExportFormat::List();
}
bool Generator::exportToText( const QString& )
bool Generator::exportTo( const QString&, const ExportFormat& )
{
return false;
}
QList<ExportEntry*> Generator::exportFormats() const
bool Generator::handleEvent( QEvent* )
{
return QList<ExportEntry*>();
return true;
}
bool Generator::exportTo( const QString&, const KMimeType::Ptr& )
void Generator::setDocument( Document *document )
{
return false;
d->m_document = document;
}
bool Generator::handleEvent( QEvent* )
void Generator::signalRequestDone( PixmapRequest * request )
{
return true;
if ( d->m_document )
d->m_document->requestDone( request );
else
Q_ASSERT( !"No document set for generator in signalRequestDone!" );
}
void Generator::setDocument( Document *document )
Document * Generator::document() const
{
m_document = document;
return d->m_document;
}
void Generator::signalRequestDone( PixmapRequest * request )
class PixmapRequest::Private
{
public:
int mId;
int mPageNumber;
int mWidth;
int mHeight;
int mPriority;
bool mAsynchronous;
Page *mPage;
};
PixmapRequest::PixmapRequest( int id, int pageNumber, int width, int height, int priority, bool asynchronous )
: d( new Private )
{
m_document->requestDone( request );
d->mId = id;
d->mPageNumber = pageNumber;
d->mWidth = width;
d->mHeight = height;
d->mPriority = priority;
d->mAsynchronous = asynchronous;
}
Document * Generator::document() const
PixmapRequest::~PixmapRequest()
{
delete d;
}
int PixmapRequest::id() const
{
return d->mId;
}
int PixmapRequest::pageNumber() const
{
return d->mPageNumber;
}
int PixmapRequest::width() const
{
return d->mWidth;
}
int PixmapRequest::height() const
{
return m_document;
return d->mHeight;
}
int PixmapRequest::priority() const
{
return d->mPriority;
}
bool PixmapRequest::asynchronous() const
{
return d->mAsynchronous;
}
Page* PixmapRequest::page() const
{
return d->mPage;
}
void PixmapRequest::setPriority( int priority )
{
d->mPriority = priority;
}
void PixmapRequest::setAsynchronous( bool asynchronous )
{
d->mAsynchronous = asynchronous;
}
void PixmapRequest::setPage( Page *page )
{
d->mPage = page;
}
class ExportFormat::Private
{
public:
Private( const QString &description, const KMimeType::Ptr &mimeType, const KIcon &icon = KIcon() )
: mDescription( description ), mMimeType( mimeType ), mIcon( icon )
{
}
QString mDescription;
KMimeType::Ptr mMimeType;
KIcon mIcon;
};
ExportFormat::ExportFormat()
: d( new Private( QString(), KMimeType::Ptr() ) )
{
}
ExportFormat::ExportFormat( const QString &description, const KMimeType::Ptr &mimeType )
: d( new Private( description, mimeType ) )
{
}
ExportFormat::ExportFormat( const KIcon &icon, const QString &description, const KMimeType::Ptr &mimeType )
: d( new Private( description, mimeType, icon ) )
{
}
ExportFormat::~ExportFormat()
{
delete d;
}
ExportFormat::ExportFormat( const ExportFormat &other )
: d( new Private( QString(), KMimeType::Ptr() ) )
{
*d = *other.d;
}
ExportFormat& ExportFormat::operator=( const ExportFormat &other )
{
if ( this == &other )
return *this;
*d = *other.d;
return *this;
}
QString ExportFormat::description() const
{
return d->mDescription;
}
KMimeType::Ptr ExportFormat::mimeType() const
{
return d->mMimeType;
}
KIcon ExportFormat::icon() const
{
return d->mIcon;
}
kdbgstream& operator<<( kdbgstream &str, const Okular::PixmapRequest &req )
{
QString s = QString( "%1 PixmapRequest (id: %2) (%3x%4), prio %5, pageNo %6" )
.arg( QString( req.async ? "Async" : "Sync" ) )
.arg( req.id )
.arg( req.width )
.arg( req.height )
.arg( req.priority )
.arg( req.pageNumber );
.arg( QString( req.asynchronous() ? "Async" : "Sync" ) )
.arg( req.id() )
.arg( req.width() )
.arg( req.height() )
.arg( req.priority() )
.arg( req.pageNumber() );
str << s;
return str;
}
......
......@@ -29,12 +29,12 @@
#include "document.h"
class KConfigDialog;
class KIcon;
class KPrinter;
class kdbgstream;
namespace Okular {
class ExportEntry;
class Link;
class Page;
class PixmapRequest;
......@@ -50,6 +50,68 @@ class TextPage;
* (even for sync or async queries) has been done.
*/
/**
* @short Defines an entry for the export menu
*
* This class encapsulates information about an export format.
* Every Generator can support 0 ore more export formats which can be
* queried with @see Generator::exportFormats().
*/
class OKULAR_EXPORT ExportFormat
{
public:
typedef QList<ExportFormat> List;
/**
* Creates an empty export format.
*/
ExportFormat();
/**
* Creates a new export format.
*
* @param description The i18n'ed description of the format.
* @param mimeType The supported mime type of the format.
*/
ExportFormat( const QString &description, const KMimeType::Ptr &mimeType );
/**
* Creates a new export format.
*
* @param icon The icon used in the GUI for this format.
* @param description The i18n'ed description of the format.
* @param mimeType The supported mime type of the format.
*/
ExportFormat( const KIcon &icon, const QString &description, const KMimeType::Ptr &mimeType );
/**
* Destroys the export format.
*/
~ExportFormat();
ExportFormat( const ExportFormat &other );
ExportFormat& operator=( const ExportFormat &other );
/**
* Returns the description of the format.
*/
QString description() const;
/**
* Returns the mime type of the format.
*/
KMimeType::Ptr mimeType() const;
/**
* Returns the icon for GUI representations of the format.
*/
KIcon icon() const;
private:
class Private;
Private* const d;
};
/**
* @short [Abstract Class] The information generator.
*
......@@ -70,7 +132,6 @@ class OKULAR_EXPORT Generator : public QObject
*/
Generator();
/**
* Destroys the generator.
*/
......@@ -237,27 +298,16 @@ class OKULAR_EXPORT Generator : public QObject
*/
virtual void addPages( KConfigDialog *dialog );
/**
* Returns whether the generator can export the document to text format.
*/
virtual bool canExportToText() const;
/**
* This method is called to export the document as text format and save it
* under the given @p fileName.
*/
virtual bool exportToText( const QString &fileName );
/**
* Returns the list of additional supported export formats.
*/
virtual QList<ExportEntry*> exportFormats() const;
virtual ExportFormat::List exportFormats() const;
/**
* This method is called to export the document in the given @p mimeType and save it
* under the given @p fileName. The mime type must be one of the supported export formats.
* This method is called to export the document in the given @p format and save it
* under the given @p fileName. The format must be one of the supported export formats.
*/
virtual bool exportTo( const QString &fileName, const KMimeType::Ptr &mimeType );
virtual bool exportTo( const QString &fileName, const ExportFormat &format );
// TODO: remove
virtual bool handleEvent (QEvent * /*event*/ );
......@@ -300,58 +350,96 @@ class OKULAR_EXPORT Generator : public QObject
Document * document() const;
private:
/**
* The internal pointer to the document.
*/
Document * m_document;
class Private;
Private* const d;
};
/**
* @short Describes a pixmap type request.
*/
struct OKULAR_EXPORT PixmapRequest
{
PixmapRequest( int rId, int n, int w, int h, /*double z,*/ int p, bool a )
: id( rId ), pageNumber( n ), width( w ), height( h ), /*zoom(z),*/