From: Peter Penz Date: Sun, 25 Sep 2011 17:52:33 +0000 (+0200) Subject: Provide scrollbar for large items X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/aee65350437770b22b289e2c7ec5a5a4436e39a6?ds=inline Provide scrollbar for large items If an item does not fit into the available width/height a scrollbar should be provided (e.g. typically this represents the horizontal scrollbar in the details-view where the width can be larger than the than the visible width). Currently the interaction with the scrollbar is not implemented but this will be a quite minor task in comparison to this patch. --- diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 68bd7bde9..50f28fe5b 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -167,7 +167,7 @@ QSizeF KFileItemListView::itemSizeHint(int index) const return QSize(); } -QHash KFileItemListView::visibleRoleSizes() const +QHash KFileItemListView::visibleRolesSizes() const { QElapsedTimer timer; timer.start(); @@ -293,7 +293,7 @@ void KFileItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& p triggerVisibleIndexRangeUpdate(); } -void KFileItemListView::onOffsetChanged(qreal current, qreal previous) +void KFileItemListView::onScrollOffsetChanged(qreal current, qreal previous) { Q_UNUSED(current); Q_UNUSED(previous); @@ -353,7 +353,6 @@ void KFileItemListView::resizeEvent(QGraphicsSceneResizeEvent* event) { KItemListView::resizeEvent(event); triggerVisibleIndexRangeUpdate(); - markVisibleRolesSizesAsDirty(); } void KFileItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) @@ -435,8 +434,6 @@ QSizeF KFileItemListView::visibleRoleSizeHint(int index, const QByteArray& role) } if (role == "name") { - Q_ASSERT(values.contains("expansionLevel")); - // Increase the width by the expansion-toggle and the current expansion level const int expansionLevel = values.value("expansionLevel", 0).toInt(); width += option.margin + expansionLevel * itemSize().height() + KIconLoader::SizeSmall; diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index 77bfa21ed..696322f8f 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -61,7 +61,7 @@ public: virtual QSizeF itemSizeHint(int index) const; /** @reimp */ - virtual QHash visibleRoleSizes() const; + virtual QHash visibleRolesSizes() const; /** @reimp */ virtual QPixmap createDragPixmap(const QSet& indexes) const; @@ -72,7 +72,7 @@ protected: virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous); virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous); - virtual void onOffsetChanged(qreal current, qreal previous); + virtual void onScrollOffsetChanged(qreal current, qreal previous); virtual void onVisibleRolesChanged(const QList& current, const QList& previous); virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous); virtual void onTransactionBegin(); diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index 65ddcb545..3237187b4 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -122,7 +122,7 @@ void KItemListContainer::scrollContentsBy(int dx, int dy) const QScrollBar* scrollBar = (view->scrollOrientation() == Qt::Vertical) ? verticalScrollBar() : horizontalScrollBar(); - const qreal currentOffset = view->offset(); + const qreal currentOffset = view->scrollOffset(); if (static_cast(currentOffset) == scrollBar->value()) { // The current offset is already synchronous to the scrollbar return; @@ -156,9 +156,9 @@ void KItemListContainer::scrollContentsBy(int dx, int dy) m_smoothScrollingAnimation->setEndValue(endOffset); m_smoothScrollingAnimation->setEasingCurve(animRunning ? QEasingCurve::OutQuad : QEasingCurve::InOutQuad); m_smoothScrollingAnimation->start(); - view->setOffset(startOffset); + view->setScrollOffset(startOffset); } else { - view->setOffset(endOffset); + view->setScrollOffset(endOffset); } } @@ -238,16 +238,20 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* QGraphicsScene* scene = static_cast(viewport())->scene(); if (previous) { scene->removeItem(previous); - disconnect(previous, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); - disconnect(previous, SIGNAL(maximumOffsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); - disconnect(previous, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); + disconnect(previous, SIGNAL(scrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar())); + disconnect(previous, SIGNAL(maximumScrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar())); + disconnect(previous, SIGNAL(itemOffsetChanged(qreal,qreal)), this, SLOT(updateItemOffsetScrollBar())); + disconnect(previous, SIGNAL(maximumItemOffsetChanged(qreal,qreal)), this, SLOT(updateItemOffsetScrollBar())); + disconnect(previous, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); m_smoothScrollingAnimation->setTargetObject(0); } if (current) { scene->addItem(current); - connect(current, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); - connect(current, SIGNAL(maximumOffsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); - connect(current, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); + connect(current, SIGNAL(scrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar())); + connect(current, SIGNAL(maximumScrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar())); + connect(current, SIGNAL(itemOffsetChanged(qreal,qreal)), this, SLOT(updateItemOffsetScrollBar())); + connect(current, SIGNAL(maximumItemOffsetChanged(qreal,qreal)), this, SLOT(updateItemOffsetScrollBar())); + connect(current, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); m_smoothScrollingAnimation->setTargetObject(current); } } @@ -275,33 +279,30 @@ void KItemListContainer::scrollTo(qreal offset) scrollBar->setValue(offset); } -void KItemListContainer::updateScrollBars() +void KItemListContainer::updateScrollOffsetScrollBar() { const KItemListView* view = m_controller->view(); if (!view) { return; } - QScrollBar* scrollBar = 0; + QScrollBar* scrollOffsetScrollBar = 0; int singleStep = 0; int pageStep = 0; - QScrollBar* otherScrollBar = 0; if (view->scrollOrientation() == Qt::Vertical) { - scrollBar = verticalScrollBar(); + scrollOffsetScrollBar = verticalScrollBar(); singleStep = view->itemSize().height(); pageStep = view->size().height(); - otherScrollBar = horizontalScrollBar(); } else { - scrollBar = horizontalScrollBar(); + scrollOffsetScrollBar = horizontalScrollBar(); singleStep = view->itemSize().width(); pageStep = view->size().width(); - otherScrollBar = verticalScrollBar(); } - const int value = view->offset(); - const int maximum = qMax(0, int(view->maximumOffset() - pageStep)); + const int value = view->scrollOffset(); + const int maximum = qMax(0, int(view->maximumScrollOffset() - pageStep)); if (m_smoothScrollingAnimation->state() == QAbstractAnimation::Running) { - if (maximum == scrollBar->maximum()) { + if (maximum == scrollOffsetScrollBar->maximum()) { // The value has been changed by the animation, no update // of the scrollbars is required as their target state will be // reached with the end of the animation. @@ -314,15 +315,41 @@ void KItemListContainer::updateScrollBars() m_smoothScrollingAnimation->stop(); } - scrollBar->setSingleStep(singleStep); - scrollBar->setPageStep(pageStep); - scrollBar->setMinimum(0); - scrollBar->setMaximum(maximum); - scrollBar->setValue(value); + scrollOffsetScrollBar->setSingleStep(singleStep); + scrollOffsetScrollBar->setPageStep(pageStep); + scrollOffsetScrollBar->setMinimum(0); + scrollOffsetScrollBar->setMaximum(maximum); + scrollOffsetScrollBar->setValue(value); +} + +void KItemListContainer::updateItemOffsetScrollBar() +{ + const KItemListView* view = m_controller->view(); + if (!view) { + return; + } + + QScrollBar* itemOffsetScrollBar = 0; + int singleStep = 0; + int pageStep = 0; + if (view->scrollOrientation() == Qt::Vertical) { + itemOffsetScrollBar = horizontalScrollBar(); + singleStep = view->itemSize().width() / 10; + pageStep = view->size().width(); + } else { + itemOffsetScrollBar = verticalScrollBar(); + singleStep = view->itemSize().height() / 10; + pageStep = view->size().height(); + } + + const int value = view->itemOffset(); + const int maximum = qMax(0, int(view->maximumItemOffset() - pageStep)); - // Make sure that the other scroll bar is hidden - otherScrollBar->setMaximum(0); - otherScrollBar->setValue(0); + itemOffsetScrollBar->setSingleStep(singleStep); + itemOffsetScrollBar->setPageStep(pageStep); + itemOffsetScrollBar->setMinimum(0); + itemOffsetScrollBar->setMaximum(maximum); + itemOffsetScrollBar->setValue(value); } void KItemListContainer::updateGeometries() @@ -344,7 +371,8 @@ void KItemListContainer::updateGeometries() static_cast(viewport())->scene()->setSceneRect(0, 0, rect.width(), rect.height()); static_cast(viewport())->viewport()->setGeometry(QRect(0, 0, rect.width(), rect.height())); - updateScrollBars(); + updateScrollOffsetScrollBar(); + updateItemOffsetScrollBar(); } void KItemListContainer::initialize() @@ -361,7 +389,7 @@ void KItemListContainer::initialize() QGraphicsView* graphicsView = new KItemListContainerViewport(new QGraphicsScene(this), this); setViewport(graphicsView); - m_smoothScrollingAnimation = new QPropertyAnimation(this, "offset"); + m_smoothScrollingAnimation = new QPropertyAnimation(this, "scrollOffset"); m_smoothScrollingAnimation->setDuration(300); connect(m_smoothScrollingAnimation, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)), this, SLOT(slotAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); diff --git a/src/kitemviews/kitemlistcontainer.h b/src/kitemviews/kitemlistcontainer.h index 333f01de7..36ac9753e 100644 --- a/src/kitemviews/kitemlistcontainer.h +++ b/src/kitemviews/kitemlistcontainer.h @@ -62,7 +62,8 @@ private slots: void slotViewChanged(KItemListView* current, KItemListView* previous); void slotAnimationStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); void scrollTo(qreal offset); - void updateScrollBars(); + void updateScrollOffsetScrollBar(); + void updateItemOffsetScrollBar(); private: void initialize(); diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 4a81eaaa5..13ced1aac 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -91,7 +91,7 @@ void KItemListController::setView(KItemListView* view) KItemListView* oldView = m_view; if (oldView) { - disconnect(oldView, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); + disconnect(oldView, SIGNAL(scrollOffsetChanged(qreal,qreal)), this, SLOT(slotViewScrollOffsetChanged(qreal,qreal))); } m_view = view; @@ -99,7 +99,7 @@ void KItemListController::setView(KItemListView* view) if (m_view) { m_view->setController(this); m_view->setModel(m_model); - connect(m_view, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); + connect(m_view, SIGNAL(scrollOffsetChanged(qreal,qreal)), this, SLOT(slotViewScrollOffsetChanged(qreal,qreal))); } emit viewChanged(m_view, oldView); @@ -331,14 +331,14 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const KItemListRubberBand* rubberBand = m_view->rubberBand(); QPointF startPos = m_pressedMousePos; if (m_view->scrollOrientation() == Qt::Vertical) { - startPos.ry() += m_view->offset(); + startPos.ry() += m_view->scrollOffset(); if (m_view->itemSize().width() < 0) { // Use a special rubberband for views that have only one column and // expand the rubberband to use the whole width of the view. startPos.setX(0); } } else { - startPos.rx() += m_view->offset(); + startPos.rx() += m_view->scrollOffset(); } m_oldSelection = m_selectionManager->selectedItems(); @@ -371,14 +371,14 @@ bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const if (rubberBand->isActive()) { QPointF endPos = transform.map(event->pos()); if (m_view->scrollOrientation() == Qt::Vertical) { - endPos.ry() += m_view->offset(); + endPos.ry() += m_view->scrollOffset(); if (m_view->itemSize().width() < 0) { // Use a special rubberband for views that have only one column and // expand the rubberband to use the whole width of the view. endPos.setX(m_view->size().width()); } } else { - endPos.rx() += m_view->offset(); + endPos.rx() += m_view->scrollOffset(); } rubberBand->setEndPosition(endPos); } @@ -625,7 +625,7 @@ bool KItemListController::processEvent(QEvent* event, const QTransform& transfor return false; } -void KItemListController::slotViewOffsetChanged(qreal current, qreal previous) +void KItemListController::slotViewScrollOffsetChanged(qreal current, qreal previous) { if (!m_view) { return; @@ -662,9 +662,9 @@ void KItemListController::slotRubberBandChanged() const bool scrollVertical = (m_view->scrollOrientation() == Qt::Vertical); if (scrollVertical) { - rubberBandRect.translate(0, -m_view->offset()); + rubberBandRect.translate(0, -m_view->scrollOffset()); } else { - rubberBandRect.translate(-m_view->offset(), 0); + rubberBandRect.translate(-m_view->scrollOffset(), 0); } if (!m_oldSelection.isEmpty()) { diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index 80c750581..8ef045ea3 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -135,7 +135,7 @@ signals: void viewChanged(KItemListView* current, KItemListView* previous); private slots: - void slotViewOffsetChanged(qreal current, qreal previous); + void slotViewScrollOffsetChanged(qreal current, qreal previous); /** * Is invoked when the rubberband boundaries have been changed and will select diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 0a346b094..6d96c0999 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -69,8 +69,10 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_layouter(0), m_animation(0), m_layoutTimer(0), - m_oldOffset(0), - m_oldMaximumOffset(0), + m_oldScrollOffset(0), + m_oldMaximumScrollOffset(0), + m_oldItemOffset(0), + m_oldMaximumItemOffset(0), m_skipAutoScrollForRubberBand(false), m_rubberBand(0), m_mousePos(), @@ -133,12 +135,14 @@ void KItemListView::setItemSize(const QSizeF& itemSize) m_itemSize = itemSize; - if (!markVisibleRolesSizesAsDirty()) { - if (itemSize.width() < previousSize.width() || itemSize.height() < previousSize.height()) { - prepareLayoutForIncreasedItemCount(itemSize, ItemSize); - } else { - m_layouter->setItemSize(itemSize); - } + if (itemSize.isEmpty()) { + updateVisibleRoleSizes(); + } + + if (itemSize.width() < previousSize.width() || itemSize.height() < previousSize.height()) { + prepareLayoutForIncreasedItemCount(itemSize, ItemSize); + } else { + m_layouter->setItemSize(itemSize); } m_sizeHintResolver->clearCache(); @@ -151,34 +155,49 @@ QSizeF KItemListView::itemSize() const return m_itemSize; } -void KItemListView::setOffset(qreal offset) +void KItemListView::setScrollOffset(qreal offset) { if (offset < 0) { offset = 0; } - const qreal previousOffset = m_layouter->offset(); + const qreal previousOffset = m_layouter->scrollOffset(); if (offset == previousOffset) { return; } - m_layouter->setOffset(offset); - m_animation->setOffset(offset); + m_layouter->setScrollOffset(offset); + m_animation->setScrollOffset(offset); if (!m_layoutTimer->isActive()) { doLayout(NoAnimation, 0, 0); update(); } - onOffsetChanged(offset, previousOffset); + onScrollOffsetChanged(offset, previousOffset); +} + +qreal KItemListView::scrollOffset() const +{ + return m_layouter->scrollOffset(); +} + +qreal KItemListView::maximumScrollOffset() const +{ + return m_layouter->maximumScrollOffset(); +} + +void KItemListView::setItemOffset(qreal offset) +{ + m_layouter->setItemOffset(offset); } -qreal KItemListView::offset() const +qreal KItemListView::itemOffset() const { - return m_layouter->offset(); + return m_layouter->itemOffset(); } -qreal KItemListView::maximumOffset() const +qreal KItemListView::maximumItemOffset() const { - return m_layouter->maximumOffset(); + return m_layouter->maximumItemOffset(); } void KItemListView::setVisibleRoles(const QList& roles) @@ -198,7 +217,7 @@ void KItemListView::setVisibleRoles(const QList& roles) m_layouter->markAsDirty(); onVisibleRolesChanged(roles, previousRoles); - markVisibleRolesSizesAsDirty(); + updateVisibleRoleSizes(); updateLayout(); if (m_header) { @@ -320,10 +339,6 @@ void KItemListView::setGeometry(const QRectF& rect) return; } - if (m_itemSize.isEmpty()) { - m_layouter->setItemSize(QSizeF()); - } - if (m_model->count() > 0) { prepareLayoutForIncreasedItemCount(rect.size(), LayouterSize); } else { @@ -333,6 +348,8 @@ void KItemListView::setGeometry(const QRectF& rect) if (!m_layoutTimer->isActive()) { m_layoutTimer->start(); } + + updateVisibleRoleSizes(); } int KItemListView::itemAt(const QPointF& pos) const @@ -387,7 +404,7 @@ QSizeF KItemListView::itemSizeHint(int index) const return itemSize(); } -QHash KItemListView::visibleRoleSizes() const +QHash KItemListView::visibleRolesSizes() const { return QHash(); } @@ -445,9 +462,9 @@ void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt const QPointF topLeft = rubberBandRect.topLeft(); if (scrollOrientation() == Qt::Vertical) { - rubberBandRect.moveTo(topLeft.x(), topLeft.y() - offset()); + rubberBandRect.moveTo(topLeft.x(), topLeft.y() - scrollOffset()); } else { - rubberBandRect.moveTo(topLeft.x() - offset(), topLeft.y()); + rubberBandRect.moveTo(topLeft.x() - scrollOffset(), topLeft.y()); } QStyleOptionRubberBand opt; @@ -494,7 +511,7 @@ void KItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& previ Q_UNUSED(previous); } -void KItemListView::onOffsetChanged(qreal current, qreal previous) +void KItemListView::onScrollOffsetChanged(qreal current, qreal previous) { Q_UNUSED(current); Q_UNUSED(previous); @@ -585,19 +602,9 @@ void KItemListView::resizeEvent(QGraphicsSceneResizeEvent* event) updateHeaderWidth(); } -bool KItemListView::markVisibleRolesSizesAsDirty() -{ - const bool dirty = m_itemSize.isEmpty(); - if (dirty && !m_useHeaderWidths) { - m_visibleRolesSizes.clear(); - m_layouter->setItemSize(QSizeF()); - } - return dirty; -} - void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) { - markVisibleRolesSizesAsDirty(); + updateVisibleRoleSizes(); const bool hasMultipleRanges = (itemRanges.count() > 1); if (hasMultipleRanges) { @@ -641,7 +648,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) } m_layouter->markAsDirty(); - if (m_model->count() == count && maximumOffset() > size().height()) { + if (m_model->count() == count && maximumScrollOffset() > size().height()) { kDebug() << "Scrollbar required, skipping layout"; const int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent); QSizeF layouterSize = m_layouter->size(); @@ -670,7 +677,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) { - markVisibleRolesSizesAsDirty(); + updateVisibleRoleSizes(); const bool hasMultipleRanges = (itemRanges.count() > 1); if (hasMultipleRanges) { @@ -754,7 +761,7 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, { const bool updateSizeHints = itemSizeHintUpdateRequired(roles); if (updateSizeHints) { - markVisibleRolesSizesAsDirty(); + updateVisibleRoleSizes(); } foreach (const KItemRange& itemRange, itemRanges) { @@ -802,7 +809,7 @@ void KItemListView::slotCurrentChanged(int current, int previous) if (!viewGeometry.contains(currentBoundingRect)) { // Make sure that the new current item is fully visible in the view. - qreal newOffset = offset(); + qreal newOffset = scrollOffset(); if (currentBoundingRect.top() < viewGeometry.top()) { Q_ASSERT(scrollOrientation() == Qt::Vertical); newOffset += currentBoundingRect.top() - viewGeometry.top(); @@ -819,7 +826,7 @@ void KItemListView::slotCurrentChanged(int current, int previous) } } - if (newOffset != offset()) { + if (newOffset != scrollOffset()) { emit scrollTo(newOffset); } } @@ -917,10 +924,10 @@ void KItemListView::slotVisibleRoleWidthChanged(const QByteArray& role, QSizeF roleSize = m_visibleRolesSizes.value(role); roleSize.setWidth(currentWidth); m_visibleRolesSizes.insert(role, roleSize); - } - m_layouter->setItemSize(QSizeF()); // Forces an update in applyDynamicItemSize() - updateLayout(); + updateVisibleRoleSizes(); + updateLayout(); + } } void KItemListView::triggerAutoScrolling() @@ -973,7 +980,7 @@ void KItemListView::triggerAutoScrolling() // the autoscrolling may not get skipped anymore until a new rubberband is created m_skipAutoScrollForRubberBand = false; - setOffset(offset() + m_autoScrollIncrement); + setScrollOffset(scrollOffset() + m_autoScrollIncrement); // Trigger the autoscroll timer which will periodically call // triggerAutoScrolling() @@ -1057,7 +1064,7 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha return; } - applyDynamicItemSize(); + //markVisibleRolesSizesAsDirty(); const int firstVisibleIndex = m_layouter->firstVisibleIndex(); const int lastVisibleIndex = m_layouter->lastVisibleIndex(); @@ -1066,13 +1073,13 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha return; } - // Do a sanity check of the offset-property: When properties of the itemlist-view have been changed + // Do a sanity check of the scroll-offset property: When properties of the itemlist-view have been changed // it might be possible that the maximum offset got changed too. Assure that the full visible range // is still shown if the maximum offset got decreased. const qreal visibleOffsetRange = (scrollOrientation() == Qt::Horizontal) ? size().width() : size().height(); - const qreal maxOffsetToShowFullRange = maximumOffset() - visibleOffsetRange; - if (offset() > maxOffsetToShowFullRange) { - m_layouter->setOffset(qMax(qreal(0), maxOffsetToShowFullRange)); + const qreal maxOffsetToShowFullRange = maximumScrollOffset() - visibleOffsetRange; + if (scrollOffset() > maxOffsetToShowFullRange) { + m_layouter->setScrollOffset(qMax(qreal(0), maxOffsetToShowFullRange)); } // Determine all items that are completely invisible and might be @@ -1187,16 +1194,28 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha void KItemListView::emitOffsetChanges() { - const qreal newOffset = m_layouter->offset(); - if (m_oldOffset != newOffset) { - emit offsetChanged(newOffset, m_oldOffset); - m_oldOffset = newOffset; + const qreal newScrollOffset = m_layouter->scrollOffset(); + if (m_oldScrollOffset != newScrollOffset) { + emit scrollOffsetChanged(newScrollOffset, m_oldScrollOffset); + m_oldScrollOffset = newScrollOffset; + } + + const qreal newMaximumScrollOffset = m_layouter->maximumScrollOffset(); + if (m_oldMaximumScrollOffset != newMaximumScrollOffset) { + emit maximumScrollOffsetChanged(newMaximumScrollOffset, m_oldMaximumScrollOffset); + m_oldMaximumScrollOffset = newMaximumScrollOffset; } - const qreal newMaximumOffset = m_layouter->maximumOffset(); - if (m_oldMaximumOffset != newMaximumOffset) { - emit maximumOffsetChanged(newMaximumOffset, m_oldMaximumOffset); - m_oldMaximumOffset = newMaximumOffset; + const qreal newItemOffset = m_layouter->itemOffset(); + if (m_oldItemOffset != newItemOffset) { + emit itemOffsetChanged(newItemOffset, m_oldItemOffset); + m_oldItemOffset = newItemOffset; + } + + const qreal newMaximumItemOffset = m_layouter->maximumItemOffset(); + if (m_oldMaximumItemOffset != newMaximumItemOffset) { + emit maximumItemOffsetChanged(newMaximumItemOffset, m_oldMaximumItemOffset); + m_oldMaximumItemOffset = newMaximumItemOffset; } } @@ -1317,50 +1336,6 @@ void KItemListView::setLayouterSize(const QSizeF& size, SizeType sizeType) } } -void KItemListView::applyDynamicItemSize() -{ - if (!m_itemSize.isEmpty()) { - return; - } - - if (m_visibleRolesSizes.isEmpty()) { - m_visibleRolesSizes = visibleRoleSizes(); - if (m_header) { - m_header->setVisibleRolesWidths(headerRolesWidths()); - } - } - - if (m_layouter->itemSize().isEmpty()) { - // Calculate the maximum size of an item by considering the - // visible role sizes and apply them to the layouter. - qreal requiredWidth = 0; - qreal requiredHeight = 0; - - QHashIterator it(m_visibleRolesSizes); - while (it.hasNext()) { - it.next(); - const QSizeF& visibleRoleSize = it.value(); - requiredWidth += visibleRoleSize.width(); - requiredHeight += visibleRoleSize.height(); - } - - QSizeF dynamicItemSize = m_itemSize; - if (dynamicItemSize.width() <= 0) { - dynamicItemSize.setWidth(qMax(requiredWidth, size().width())); - } - if (dynamicItemSize.height() <= 0) { - dynamicItemSize.setHeight(qMax(requiredHeight, size().height())); - } - - m_layouter->setItemSize(dynamicItemSize); - - // Update the role sizes for all visible widgets - foreach (KItemListWidget* widget, visibleItemListWidgets()) { - widget->setVisibleRolesSizes(m_visibleRolesSizes); - } - } -} - void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index) { widget->setVisibleRoles(m_visibleRoles); @@ -1406,6 +1381,46 @@ QHash KItemListView::headerRolesWidths() const return rolesWidths; } +void KItemListView::updateVisibleRoleSizes() +{ + if (!m_itemSize.isEmpty() || m_useHeaderWidths) { + return; + } + + m_visibleRolesSizes = visibleRolesSizes(); + if (m_header) { + m_header->setVisibleRolesWidths(headerRolesWidths()); + } + + // Calculate the maximum size of an item by considering the + // visible role sizes and apply them to the layouter. + qreal requiredWidth = 0; + qreal requiredHeight = 0; + + QHashIterator it(m_visibleRolesSizes); + while (it.hasNext()) { + it.next(); + const QSizeF& visibleRoleSize = it.value(); + requiredWidth += visibleRoleSize.width(); + requiredHeight += visibleRoleSize.height(); + } + + QSizeF dynamicItemSize = m_itemSize; + if (dynamicItemSize.width() <= 0) { + dynamicItemSize.setWidth(qMax(requiredWidth, size().width())); + } + if (dynamicItemSize.height() <= 0) { + dynamicItemSize.setHeight(qMax(requiredHeight, size().height())); + } + + m_layouter->setItemSize(dynamicItemSize); + + // Update the role sizes for all visible widgets + foreach (KItemListWidget* widget, visibleItemListWidgets()) { + widget->setVisibleRolesSizes(m_visibleRolesSizes); + } +} + int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc) { int inc = 0; @@ -1433,6 +1448,7 @@ int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldIn } + KItemListCreatorBase::~KItemListCreatorBase() { qDeleteAll(m_recycleableWidgets); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 75a298a1e..d6b0d5a77 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -65,7 +65,7 @@ class LIBDOLPHINPRIVATE_EXPORT KItemListView : public QGraphicsWidget { Q_OBJECT - Q_PROPERTY(qreal offset READ offset WRITE setOffset) + Q_PROPERTY(qreal scrollOffset READ scrollOffset WRITE setScrollOffset) public: KItemListView(QGraphicsWidget* parent = 0); @@ -78,10 +78,15 @@ public: QSizeF itemSize() const; // TODO: add note that offset is not checked against maximumOffset, only against 0. - void setOffset(qreal offset); - qreal offset() const; + void setScrollOffset(qreal offset); + qreal scrollOffset() const; - qreal maximumOffset() const; + qreal maximumScrollOffset() const; + + void setItemOffset(qreal scrollOffset); + qreal itemOffset() const; + + qreal maximumItemOffset() const; void setVisibleRoles(const QList& roles); QList visibleRoles() const; @@ -159,7 +164,7 @@ public: * is empty. This allows to have dynamic but equal role sizes between * all items. Per default an empty hash is returned. */ - virtual QHash visibleRoleSizes() const; + virtual QHash visibleRolesSizes() const; /** * @return The bounding rectangle of the item relative to the top/left of @@ -193,8 +198,10 @@ public: virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); signals: - void offsetChanged(qreal current, qreal previous); - void maximumOffsetChanged(qreal current, qreal previous); + void scrollOffsetChanged(qreal current, qreal previous); + void maximumScrollOffsetChanged(qreal current, qreal previous); + void itemOffsetChanged(qreal current, qreal previous); + void maximumItemOffsetChanged(qreal current, qreal previous); void scrollTo(qreal newOffset); protected: @@ -215,7 +222,7 @@ protected: virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous); - virtual void onOffsetChanged(qreal current, qreal previous); + virtual void onScrollOffsetChanged(qreal current, qreal previous); virtual void onVisibleRolesChanged(const QList& current, const QList& previous); virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous); @@ -232,15 +239,6 @@ protected: QList visibleItemListWidgets() const; - /** - * Marks the visible roles as dirty so that they will get updated when doing the next - * layout. The visible roles will only get marked as dirty if an empty item-size is - * given and if the roles have not already been customized by the user by adjusting - * the view-header. - * @return True if the visible roles have been marked as dirty. - */ - bool markVisibleRolesSizesAsDirty(); - /** @reimp */ virtual void resizeEvent(QGraphicsSceneResizeEvent* event); @@ -320,12 +318,6 @@ private: */ void setLayouterSize(const QSizeF& size, SizeType sizeType); - /** - * Updates the m_visibleRoleSizes property and applies the dynamic - * size to the layouter. - */ - void applyDynamicItemSize(); - /** * Helper method for createWidget() and setWidgetIndex() to update the properties * of the itemlist widget. @@ -343,6 +335,13 @@ private: */ QHash headerRolesWidths() const; + /** + * Updates m_visibleRoleSizes by calling KItemListView::visibleRoleSizes() + * if the m_itemRect is empty and no custom header-widths are used + * (see m_useHeaderWidths). + */ + void updateVisibleRoleSizes(); + /** * Helper function for triggerAutoScrolling(). * @param pos Logical position of the mouse relative to the range. @@ -377,8 +376,10 @@ private: KItemListViewAnimation* m_animation; QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call. - qreal m_oldOffset; - qreal m_oldMaximumOffset; + qreal m_oldScrollOffset; + qreal m_oldMaximumScrollOffset; + qreal m_oldItemOffset; + qreal m_oldMaximumItemOffset; bool m_skipAutoScrollForRubberBand; KItemListRubberBand* m_rubberBand; diff --git a/src/kitemviews/kitemlistviewanimation.cpp b/src/kitemviews/kitemlistviewanimation.cpp index 449d557f9..9b122ee8c 100644 --- a/src/kitemviews/kitemlistviewanimation.cpp +++ b/src/kitemviews/kitemlistviewanimation.cpp @@ -29,7 +29,7 @@ KItemListViewAnimation::KItemListViewAnimation(QObject* parent) : QObject(parent), m_scrollOrientation(Qt::Vertical), - m_offset(0), + m_scrollOffset(0), m_animation() { } @@ -51,10 +51,10 @@ Qt::Orientation KItemListViewAnimation::scrollOrientation() const return m_scrollOrientation; } -void KItemListViewAnimation::setOffset(qreal offset) +void KItemListViewAnimation::setScrollOffset(qreal offset) { - const qreal diff = m_offset - offset; - m_offset = offset; + const qreal diff = m_scrollOffset - offset; + m_scrollOffset = offset; // The change of the offset requires that the position of all // animated QGraphicsWidgets get adjusted. An exception is made @@ -108,9 +108,9 @@ void KItemListViewAnimation::setOffset(qreal offset) } } -qreal KItemListViewAnimation::offset() const +qreal KItemListViewAnimation::scrollOffset() const { - return m_offset; + return m_scrollOffset; } void KItemListViewAnimation::start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue) diff --git a/src/kitemviews/kitemlistviewanimation_p.h b/src/kitemviews/kitemlistviewanimation_p.h index 0bf54d296..b3a95a871 100644 --- a/src/kitemviews/kitemlistviewanimation_p.h +++ b/src/kitemviews/kitemlistviewanimation_p.h @@ -49,8 +49,8 @@ public: void setScrollOrientation(Qt::Orientation orientation); Qt::Orientation scrollOrientation() const; - void setOffset(qreal offset); - qreal offset() const; + void setScrollOffset(qreal scrollOffset); + qreal scrollOffset() const; void start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue = QVariant()); @@ -70,7 +70,7 @@ private: enum { AnimationTypeCount = 4 }; Qt::Orientation m_scrollOrientation; - qreal m_offset; + qreal m_scrollOffset; QHash m_animation[AnimationTypeCount]; }; diff --git a/src/kitemviews/kitemlistviewlayouter.cpp b/src/kitemviews/kitemlistviewlayouter.cpp index eaf175a51..f829824f0 100644 --- a/src/kitemviews/kitemlistviewlayouter.cpp +++ b/src/kitemviews/kitemlistviewlayouter.cpp @@ -42,8 +42,10 @@ KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : m_headerHeight(0), m_model(0), m_sizeHintResolver(0), - m_offset(0), - m_maximumOffset(0), + m_scrollOffset(0), + m_maximumScrollOffset(0), + m_itemOffset(0), + m_maximumItemOffset(0), m_firstVisibleIndex(-1), m_lastVisibleIndex(-1), m_firstVisibleGroupIndex(-1), @@ -112,17 +114,42 @@ qreal KItemListViewLayouter::headerHeight() const return m_headerHeight; } -void KItemListViewLayouter::setOffset(qreal offset) +void KItemListViewLayouter::setScrollOffset(qreal offset) { - if (m_offset != offset) { - m_offset = offset; + if (m_scrollOffset != offset) { + m_scrollOffset = offset; m_visibleIndexesDirty = true; } } -qreal KItemListViewLayouter::offset() const +qreal KItemListViewLayouter::scrollOffset() const { - return m_offset; + return m_scrollOffset; +} + +qreal KItemListViewLayouter::maximumScrollOffset() const +{ + const_cast(this)->doLayout(); + return m_maximumScrollOffset; +} + +void KItemListViewLayouter::setItemOffset(qreal offset) +{ + if (m_itemOffset != offset) { + m_itemOffset = offset; + m_visibleIndexesDirty = true; + } +} + +qreal KItemListViewLayouter::itemOffset() const +{ + return m_itemOffset; +} + +qreal KItemListViewLayouter::maximumItemOffset() const +{ + const_cast(this)->doLayout(); + return m_maximumItemOffset; } void KItemListViewLayouter::setModel(const KItemModelBase* model) @@ -151,12 +178,6 @@ const KItemListSizeHintResolver* KItemListViewLayouter::sizeHintResolver() const return m_sizeHintResolver; } -qreal KItemListViewLayouter::maximumOffset() const -{ - const_cast(this)->doLayout(); - return m_maximumOffset; -} - int KItemListViewLayouter::firstVisibleIndex() const { const_cast(this)->doLayout(); @@ -182,15 +203,13 @@ QRectF KItemListViewLayouter::itemBoundingRect(int index) const const QRectF& b = m_itemBoundingRects[index]; QRectF bounds(b.y(), b.x(), b.height(), b.width()); QPointF pos = bounds.topLeft(); - pos.rx() -= m_offset; + pos.rx() -= m_scrollOffset; bounds.moveTo(pos); return bounds; } QRectF bounds = m_itemBoundingRects[index]; - QPointF pos = bounds.topLeft(); - pos.ry() -= m_offset; - bounds.moveTo(pos); + bounds.moveTo(bounds.topLeft() - QPointF(m_itemOffset, m_scrollOffset)); return bounds; } @@ -251,9 +270,11 @@ void KItemListViewLayouter::doLayout() if (itemCount > m_columnCount) { // Apply the unused width equally to each column const qreal unusedWidth = size.width() - m_columnCount * m_columnWidth; - const qreal columnInc = unusedWidth / (m_columnCount + 1); - m_columnWidth += columnInc; - m_xPosInc += columnInc; + if (unusedWidth > 0) { + const qreal columnInc = unusedWidth / (m_columnCount + 1); + m_columnWidth += columnInc; + m_xPosInc += columnInc; + } } int rowCount = itemCount / m_columnCount; @@ -303,7 +324,13 @@ void KItemListViewLayouter::doLayout() m_itemBoundingRects.end()); } - m_maximumOffset = (itemCount > 0) ? m_itemBoundingRects.last().bottom() : 0; + if (itemCount > 0) { + m_maximumScrollOffset = m_itemBoundingRects.last().bottom(); + m_maximumItemOffset = m_columnCount * m_columnWidth; + } else { + m_maximumScrollOffset = 0; + m_maximumItemOffset = 0; + } m_grouped = !m_model->groupRole().isEmpty(); /*if (m_grouped) { @@ -354,7 +381,7 @@ void KItemListViewLayouter::updateVisibleIndexes() // Calculate the first visible index: // 1. Guess the index by using the minimum row height const int maxIndex = m_model->count() - 1; - m_firstVisibleIndex = int(m_offset / minimumHeight) * m_columnCount; + m_firstVisibleIndex = int(m_scrollOffset / minimumHeight) * m_columnCount; // 2. Decrease the index by checking the real row heights int prevRowIndex = m_firstVisibleIndex - m_columnCount; @@ -362,7 +389,7 @@ void KItemListViewLayouter::updateVisibleIndexes() prevRowIndex -= m_columnCount; } - const qreal top = m_offset + m_headerHeight; + const qreal top = m_scrollOffset + m_headerHeight; while (prevRowIndex >= 0 && m_itemBoundingRects[prevRowIndex].bottom() >= top) { m_firstVisibleIndex = prevRowIndex; prevRowIndex -= m_columnCount; @@ -371,7 +398,7 @@ void KItemListViewLayouter::updateVisibleIndexes() // Calculate the last visible index const int visibleHeight = horizontalScrolling ? m_size.width() : m_size.height(); - const qreal bottom = m_offset + visibleHeight; + const qreal bottom = m_scrollOffset + visibleHeight; m_lastVisibleIndex = m_firstVisibleIndex; // first visible row, first column int nextRowIndex = m_lastVisibleIndex + m_columnCount; while (nextRowIndex <= maxIndex && m_itemBoundingRects[nextRowIndex].y() <= bottom) { @@ -404,7 +431,7 @@ void KItemListViewLayouter::updateGroupedVisibleIndexes() const int lastGroupIndex = m_groups.count() - 1; int groupIndex = lastGroupIndex; for (int i = 1; i < m_groups.count(); ++i) { - if (m_groups[i].y >= m_offset) { + if (m_groups[i].y >= m_scrollOffset) { groupIndex = i - 1; break; } @@ -413,7 +440,7 @@ void KItemListViewLayouter::updateGroupedVisibleIndexes() // Calculate the first visible index qreal groupY = m_groups[groupIndex].y; m_firstVisibleIndex = m_groups[groupIndex].firstItemIndex; - const int invisibleRowCount = int(m_offset - groupY) / int(m_itemSize.height()); + const int invisibleRowCount = int(m_scrollOffset - groupY) / int(m_itemSize.height()); m_firstVisibleIndex += invisibleRowCount * m_columnCount; if (groupIndex + 1 <= lastGroupIndex) { // Check whether the calculated first visible index remains inside the current @@ -431,7 +458,7 @@ void KItemListViewLayouter::updateGroupedVisibleIndexes() m_firstVisibleIndex = qBound(0, m_firstVisibleIndex, maxIndex); // Calculate the last visible index: Find group where the last visible item is shown. - const qreal visibleBottom = m_offset + m_size.height(); // TODO: respect Qt::Horizontal alignment + const qreal visibleBottom = m_scrollOffset + m_size.height(); // TODO: respect Qt::Horizontal alignment while ((groupIndex < lastGroupIndex) && (m_groups[groupIndex + 1].y < visibleBottom)) { ++groupIndex; } diff --git a/src/kitemviews/kitemlistviewlayouter_p.h b/src/kitemviews/kitemlistviewlayouter_p.h index 18ffb4caa..c81995d9b 100644 --- a/src/kitemviews/kitemlistviewlayouter_p.h +++ b/src/kitemviews/kitemlistviewlayouter_p.h @@ -56,8 +56,15 @@ public: qreal headerHeight() const; // TODO: add note that offset can be < 0 or > maximumOffset! - void setOffset(qreal offset); - qreal offset() const; + void setScrollOffset(qreal scrollOffset); + qreal scrollOffset() const; + + qreal maximumScrollOffset() const; + + void setItemOffset(qreal scrollOffset); + qreal itemOffset() const; + + qreal maximumItemOffset() const; void setModel(const KItemModelBase* model); const KItemModelBase* model() const; @@ -65,7 +72,6 @@ public: void setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver); const KItemListSizeHintResolver* sizeHintResolver() const; - qreal maximumOffset() const; // TODO: mention that return value is -1 if count == 0 int firstVisibleIndex() const; @@ -107,8 +113,11 @@ private: const KItemModelBase* m_model; const KItemListSizeHintResolver* m_sizeHintResolver; - qreal m_offset; - qreal m_maximumOffset; + qreal m_scrollOffset; + qreal m_maximumScrollOffset; + + qreal m_itemOffset; + qreal m_maximumItemOffset; int m_firstVisibleIndex; int m_lastVisibleIndex;