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

List:       kde-commits
Subject:    KDE/kdegraphics/kviewshell/shell
From:       Wilfried Huss <Wilfried.Huss () gmx ! at>
Date:       2006-11-12 16:47:25
Message-ID: 1163350045.266152.22825.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 604368 by whuss:

port of commit 602778:

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  +87 -19    marklist.cpp  
 M  +10 -5     marklist.h  


--- trunk/KDE/kdegraphics/kviewshell/shell/kviewpart.cpp #604367:604368
@@ -671,6 +671,8 @@
 
 bool KViewPart::openFile()
 {
+  closeUrl();
+
   KUrl tmpFileURL;
 
   // We try to be error-tolerant about filenames. If the user calls us
@@ -1899,7 +1901,7 @@
     // Update widget sizes immediately
     pageView()->resizeWidgets();
   }
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 
   // return to the privious position in the document
   dataModel->setCurrentPageNumber(_currentPage);
@@ -1938,7 +1940,7 @@
     // Update widget sizes immediately
     pageView()->resizeWidgets();
   }
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 
   // return to the privious position in the document
   dataModel->setCurrentPageNumber(_currentPage);
@@ -1952,7 +1954,7 @@
     pageCache->clear();
 
   pageView()->repaintPages();
-  markList()->repaintThumbnails();
+  markList()->rebuildThumbnailWidgets();
 }
 
 //TODO: split into several functions
--- trunk/KDE/kdegraphics/kviewshell/shell/marklist.cpp #604367:604368
@@ -44,6 +44,10 @@
 
 #include "marklist.moc"
 
+// Maximal number of MarkListWidgets we keep in the cache,
+// to reuse for future use.
+#define WIDGET_CACHE_SIZE 100
+
 namespace {
 
 /** Holds the icon used as a overlay on pages which are not drawn yet. */
@@ -465,6 +469,8 @@
 
 MarkList::~MarkList()
 {
+  clear();
+
   delete testWidget;
   delete contextMenu;
 }
@@ -493,6 +499,9 @@
 
 void MarkList::slotCreateWidgets(int x, int y)
 {
+  if (!isVisible())
+    return;
+
   Q_UNUSED(x);
 
   unsigned int ytop = y;
@@ -531,10 +540,39 @@
     {
       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)
+      {
+        item->setSelected(false);
+	item->setChecked(false);
+        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);
@@ -593,9 +631,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))); @@ -636,11 +687,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.
@@ -743,15 +799,11 @@
 }
 
 
-void MarkList::setNumberOfPages()
+void MarkList::clear()
 {
-  clear();
-  rebuildThumbnailWidgets();
-}
+  resizeContents(0, 0);
+  setContentsPos(0, 0);
 
-
-void MarkList::clear()
-{
   currentPage = PageNumber::invalidPage;
   widgetPositionList.clear();
 
@@ -763,6 +815,12 @@
     widgetMap.remove(pages[i]);
     delete item;
   }
+
+  for (unsigned int i = 0; i < widgetCache.count(); i++)
+  {
+    delete widgetCache[i];
+  }
+  widgetCache.clear();
 }
 
 
@@ -900,6 +958,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)
@@ -910,20 +986,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)
@@ -1091,7 +1159,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()));  
   /*
   QList<PageNumber> keys = dataModel->bookmarks();
--- trunk/KDE/kdegraphics/kviewshell/shell/marklist.h #604367:604368
@@ -55,11 +55,11 @@
 
   void setPageNumber(const PageNumber&);
 
+  int thumbnailWidth();
+
 private:
   virtual void paintEvent(QPaintEvent*);
 
-  int thumbnailWidth();
-
 private:
   PageNumber pageNumber;
 
@@ -91,6 +91,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(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.
+  QVector<MarkListWidget*> widgetCache;
+
   QVector<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