]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Fix potential endless loop in layout
authorPeter Penz <peter.penz19@gmail.com>
Sun, 5 Feb 2012 18:14:17 +0000 (19:14 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Sun, 5 Feb 2012 18:22:34 +0000 (19:22 +0100)
Usecase:
- No scrollbar is shown
- Window size will be decreased so that a scrollbar gets necessary

The decreased window size minus the space required for the scrollbar
results in a relayout of the items. In 99 % of all
cases a decreased window size won't result in showing more items in parallel in
comparison to a larger window size. However in the remaining 1 % this can
happen (e.g. see bug 293318 for a sample). This results in an endless loop as
now no scrollbar is required anymore, the layout changes again, the scrollbar
is required again, ...

BUG: 293318
FIXED-IN: 4.8.1

src/kitemviews/kitemlistcontainer.cpp
src/kitemviews/kitemlistcontainer.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h

index 58f2e3cd6bcfa25f188d2ab5f0f43b35184a25ce..b480b449488eb7b40411cf88be27cd7ae31f6109 100644 (file)
@@ -234,11 +234,19 @@ void KItemListContainer::updateScrollOffsetScrollBar()
     const int value = view->scrollOffset();
     const int maximum = qMax(0, int(view->maximumScrollOffset() - pageStep));
     if (smoothScroller->requestScrollBarUpdate(maximum)) {
     const int value = view->scrollOffset();
     const int maximum = qMax(0, int(view->maximumScrollOffset() - pageStep));
     if (smoothScroller->requestScrollBarUpdate(maximum)) {
+        const bool updatePolicy = (scrollOffsetScrollBar->maximum() > 0 && maximum == 0)
+                                  || horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn;
+
         scrollOffsetScrollBar->setSingleStep(singleStep);
         scrollOffsetScrollBar->setPageStep(pageStep);
         scrollOffsetScrollBar->setMinimum(0);
         scrollOffsetScrollBar->setMaximum(maximum);
         scrollOffsetScrollBar->setValue(value);
         scrollOffsetScrollBar->setSingleStep(singleStep);
         scrollOffsetScrollBar->setPageStep(pageStep);
         scrollOffsetScrollBar->setMinimum(0);
         scrollOffsetScrollBar->setMaximum(maximum);
         scrollOffsetScrollBar->setValue(value);
+
+        if (updatePolicy) {
+            // Prevent a potential endless layout loop (see bug #293318).
+            updateScrollOffsetScrollBarPolicy();
+        }
     }
 }
 
     }
 }
 
@@ -320,6 +328,32 @@ void KItemListContainer::updateSmoothScrollers(Qt::Orientation orientation)
     }
 }
 
     }
 }
 
+void KItemListContainer::updateScrollOffsetScrollBarPolicy()
+{
+    const KItemListView* view = m_controller->view();
+    Q_ASSERT(view);
+    const bool vertical = (view->scrollOrientation() == Qt::Vertical);
+
+    QStyleOption option;
+    option.initFrom(this);
+    const int scrollBarInc = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, this);
+
+    QSizeF newViewSize = m_controller->view()->size();
+    if (vertical) {
+        newViewSize.rwidth() += scrollBarInc;
+    } else {
+        newViewSize.rheight() += scrollBarInc;
+    }
+
+    const Qt::ScrollBarPolicy policy = view->scrollBarRequired(newViewSize)
+                                       ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAsNeeded;
+    if (vertical) {
+        setVerticalScrollBarPolicy(policy);
+    } else {
+        setHorizontalScrollBarPolicy(policy);
+    }
+}
+
 void KItemListContainer::initialize()
 {
     if (m_controller) {
 void KItemListContainer::initialize()
 {
     if (m_controller) {
index 4d6eadbbbd4356a6f3671e38cf2e9a031a5d7faa..b41f48a7f189d556e0203e55a90de6d24e6578a0 100644 (file)
@@ -70,6 +70,13 @@ private:
     void updateGeometries();
     void updateSmoothScrollers(Qt::Orientation orientation);
 
     void updateGeometries();
     void updateSmoothScrollers(Qt::Orientation orientation);
 
+    /**
+     * Helper method for updateScrollOffsetScrollBar(). Updates the scrollbar-policy
+     * to Qt::ScrollBarAlwaysOn for cases where turning off the scrollbar might lead
+     * to an endless layout loop (see bug #293318).
+     */
+    void updateScrollOffsetScrollBarPolicy();
+
 private:
     KItemListController* m_controller;
 
 private:
     KItemListController* m_controller;
 
index c671a2e6e939500b787fd0d7c137f8bbc078f79e..52d85770549c0be87f6ac07dc1bdb445e40b4821 100644 (file)
@@ -1880,6 +1880,19 @@ bool KItemListView::animateChangedItemCount(int changedItemCount) const
     return changedItemCount <= maximum * 2 / 3;
 }
 
     return changedItemCount <= maximum * 2 / 3;
 }
 
+
+bool KItemListView::scrollBarRequired(const QSizeF& size) const
+{
+    const QSizeF oldSize = m_layouter->size();
+
+    m_layouter->setSize(size);
+    const qreal maxOffset = m_layouter->maximumScrollOffset();
+    m_layouter->setSize(oldSize);
+
+    return m_layouter->scrollOrientation() == Qt::Vertical ? maxOffset > size.height()
+                                                           : maxOffset > size.width();
+}
+
 int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
 {
     int inc = 0;
 int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
 {
     int inc = 0;
index 9c34daba3fa5e3459bbd4497bde0f28ad746943b..e675df2211e946a2223c127de142282bd716c2f0 100644 (file)
@@ -461,6 +461,13 @@ private:
      */
     bool animateChangedItemCount(int changedItemCount) const;
 
      */
     bool animateChangedItemCount(int changedItemCount) const;
 
+    /**
+     * @return True if a scrollbar for the given scroll-orientation is required
+     *         when using a size of \p size for the view. Calling the method is rather
+     *         expansive as a temporary relayout needs to be done.
+     */
+    bool scrollBarRequired(const QSizeF& size) const;
+
     /**
      * Helper function for triggerAutoScrolling().
      * @param pos    Logical position of the mouse relative to the range.
     /**
      * Helper function for triggerAutoScrolling().
      * @param pos    Logical position of the mouse relative to the range.
@@ -512,6 +519,7 @@ private:
     KItemListHeader* m_header;
     bool m_useHeaderWidths;
 
     KItemListHeader* m_header;
     bool m_useHeaderWidths;
 
+    friend class KItemListContainer; // Accesses scrollBarRequired()
     friend class KItemListController;
     friend class KItemListControllerTest;
 };
     friend class KItemListController;
     friend class KItemListControllerTest;
 };