• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

documentPageCache.cpp

Go to the documentation of this file.
00001 //
00002 // Class: documentPageCache
00003 //
00004 // Cache that holds a number of pages in a document.
00005 // Part of KDVI- A previewer for TeX DVI files.
00006 //
00007 // (C) 2004 Stefan Kebekus. Distributed under the GPL.
00008 
00009 #include <config.h>
00010 
00011 #include <kdebug.h>
00012 #include <qapplication.h>
00013 
00014 #include "documentPageCache.h"
00015 #include "documentRenderer.h"
00016 #include "kvsprefs.h"
00017 #include "renderedDocumentPagePixmap.h"
00018 
00019 
00020 //#define documentPageCache_DEBUG
00021 
00022 
00023 DocumentPageCache::DocumentPageCache()
00024   : maxMemory(2*16777216), LRUCache(maxMemory, 200)
00025 {
00026   LRUCache.setAutoDelete(true);
00027 
00028   resolutionInDPI = 0.0;
00029   Length w,h;
00030   w.setLength_in_mm(200);
00031   h.setLength_in_mm(300);
00032   userPreferredSize.setPageSize(w,h);
00033   useDocumentSpecifiedSize = true;
00034 }
00035 
00036 
00037 DocumentPageCache::~DocumentPageCache()
00038 {
00039 }
00040 
00041 
00042 void DocumentPageCache::setRenderer(DocumentRenderer *_renderer)
00043 {
00044   clear();
00045   renderer = _renderer;
00046 }
00047 
00048 
00049 SimplePageSize DocumentPageCache::sizeOfPage(const PageNumber& page) const
00050 {
00051   // Paranoid safety checks
00052   if (!page.isValid()) {
00053     kdError(1223) << "DocumentPageCache::sizeOfPage( " <<  page << ") called with invalid page number." << endl;
00054     return SimplePageSize();
00055   }
00056   if (renderer.isNull()) {
00057     kdError(1223) << "DocumentPageCache::sizeOfPage( " <<  page << ") called when no renderer was set." << endl;
00058     return SimplePageSize();
00059   }
00060 
00061   SimplePageSize s = renderer->sizeOfPage(page);
00062   if (!useDocumentSpecifiedSize)
00063     s = userPreferredSize;
00064 
00065   if (!s.isValid())
00066   {
00067     // If the size is invalid use the size of the first Page in the document
00068     // as an estimate.
00069     s = renderer->sizeOfPage(1);
00070     if (!s.isValid())
00071       s = userPreferredSize;
00072   }
00073 
00074   return s;
00075 }
00076 
00077 void DocumentPageCache::setResolution(double res)
00078 {
00079   resolutionInDPI = res;
00080 }
00081 
00082 QSize DocumentPageCache::sizeOfPageInPixel(const PageNumber& pg) const
00083 {
00084   // Paranoid safety checks
00085   if (renderer.isNull()) {
00086     kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called but no renderer was set" << endl;
00087     return QSize();
00088   }
00089   if (!pg.isValid()) {
00090     kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called with invalid argument" << endl;
00091     return QSize();
00092   }
00093 
00094   SimplePageSize ps = sizeOfPage(pg);
00095   if (ps.isValid())
00096     return ps.sizeInPixel(resolutionInDPI);
00097   return userPreferredSize.sizeInPixel(resolutionInDPI); 
00098 }
00099 
00100 
00101 bool DocumentPageCache::isPageCached(const PageNumber& pageNumber, const QSize& size)
00102 {
00103   // Paranoid checks
00104   if (renderer.isNull()) {
00105     kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
00106     return false;
00107   }
00108   if (!pageNumber.isValid()) {
00109     kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
00110     return false;
00111   }
00112   if (renderer->totalPages() < pageNumber) {
00113     kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
00114                   << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
00115     return false;
00116   }
00117 
00118   QString key = createKey(pageNumber, size);
00119 
00120   // Check if the page that we are looking for is in the cache.
00121   // We are not accessing the page, so we don't want it to be moved into the front.
00122   RenderedDocumentPagePixmap* page = LRUCache.find(key, false);
00123 
00124   if (page)
00125     return true;
00126   else
00127     return false;
00128 }
00129 
00130 QString DocumentPageCache::createKey(const PageNumber& pageNumber, const QSize& size)
00131 {
00132   QString key;
00133 
00134   key = QString::number(pageNumber) + ":" +
00135         QString::number(size.width()) + ":" + QString::number(size.height());
00136 
00137   return key;
00138 }
00139 
00140 QString DocumentPageCache::createKey(const PageNumber& pageNumber)
00141 {
00142   QSize pageSize = sizeOfPageInPixel(pageNumber);
00143 
00144   QString key;
00145 
00146   key = QString::number(pageNumber) + ":" +
00147         QString::number(pageSize.width()) + ":" + QString::number(pageSize.height());
00148 
00149   return key;
00150 }
00151 
00152 bool DocumentPageCache::isPageCached(const PageNumber& pageNumber)
00153 {
00154   // Paranoid checks
00155   if (renderer.isNull()) {
00156     kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
00157     return false;
00158   }
00159   if (!pageNumber.isValid()) {
00160     kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
00161     return false;
00162   }
00163   if (renderer->totalPages() < pageNumber) {
00164     kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
00165                   << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
00166     return false;
00167   }
00168 
00169   return isPageCached(pageNumber, sizeOfPageInPixel(pageNumber));
00170 }
00171 
00172 RenderedDocumentPagePixmap* DocumentPageCache::getPage(const PageNumber& pageNr)
00173 {
00174 #ifdef DocumentPageCache_DEBUG
00175   kdDebug(1223) << "DocumentPageCache::getPage( pageNr=" << pageNr << " )" << endl;
00176 #endif
00177 
00178   // Paranoid checks
00179   if (renderer.isNull()) {
00180     kdError(1223) << "DocumentPageCache::getPage(..) called but no renderer was set" << endl;
00181     return 0;
00182   }
00183   if (!pageNr.isValid()) {
00184     kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called, with invalid argument." << endl;
00185     return 0;
00186   }
00187   if (renderer->totalPages() < pageNr) {
00188     kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
00189     return 0;
00190   }
00191 
00192   // First check if the page that we are looking for is in the cache
00193   RenderedDocumentPagePixmap* page;
00194   page = LRUCache.find(createKey(pageNr));
00195 
00196   if (page)
00197     return page;
00198 
00199   // The page was not found in the cache, so we have to make a new
00200   // page and add this to the cache.
00201   page = createDocumentPagePixmap();
00202 
00203   // If that failed, issue an error message and quit.
00204   if (page == 0) {
00205     kdError(1223) << "DocumentPageCache::getPage(..) cannot allocate DocumentPage structure" << endl;
00206     return 0;
00207   }
00208   
00209   // Now 'page' contains a point to a page structure that we can
00210   // use. Add the page to the cache, and apply the renderer to the page.
00211   page->setPageNumber(pageNr);
00212   if (!renderer.isNull())
00213   {
00214     if (resolutionInDPI > 0.0)
00215     {
00216       page->resize(sizeOfPageInPixel(pageNr));
00217       QApplication::setOverrideCursor( waitCursor );
00218       renderer->drawPage(resolutionInDPI, page);
00219       QApplication::restoreOverrideCursor();
00220 
00221       // We always set the cache capacity to be at least n times the cost of the page we want to insert.
00222       // Where n is the number of pages that can be visible at the same time at very high zoomlevels.
00223       // n depends on the layout mode.
00224       // If these pages are not all in the cache, scrolling the view becomes very slow, because for each
00225       // paint event the pages need to be rerendered.
00226       // We set n for each viewmode differently so that the user is able to reduce memory consuption by
00227       // switching to a simpler viewmode like Single Page.
00228       int n = 4;
00229       switch (KVSPrefs::viewMode())
00230       {
00231         case KVSPrefs::EnumViewMode::SinglePage:
00232           n = 1;
00233           break;
00234         case KVSPrefs::EnumViewMode::Continuous:
00235           n = 2;
00236           break;
00237         default:
00238           n = 4;
00239       }
00240       LRUCache.setMaxCost(QMAX(page->memory() * n, maxMemory));
00241 
00242       if (!LRUCache.insert(createKey(pageNr), page, page->memory()))
00243       {
00244         kdError() << "DocumentPageCache::getPage(): inserting pagestructure into the cache failed.\n This should never happen. If you see this message, something is very wrong." << endl;
00245       }
00246     }
00247     else
00248       kdError(1223) << "DocumentPageCache::getPage() called, but no resolution or negative resolution was set" << endl;
00249   }
00250 
00251   return page;
00252 }
00253 
00254 
00255 RenderedDocumentPagePixmap* DocumentPageCache::createDocumentPagePixmap() const
00256 {
00257  return new RenderedDocumentPagePixmap();
00258 }
00259 
00260 
00261 void DocumentPageCache::clear()
00262 {
00263   LRUCache.clear();
00264 }
00265 
00266 
00267 void DocumentPageCache::setUserPreferredSize(const SimplePageSize& s)
00268 {
00269   bool sizeChanged = !userPreferredSize.isNearlyEqual(s);
00270   userPreferredSize = s;
00271 
00272   if (sizeChanged)
00273     emit(paperSizeChanged());
00274 }
00275 
00276 
00277 void DocumentPageCache::setUseDocumentSpecifiedSize(bool b)
00278 {
00279   bool valChanged = (useDocumentSpecifiedSize == b);
00280 
00281   useDocumentSpecifiedSize = b;
00282   if (valChanged)
00283     emit(paperSizeChanged());
00284 }
00285 
00286 
00287 QPixmap DocumentPageCache::createThumbnail(const PageNumber& pageNr, int width)
00288 {
00289   // Paranoid checks
00290   if (renderer.isNull()) {
00291     kdError(1223) << "DocumentPageCache::createThumbnail(..) called but no renderer was set" << endl;
00292     thumbnailPage.resize(0,0);
00293     return thumbnailPage;
00294   }
00295   if (renderer->totalPages() < pageNr) {
00296     kdError(1223) << "DocumentPageCache::createThumbnail( " << pageNr << ", width ) called but document contains only " << renderer->totalPages() << " pages." << endl;
00297     thumbnailPage.resize(0,0);
00298     return thumbnailPage;
00299   }
00300   if (!pageNr.isValid()) {
00301     kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid page specification" << endl;
00302     thumbnailPage.resize(0,0);
00303     return thumbnailPage;
00304   }
00305   if (!sizeOfPage().isValid()) {
00306     kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid size" << endl;
00307     thumbnailPage.resize(0,0);
00308     return thumbnailPage;
00309   }
00310 
00311   thumbnailPage.setPageNumber(pageNr);
00312   thumbnailPage.resize(width, (int)(width/sizeOfPage(pageNr).aspectRatio() + 0.5 ) );
00313   renderer->drawThumbnail((double)(width)/sizeOfPage(pageNr).width().getLength_in_inch(), &thumbnailPage);
00314 
00315   if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
00316   {
00317     return thumbnailPage.accessiblePixmap();
00318   }
00319   else
00320   {
00321     return thumbnailPage;
00322   }
00323 }
00324 
00325 void DocumentPageCache::deselectText() 
00326 {
00327   userSelection.clear();
00328   emit textSelected(false);
00329 }
00330 
00331 void DocumentPageCache::selectText(const TextSelection& selection)
00332 {
00333   userSelection = selection;
00334   emit textSelected(!userSelection.isEmpty());
00335 }
00336 
00337 #include "documentPageCache.moc"

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal