From: Peter Penz Date: Sun, 5 Feb 2012 18:14:17 +0000 (+0100) Subject: Fix potential endless loop in layout X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/7af39fb960352e0504153c627db0615d80758ebe?ds=sidebyside Fix potential endless loop in layout 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 --- diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index 58f2e3cd6..b480b4494 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -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 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); + + 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) { diff --git a/src/kitemviews/kitemlistcontainer.h b/src/kitemviews/kitemlistcontainer.h index 4d6eadbbb..b41f48a7f 100644 --- a/src/kitemviews/kitemlistcontainer.h +++ b/src/kitemviews/kitemlistcontainer.h @@ -70,6 +70,13 @@ private: 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; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index c671a2e6e..52d857705 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -1880,6 +1880,19 @@ bool KItemListView::animateChangedItemCount(int changedItemCount) const 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; diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 9c34daba3..e675df221 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -461,6 +461,13 @@ private: */ 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. @@ -512,6 +519,7 @@ private: KItemListHeader* m_header; bool m_useHeaderWidths; + friend class KItemListContainer; // Accesses scrollBarRequired() friend class KItemListController; friend class KItemListControllerTest; };