[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    branches/work/kviewshell-0.7/kviewshell/shell
From:       Wilfried Huss <Wilfried.Huss () gmx ! at>
Date:       2006-11-06 20:00:23
Message-ID: 1162843223.221000.19024.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 602778 by whuss:

Fix regressions caused by my last commit.

Add a widget cache that holds MarkListWidgets that are currently not in use,
to minimize Widget creation and destruction. This gives a significant performance
boost during scrolling.

Also enable prerendering of thumbnail widgets. In most cases the widgets
should now be already calculated when the widget comes into view.

Some cleanups.

 M  +5 -3      kviewpart.cpp  
 M  +84 -18    marklist.cpp  
 M  +10 -5     marklist.h  


--- branches/work/kviewshell-0.7/kviewshell/shell/kviewpart.cpp #602777:602778
@@ -604,6 +604,8 @@
 
 bool KViewPart::openFile()
 {
+  closeURL();
+
   KURL tmpFileURL;
 
   // We try to be error-tolerant about filenames. If the user calls us
@@ -1814,7 +1816,7 @@
     // Update widget sizes immediately
     pageView()->resizeWidgets();
   }
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 
   // return to the privious position in the document
   dataModel->setCurrentPageNumber(_currentPage);
@@ -1853,7 +1855,7 @@
     // Update widget sizes immediately
     pageView()->resizeWidgets();
   }
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 
   // return to the privious position in the document
   dataModel->setCurrentPageNumber(_currentPage);
@@ -1867,7 +1869,7 @@
     pageCache->clear();
 
   pageView()->repaintPages();
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 }
 
 //TODO: split into several functions
--- branches/work/kviewshell-0.7/kviewshell/shell/marklist.cpp #602777:602778
@@ -44,6 +44,9 @@
 
 #include "marklist.moc"
 
+// Maximal number of MarkListWidgets we keep in the cache,
+// to reuse for future use.
+#define WIDGET_CACHE_SIZE 100
 
 namespace {
 
@@ -448,6 +451,8 @@
 
 MarkList::~MarkList()
 {
+  clear();
+
   delete testWidget;
   delete contextMenu;
 }
@@ -475,6 +480,9 @@
 
 void MarkList::slotCreateWidgets(int x, int y)
 {
+  if (!isVisible())
+    return;
+
   Q_UNUSED(x);
 
   unsigned int ytop = y;
@@ -513,10 +521,37 @@
     {
       MarkListWidget* item = widgetMap[pages[i]];
       widgetMap.remove(pages[i]);
-      delete item;
+
+      // Since deleteing QWidgets is an expensive operation, we only do
+      // it if we already have enough in the widget cache.
+      if (widgetCache.size() <= WIDGET_CACHE_SIZE)
+      {
+        widgetCache.push_back(item);
+        item->disconnect();
+      }
+      else
+      {
+        delete item;
+      }
     }
   }
 
+  // Prerender the pages right before and after the visible ones.
+  if (dataModel->preferences()->showThumbnails())
+  {
+    //TODO: find a less ugly way to do this.
+    if (startIndex - 1 > 0)
+    {
+      testWidget->setPageNumber(startIndex - 1);
+      pageCache->getThumbnail(startIndex - 1, testWidget->thumbnailWidth());
+    }
+    if (stopIndex + 1 <= dataModel->numberOfPages())
+    {
+      testWidget->setPageNumber(stopIndex + 1);
+      pageCache->getThumbnail(stopIndex + 1, testWidget->thumbnailWidth());
+    }
+  }
+
   for (int i = startIndex; i <= stopIndex; i++)
   {
     QWidget* widget = createWidget(i);
@@ -575,9 +610,22 @@
     return widgetMap[pageNumber];
   }
 
-  MarkListWidget* item = new MarkListWidget(viewport(), this, pageNumber, pageCache, \
                dataModel->preferences()->showThumbnails());
-  item->setupObservers(dataModel);
+  MarkListWidget* item;
 
+  // If we have a widget in the widget cache use it,
+  // otherwise we really need to create a new MarkListWidget
+  if (!widgetCache.isEmpty())
+  {
+    item = widgetCache.back();
+    item->setPageNumber(pageNumber);
+    widgetCache.pop_back();
+  }
+  else
+  {
+    item = new MarkListWidget(viewport(), this, pageNumber, pageCache, \
dataModel->preferences()->showThumbnails()); +    item->setupObservers(dataModel);
+  }
+
   connect(item, SIGNAL(selected(const PageNumber&)), this, \
SLOT(thumbnailSelected(const PageNumber&)));  connect(item, \
SIGNAL(showPopupMenu(const PageNumber&, const QPoint&)), this, \
SLOT(showPopupMenu(const PageNumber&, const QPoint&)));  connect(item, \
SIGNAL(selectionToggled(const PageNumber&, bool)), this, SLOT(selectionToggled(const \
PageNumber&, bool))); @@ -618,11 +666,16 @@
   }
 
   resizeContents(visibleWidth(), y);
