Commit 3ba7c536 authored by Enrico Ros's avatar Enrico Ros

Fix preloading. It does real good now.

Fix cache deallocator. Hard avoids swapping memory or filling it up to the
limit (allocated pages are referenced in an internal add/remove FIFO).
Merged open and open_recent buttons as many users requested.
Using viewmag icon for find-as-you-type popup.
Disabled debug output. Updated todo with the roadmap to release.
- Need to audit the memory code and choose good default policies now.

svn path=/trunk/kdegraphics/kpdf/; revision=380494
parent e5d68bf1
TODO - branch version
TODO - KPdf HEAD
Legend:
ADD - ADDed
CHG - CHanGed
FIX - FIXed
MRG - MeRGed from head
(*) - Some parts of this item are already done
ADD - ADDed (new feature)
CHG - CHanGed (existing behavior)
FIX - FIXed (bug or regression)
MRG - MeRGed (code from a branch or a patch)
Status:
-> 2005-01-20: Stable. Apart from a bad memory deallocation mechanism
the core is ready for a public release. Usability: needs testing.
next steps: empty the in-progress list and keep it empty until release.
In progress:
-> memory: check for alloc/dealloc dynamic loops
-> new word highlighting for searches / other highlights (on paper - enrico)
-> mem: iterate from older pages to newest ones when freeing memory (not rand)
More items (first items will enter 'In progress list' first):
-> display current page / total pages (with analog indicator too (progressbar/...))
maybe this can be done on a small widget at the top of the toolbox, displaying
'document' informations (pages, current pg, some metadata, etc..)
Tested a 16px ktoolbar in the left-bottom corner.. looks goos and can be used to
insert some actions that aren't so useful in the main (and bigger) toolbar
-> c00l: add scrollbar marks for bookmarks (like kate)
-> google search in the page
-> cleanup code and update README.png
-> find-as-you-type: use shortcut for 'find next' action (not the default one)
-> show Viewport in ThumbnailsList (blended/contour)
......@@ -22,11 +32,6 @@ More items (first items will enter 'In progress list' first):
-> move toolbar view actions in the PageView instead of the part. maybe.. or not...
-> usability: layout 2PPV [1 2,3 4,5 6] -> [1,2 3,4 5]. add option for 'ebook' style alignment. (by Mikolaj)
-> usability: trigger redraw on 'filter text' on current page (by Mikolaj)
-> display current page / total pages (with analog indicator too (progressbar/...))
maybe this can be done on a small widget at the top of the toolbox, displaying
'document' informations (pages, current pg, some metadata, etc..).
Tested a 16px ktoolbar in the left-bottom corner.. looks goos and can be used to
insert some actions that aren't so useful in the main (and bigger) toolbar
-> abstract TextPage generation (the last xpdf dependant class!). then go dancing in the
streets.
-> better boomark rendering (tested a 'clip overlay' but looks bad actually)
......@@ -50,7 +55,7 @@ More items (first items will enter 'In progress list' first):
-> take care of TODOs in code
-> ADD: click over image allows "save image" [60% done (activerect of type image)]
-> screen editing (annotations): framework (BR67300,BR62793)
-> screen editing (annotations): tools (BR67300)
-> screen editing (annotations): tools (BR67300), yellow notes 'post-it' like
-> export all text in plain_text/html
-> extract(export?) images (have a look at ImageOutputDev.cc and pdfimages.cc from xpdf (not in our xpdf sources))
-> text selection in wordprocessor style (very hard/impossible)
......@@ -61,6 +66,7 @@ More items (first items will enter 'In progress list' first):
-> kttsd output with menu entries. speech{document/page/selection}. (patch available - enrico)
-> kttsd alternative (1): autodetect "/dev/speech" (speechd/festival) and provide reading
-> automatic online dictionaries / translators (BR80338)
-> core: pdf forms support
-> add OCR for building TextPages out of pure graphical (aka scanned) pages
-> rotate the whole document / individual pages
-> presentation: implement transitions (6/11 done)
......@@ -75,8 +81,13 @@ More items (first items will enter 'In progress list' first):
-> use shortcuts for next and prev page even in presenatation mode (by Tobias Koenig)
-> move some document related features from part to the document (see find, goto dialog, ...)
-> Albert: Read pdf specification and see if paths with length = 1 are allowed, in case they are allowed see how to fix 97131 without skipping paths with length = 1
-> tools: ruler, measure: distance, perimeter, ?area?, color picker
-> export: export to other formats keeping formatting (a dream.. except for PNG :-)
Done (newest features come first):
-> FIX: memory unloading order and hard swap avoiding
-> CHG: open and open-recent buttons unified in Shell
-> CHG: lens icon for the find-ahead messages
-> ADD: page preloading
-> FIX: smarter memory management / prioritize queries
-> ADD: type ahead search in pageview (type '/' then the word to search..) (JakubS)
......@@ -150,10 +161,3 @@ Done (newest features come first):
-> The branch 'kpdf_experiments' was created at this point. Code refactoring started.
-> ADD: Completely use xpdf code for rendering that solves most font problems (Albert)
-> MRG: Replace xpdf version with lastest one (3.00) that supports PDF 1.5 (Albert)
Here comes a list of suggestions from a dot post http://dot.kde.org/1095261317 and IRC:
Tool: ruler, measure: distance, perimeter, ?area?
Tool: color picker
Annotations: yellow notes 'post-it' like
Export: export to other formats keeping formatting (a dream.. except for PNG :-)
PDF: <theICEBear> pdf forms support.... :D if at all possible
......@@ -90,7 +90,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>Link &amp;thumbnails list with the page</string>
<string>Link the &amp;thumbnails with the page</string>
</property>
</widget>
</grid>
......
......@@ -52,33 +52,35 @@ class KPDFDocumentPrivate
QString xmlFileName;
// observers / requests stuff
QMap< int, class ObserverData* > observers;
QMap< int, DocumentObserver * > observers;
QValueList< PixmapRequest * > pixmapRequestsStack;
QValueList< class AllocatedPixmap * > allocatedPixmapsFifo;
int allocatedPixmapsTotalMemory;
// timers (memory checking / info saver)
QTimer * memCheckTimer;
QTimer * saveBookmarksTimer;
};
struct ObserverData
struct AllocatedPixmap
{
// public data fields
DocumentObserver * instance;
QMap< int, int > pageMemory;
int totalMemory;
// owner of the page
int id;
int page;
int memory;
// public constructor: initialize data
ObserverData( DocumentObserver * obs ) : instance( obs ), totalMemory( 0 ) {};
AllocatedPixmap( int i, int p, int m ) : id( i ), page( p ), memory( m ) {};
};
#define foreachObserver( cmd ) {\
QMap< int, ObserverData * >::iterator it = d->observers.begin(), end = d->observers.end();\
for ( ; it != end ; ++ it ) { (*it)->instance-> cmd ; } }
QMap< int, DocumentObserver * >::iterator it=d->observers.begin(), end=d->observers.end();\
for ( ; it != end ; ++ it ) { (*it)-> cmd ; } }
KPDFDocument::KPDFDocument()
: generator( 0 ), d( new KPDFDocumentPrivate )
{
d->searchPage = -1;
d->allocatedPixmapsTotalMemory = 0;
d->memCheckTimer = new QTimer( this );
connect( d->memCheckTimer, SIGNAL( timeout() ), this, SLOT( slotCheckMemory() ) );
d->saveBookmarksTimer = new QTimer( this );
......@@ -87,17 +89,10 @@ KPDFDocument::KPDFDocument()
KPDFDocument::~KPDFDocument()
{
// delete generator, pages, and related stuff
closeDocument();
ObserverData *o;
QMap< int, ObserverData * >::iterator oIt;
while (d->observers.count() > 0)
{
oIt = d->observers.begin();
o = *oIt;
d->observers.remove(oIt);
delete o;
}
// delete the private structure
delete d;
}
......@@ -189,29 +184,30 @@ void KPDFDocument::closeDocument()
foreachObserver( notifySetup( QValueVector< KPDFPage * >(), true ) );
// delete pages and clear 'pages_vector' container
for ( uint i = 0; i < pages_vector.count() ; i++ )
delete pages_vector[i];
QValueVector< KPDFPage * >::iterator pIt = pages_vector.begin();
QValueVector< KPDFPage * >::iterator pEnd = pages_vector.end();
for ( ; pIt != pEnd; ++pIt )
delete *pIt;
pages_vector.clear();
// clear memory management data
QMap< int, ObserverData * >::iterator oIt = d->observers.begin(), oEnd = d->observers.end();
for ( ; oIt != oEnd ; ++oIt )
{
ObserverData * observerData = *oIt;
observerData->pageMemory.clear();
observerData->totalMemory = 0;
}
QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
for ( ; aIt != aEnd; ++aIt )
delete *aIt;
d->allocatedPixmapsFifo.clear();
// reset internal variables
d->viewport = DocumentViewport();
d->searchPage = -1;
d->allocatedPixmapsTotalMemory = 0;
}
void KPDFDocument::addObserver( DocumentObserver * pObserver )
{
// keep the pointer to the observer in a map
d->observers[ pObserver->observerId() ] = new ObserverData( pObserver );
d->observers[ pObserver->observerId() ] = pObserver;
// if the observer is added while a document is already opened, tell it
if ( !pages_vector.isEmpty() )
......@@ -229,8 +225,7 @@ void KPDFDocument::removeObserver( DocumentObserver * pObserver )
for ( ; it != end; ++it )
(*it)->deletePixmap( observerId );
// delete observer storage info
delete d->observers[ observerId ];
// delete observer entry from the map
d->observers.remove( observerId );
}
}
......@@ -318,8 +313,6 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request
// 2. [ADD TO STACK] add requests to stack
bool threadingDisabled = !Settings::enableThreading();
bool preloadDisabled = threadingDisabled ||
Settings::memoryLevel() == Settings::EnumMemoryLevel::Low;
QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end();
for ( ; rIt != rEnd; ++rIt )
{
......@@ -403,10 +396,29 @@ void KPDFDocument::setViewport( const DocumentViewport & viewport, int id )
d->viewport = viewport;
// notify change to all other (different from id) viewports
QMap< int, ObserverData * >::iterator it = d->observers.begin(), end = d->observers.end();
QMap< int, DocumentObserver * >::iterator it = d->observers.begin(), end = d->observers.end();
for ( ; it != end ; ++ it )
if ( it.key() != id )
(*it)->instance->notifyViewportChanged();
(*it)->notifyViewportChanged();
/* [MEM] raise position of currently viewed page in allocation queue
if ( d->allocatedPixmapsFifo.count() > 1 )
{
QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
QValueList< AllocatedPixmap * >::iterator aLast = d->allocatedPixmapsFifo.end();
--aLast;
while ( aIt != aLast )
{
if ( (*aIt)->page == viewport.pageNumber )
{
d->allocatedPixmapsFifo.append( *aIt );
aIt = d->allocatedPixmapsFifo.remove( aIt );
p--rintf("%d raised prio of %d %d\n",d->allocatedPixmapsFifo.count(), (*aIt)->id, (*aIt)->page);
}
else
++aIt;
}
}*/
}
bool KPDFDocument::findText( const QString & string, bool keepCase, bool findAhead )
......@@ -635,21 +647,42 @@ bool KPDFDocument::print( KPrinter &printer )
return generator ? generator->print( printer ) : false;
}
void KPDFDocument::requestDone( PixmapRequest * req ) //FIXME
void KPDFDocument::requestDone( PixmapRequest * req )
{
// notify an observer that its pixmap changed
if ( d->observers.contains( req->id ) )
d->observers[ req->id ]->instance->notifyPageChanged( req->pageNumber, DocumentObserver::Pixmap );
// delete request
delete req;
// start a new generation
#ifndef NDEBUG
if ( !generator->canGeneratePixmap() )
kdDebug() << "requestDone with generator not in READY state." << endl;
#endif
sendGeneratorRequest();
// [MEM] 1.1 find and remove a previous entry for the same page and id
QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
for ( ; aIt != aEnd; ++aIt )
if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id )
{
AllocatedPixmap * p = *aIt;
d->allocatedPixmapsFifo.remove( aIt );
d->allocatedPixmapsTotalMemory -= p->memory;
delete p;
break;
}
// [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 );
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 );
// 3. delete request
delete req;
// 4. start a new generation if some is pending
if ( !d->pixmapRequestsStack.isEmpty() )
sendGeneratorRequest();
}
void KPDFDocument::sendGeneratorRequest()
......@@ -671,81 +704,74 @@ void KPDFDocument::sendGeneratorRequest()
if ( !request )
return;
// FIXME CHECK PREALLOC
// MEM: calc memory that should be freed to allow the new generation
int pixmapMemory = 4 * request->width * request->height / 1024;
// MEM: update statistics counting this pixmap
ObserverData * obs = d->observers[ request->id ];
int pageNumber = request->pageNumber;
if ( obs->pageMemory.contains( pageNumber ) )
obs->totalMemory -= obs->pageMemory[ pageNumber ];
obs->pageMemory[ pageNumber ] = pixmapMemory;
obs->totalMemory += pixmapMemory;
// MEM: cleanup
mCleanupMemory( request->id );
// [MEM] preventive memory freeing
int pixmapBytes = 4 * request->width * request->height;
if ( pixmapBytes > (1024 * 1024) )
cleanupMemory( pixmapBytes );
// submit the request to the generator
generator->generatePixmap( request );
}
void KPDFDocument::mCleanupMemory( int observerId )
void KPDFDocument::cleanupMemory( int /*freeOffset*/ )
{
// get observer data for given id
ObserverData * obs = d->observers[ observerId ];
// choose memory parameters based on configuration profile
int clipValue = 0;
int memoryToFree = 0;
int clipValue = -1;
int memoryToFree = -1;
switch ( Settings::memoryLevel() )
{
case Settings::EnumMemoryLevel::Low:
memoryToFree = obs->totalMemory;
memoryToFree = d->allocatedPixmapsTotalMemory;
break;
case Settings::EnumMemoryLevel::Normal:
clipValue = obs->totalMemory - mFreeMemory() / 3;
if ( observerId == THUMBNAILS_ID )
memoryToFree = obs->totalMemory - mTotalMemory() / 20;
else
memoryToFree = obs->totalMemory - mTotalMemory() / 5;
memoryToFree = d->allocatedPixmapsTotalMemory - getTotalMemory() / 5;
clipValue = d->allocatedPixmapsTotalMemory - getFreeMemory() / 2;
break;
case Settings::EnumMemoryLevel::Aggressive:
clipValue = obs->totalMemory - mFreeMemory() / 2;
clipValue = d->allocatedPixmapsTotalMemory - getFreeMemory() / 2;
break;
}
// p--rintf("T:%d TT:%d FF:%d - c:%d m:%d\n", d->allocatedPixmapsTotalMemory, getTotalMemory(), getFreeMemory(), clipValue, memoryToFree);
if ( clipValue > memoryToFree )
memoryToFree = clipValue;
if ( memoryToFree <= 0 )
return;
if ( memoryToFree > 0 )
freeMemory( memoryToFree );
}
// free memory. remove older data until we free enough memory
int freed = 0;
QMap< int, int >::iterator it = obs->pageMemory.begin(), end = obs->pageMemory.end();
while ( (it != end) && (memoryToFree > 0) )
void KPDFDocument::freeMemory( int bytesToFree )
{
//kdDebug() << "Freeing: " << bytesToFree << " bytes" << endl;
// [MEM] free memory starting from older pixmaps
int pagesFreed = 0;
QValueList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin();
QValueList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end();
while ( (pIt != pEnd) && (bytesToFree > 0) )
{
int pageNumber = it.key();
if ( obs->instance->canUnloadPixmap( pageNumber ) )
AllocatedPixmap * p = *pIt;
if ( d->observers[ p->id ]->canUnloadPixmap( p->page ) )
{
// copy iterator to avoid invalidation on map->remove( it )
QMap< int, int >::iterator i( it );
++it;
// update mem stats
memoryToFree -= i.data();
obs->totalMemory -= i.data();
obs->pageMemory.remove( i );
// update internal variables
pIt = d->allocatedPixmapsFifo.remove( pIt );
d->allocatedPixmapsTotalMemory -= p->memory;
bytesToFree -= p->memory;
pagesFreed++;
// delete pixmap
pages_vector[ pageNumber ]->deletePixmap( observerId );
freed++;
pages_vector[ p->page ]->deletePixmap( p->id );
// delete allocation descriptor
delete p;
} else
++it;
++pIt;
}
//kdDebug() << "Id:" << observerId << " [" << obs->totalMemory << "kB] Removed " << freed << " pages. " << obs->pageMemory.count() << " pages kept in memory." << endl;
//kdDebug() << "items: " << d->allocatedPixmapsFifo.count() << " [" << (d->allocatedPixmapsTotalMemory/1000) << "] Removed " << pagesFreed << " pages. gap: " << bytesToFree << endl;
}
int KPDFDocument::mTotalMemory()
int KPDFDocument::getTotalMemory()
{
static int cachedValue = 0;
if ( cachedValue )
......@@ -755,7 +781,7 @@ int KPDFDocument::mTotalMemory()
// if /proc/meminfo doesn't exist, return 128MB
QFile memFile( "/proc/meminfo" );
if ( !memFile.open( IO_ReadOnly ) )
return (cachedValue = 131072);
return (cachedValue = 134217728);
// read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers'
// and 'Cached' fields. consider swapped memory as used memory.
......@@ -764,13 +790,13 @@ int KPDFDocument::mTotalMemory()
{
QString entry = readStream.readLine();
if ( entry.startsWith( "MemTotal:" ) )
return (cachedValue = entry.section( ' ', -2, -2 ).toInt());
return (cachedValue = (1024 * entry.section( ' ', -2, -2 ).toInt()));
}
#endif
return (cachedValue = 131072);
return (cachedValue = 134217728);
}
int KPDFDocument::mFreeMemory()
int KPDFDocument::getFreeMemory()
{
#ifdef __linux__
// if /proc/meminfo doesn't exist, return MEMORY FULL
......@@ -795,7 +821,7 @@ int KPDFDocument::mFreeMemory()
memoryFree -= entry.section( ' ', -2, -2 ).toInt();
}
memFile.close();
return memoryFree;
return 1024 * memoryFree;
#else
// tell the memory is full.. will act as in LOW profile
return 0;
......@@ -982,15 +1008,10 @@ void KPDFDocument::saveDocumentInfo() const
void KPDFDocument::slotCheckMemory()
{
// perform the memory check for 'free mem dependant' profiles only
if ( Settings::memoryLevel() == Settings::EnumMemoryLevel::Low )
return;
// for each observer going over 1MB of memory, invoke the manager
QMap< int, ObserverData * >::iterator it = d->observers.begin(), end = d->observers.end();
for ( ; it != end ; ++ it )
if ( (*it)->totalMemory > 1024 )
mCleanupMemory( it.key() /*observerId*/ );
// [MEM] clean memory (for 'free mem dependant' profiles only)
if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low &&
d->allocatedPixmapsTotalMemory > 1024*1024 )
cleanupMemory();
}
......
......@@ -92,9 +92,10 @@ class KPDFDocument : public QObject // only for a private slot..
private:
void sendGeneratorRequest();
// memory management related functions
void mCleanupMemory( int observerId );
int mTotalMemory();
int mFreeMemory();
void cleanupMemory( int bytesOffset = 0 );
void freeMemory( int bytes );
int getTotalMemory();
int getFreeMemory();
// more private functions
void loadDocumentInfo();
QString giveAbsolutePath( const QString & fileName );
......
......@@ -140,16 +140,14 @@ void Shell::writeSettings()
KGlobal::config()->sync();
}
void
Shell::setupActions()
void Shell::setupActions()
{
KStdAction::open(this, SLOT(fileOpen()), actionCollection());
m_recent = KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ),
actionCollection() );
KAction * openAction = KStdAction::open(this, SLOT(fileOpen()), actionCollection());
m_recent = KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ), actionCollection() );
connect( m_recent, SIGNAL( activated() ), openAction, SLOT( activate() ) );
KStdAction::print(m_part, SLOT(slotPrint()), actionCollection());
KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
setStandardToolBarMenuEnabled(true);
m_showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection());
......
......@@ -15,7 +15,6 @@
</MenuBar>
<ToolBar noMerge="1" name="mainToolBar" >
<text>Main Toolbar</text>
<Action name="file_open" />
<Action name="file_open_recent" />
<Action name="file_print" />
</ToolBar>
......
......@@ -525,7 +525,7 @@ void PageView::keyPressEvent( QKeyEvent * e )
releaseKeyboard();
if ( d->document->findText() )
d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->findString.lower()),
PageViewMessage::Info, 3000 );
PageViewMessage::Find, 3000 );
d->findTimer->start( 3000, true );
grabKeyboard();
return;
......@@ -546,7 +546,7 @@ void PageView::keyPressEvent( QKeyEvent * e )
else if( e->key() == '/' && d->document->isOpened() )
{
d->findString = QString();
d->messageWindow->display(i18n("Starting -- find text as you type"), PageViewMessage::Info, 3000);
d->messageWindow->display(i18n("Starting -- find text as you type"), PageViewMessage::Find, 3000);
d->typeAheadActivated = true;
if ( !d->findTimer )
{
......@@ -634,7 +634,7 @@ void PageView::findTimeout()
{
d->typeAheadActivated = false;
d->findString = "";
d->messageWindow->display(i18n("Find stopped."),PageViewMessage::Info,1000);
d->messageWindow->display(i18n("Find stopped."),PageViewMessage::Find,1000);
releaseKeyboard();
}
......@@ -644,11 +644,13 @@ void PageView::findAhead(bool increase)
d->document->setViewportPage(0);
QString status;
d->document->unHilightPages(false);
if(d->document->findText(d->findString, false, true))
bool found = d->document->findText(d->findString, false, true);
if(found)
status = i18n("Text found: \"%1\".");
else
status = i18n("Text not found: \"%1\".");
d->messageWindow->display(status.arg(d->findString.lower()), PageViewMessage::Info, 4000);
d->messageWindow->display(status.arg(d->findString.lower()),
found ? PageViewMessage::Find : PageViewMessage::Warning, 4000);
}
......@@ -1530,36 +1532,38 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop )
}
}
// request pixmaps in 'requests list'
if ( !requestedPixmaps.isEmpty() )
// if preloading is enabled, add the pages before and after in preloading
if ( !d->visibleItems.isEmpty() &&
Settings::memoryLevel() != Settings::EnumMemoryLevel::Low &&
Settings::enableThreading() )
{
// if preloading is enabled, add the pages before and after in preloading
if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low &&
Settings::enableThreading() )
// add the page before the 'visible series' in preload
int headRequest = d->visibleItems.first()->pageNumber() - 1;
if ( headRequest >= 0 )
{
int headRequest = requestedPixmaps.first()->pageNumber - 1;
int tailRequest = requestedPixmaps.last()->pageNumber + 1;
// add the page before in preload
if ( headRequest >= 0 )
{
PageViewItem * i = d->items[ headRequest ];
PixmapRequest * p = new PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true );
requestedPixmaps.push_back( p );
}
// add the page before in preload
if ( tailRequest < d->items.count() )
{
PageViewItem * i = d->items[ tailRequest ];
PixmapRequest * p = new PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true );
requestedPixmaps.push_back( p );
}
PageViewItem * i = d->items[ headRequest ];
// request the pixmap if not already present
if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) )
requestedPixmaps.push_back( new PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) );
}
// add the page after the 'visible series' in preload
int tailRequest = d->visibleItems.last()->pageNumber() + 1;
if ( tailRequest < (int)d->items.count() )
{
PageViewItem * i = d->items[ tailRequest ];
// request the pixmap if not already present
if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) )
requestedPixmaps.push_back( new PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) );
}
// send requests to the document