+
+  if (contentsY() > y)
+    setContentsPos(0, 0);
 }
 
 
 void MarkList::rebuildThumbnailWidgets()
 {
+  clear();
+
   // We need to recreate the testWidget everytime, because
   // we currently cannot enable/disable the the ThumbnailWidget
   // for an already created MarkListWidget.
@@ -725,14 +778,11 @@
 }
 
 
-void MarkList::setNumberOfPages()
+void MarkList::clear()
 {
-  clear();
-  rebuildThumbnailWidgets();
-}
+  resizeContents(0, 0);
+  setContentsPos(0, 0);
 
-void MarkList::clear()
-{
   currentPage = PageNumber::invalidPage;
   widgetPositionList.clear();
 
@@ -744,6 +794,12 @@
     widgetMap.remove(pages[i]);
     delete item;
   }
+
+  for (unsigned int i = 0; i < widgetCache.count(); i++)
+  {
+    delete widgetCache[i];
+  }
+  widgetCache.clear();
 }
 
 
@@ -882,6 +938,24 @@
 }
 
 
+void MarkList::showEvent(QShowEvent*)
+{
+  slotCreateWidgets();
+
+  // We need to realign the widgets, as their positions
+  // might have been messed up while the thumbnaillist was
+  // invisible.
+  QMap<PageNumber, MarkListWidget*>::Iterator it;
+  for (it = widgetMap.begin(); it != widgetMap.end(); ++it)
+  {
+    MarkListWidget* item = *it;
+    item->setNewWidth(visibleWidth());
+    moveChild(item, 0, widgetPositionList[item->getPageNumber() - 1]);
+  }
+
+  viewport()->update();
+}
+
 void MarkList::slotShowThumbnails()
 {
   if (dataModel->numberOfPages() == 0)
@@ -892,20 +966,12 @@
   dataModel->preferences()->setSmoothScrolling(false);
 
   // Rebuild thumbnail widgets.
-  clear();
   rebuildThumbnailWidgets();
 
   dataModel->preferences()->setSmoothScrolling(smooth);
 }
 
 
-void MarkList::repaintThumbnails()
-{
-  // Rebuild thumbnail widgets.
-  rebuildThumbnailWidgets();
-}
-
-
 void MarkList::showPopupMenu(const PageNumber& pageNumber, const QPoint& position)
 {
   if (contextMenu == 0)
@@ -1063,7 +1129,7 @@
 {
   SmoothScrollView::setupObservers(_dataModel);
   connect(dataModel, SIGNAL(currentPageNumberChanged()), this, \
                SLOT(setCurrentPage()));
-  connect(dataModel, SIGNAL(numberOfPagesChanged()), this, \
SLOT(setNumberOfPages())); +  connect(dataModel, SIGNAL(numberOfPagesChanged()), \
this, SLOT(rebuildThumbnailWidgets()));  
   /*
   QValueList<PageNumber> keys = dataModel->bookmarks();
--- branches/work/kviewshell-0.7/kviewshell/shell/marklist.h #602777:602778
@@ -57,11 +57,11 @@
 
   void setPageNumber(const PageNumber&);
 
+  int thumbnailWidth();
+
 private:
   virtual void paintEvent(QPaintEvent*);
 
-  int thumbnailWidth();
-
 private:
   PageNumber pageNumber;
 
@@ -93,6 +93,8 @@
 
   virtual void setupObservers(DataModel*);
 
+  int thumbnailWidth() { if (thumbnailWidget) return \
thumbnailWidget->thumbnailWidth(); else return 0; } +
 public slots:
   void toggle();
 
@@ -176,21 +178,19 @@
   void clear();
 
   void slotShowThumbnails();
-  void repaintThumbnails();
 
   /** @brief Called whenever the rendering of a thumbnail has been finished. */
   void slotSetThumbnail(const PageNumber&);
 
 protected:
   virtual void viewportResizeEvent(QResizeEvent*);
-
+  virtual void showEvent(QShowEvent*);
   virtual void mousePressEvent(QMouseEvent*);
 
   virtual bool isSmoothScrollDistance(double scrollDistance);
 
 private slots:
   void setCurrentPage();
-  void setNumberOfPages();
 
   void selectionToggled(const PageNumber& page, bool on);
 
@@ -274,6 +274,11 @@
   // for a given size. It is hidden. TODO: find a better way to do this.
   MarkListWidget* testWidget;
 
+  // The widgets in this list are currently not in use.
+  // Because creating and deleting MarkListWidgets is slow
+  // we use this to hold widgets that are temporarely not needed.
+  QValueVector<MarkListWidget*> widgetCache;
+
   QValueVector<unsigned int> widgetPositionList;
 
   QMap<PageNumber, MarkListWidget*> widgetMap;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic