X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/f63daef339dde16c7ef598f6fdaa5d2191da4685..c8d8556950005dfd96ebdb41d2f43ad90356367c:/src/kitemviews/kitemlistview.cpp diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 478bf6260..5dbc128b5 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -52,6 +52,7 @@ namespace { KItemListView::KItemListView(QGraphicsWidget* parent) : QGraphicsWidget(parent), + m_enabledSelectionToggles(false), m_grouped(false), m_activeTransactions(0), m_itemSize(), @@ -126,7 +127,7 @@ void KItemListView::setScrollOrientation(Qt::Orientation orientation) } } - updateLayout(); + doLayout(Animation); onScrollOrientationChanged(orientation, previousOrientation); emit scrollOrientationChanged(orientation, previousOrientation); @@ -158,7 +159,7 @@ void KItemListView::setItemSize(const QSizeF& itemSize) } m_sizeHintResolver->clearCache(); - updateLayout(); + doLayout(Animation); onItemSizeChanged(itemSize, previousSize); } @@ -180,10 +181,11 @@ void KItemListView::setScrollOffset(qreal offset) m_layouter->setScrollOffset(offset); m_animation->setScrollOffset(offset); - if (!m_layoutTimer->isActive()) { - doLayout(NoAnimation, 0, 0); - update(); - } + + // Don't check whether the m_layoutTimer is active: Changing the + // scroll offset must always trigger a synchronous layout, otherwise + // the smooth-scrolling might get jerky. + doLayout(NoAnimation); onScrollOffsetChanged(offset, previousOffset); } @@ -199,14 +201,19 @@ qreal KItemListView::maximumScrollOffset() const void KItemListView::setItemOffset(qreal offset) { + if (m_layouter->itemOffset() == offset) { + return; + } + m_layouter->setItemOffset(offset); if (m_header) { m_header->setPos(-offset, 0); } - if (!m_layoutTimer->isActive()) { - doLayout(NoAnimation, 0, 0); - update(); - } + + // Don't check whether the m_layoutTimer is active: Changing the + // item offset must always trigger a synchronous layout, otherwise + // the smooth-scrolling might get jerky. + doLayout(NoAnimation); } qreal KItemListView::itemOffset() const @@ -242,7 +249,7 @@ void KItemListView::setVisibleRoles(const QList& roles) } updateVisibleRolesSizes(); - updateLayout(); + doLayout(Animation); onVisibleRolesChanged(roles, previousRoles); } @@ -271,6 +278,24 @@ bool KItemListView::autoScroll() const return m_autoScrollTimer != 0; } +void KItemListView::setEnabledSelectionToggles(bool enabled) +{ + if (m_enabledSelectionToggles != enabled) { + m_enabledSelectionToggles = enabled; + + QHashIterator it(m_visibleItems); + while (it.hasNext()) { + it.next(); + it.value()->setEnabledSelectionToggle(enabled); + } + } +} + +bool KItemListView::enabledSelectionToggles() const +{ + return m_enabledSelectionToggles; +} + KItemListController* KItemListView::controller() const { return m_controller; @@ -313,7 +338,7 @@ void KItemListView::setStyleOption(const KItemListStyleOption& option) } m_sizeHintResolver->clearCache(); - updateLayout(); + doLayout(Animation); onStyleOptionChanged(option, previousOption); } @@ -364,8 +389,14 @@ int KItemListView::itemAt(const QPointF& pos) const bool KItemListView::isAboveSelectionToggle(int index, const QPointF& pos) const { - Q_UNUSED(index); - Q_UNUSED(pos); + const KItemListWidget* widget = m_visibleItems.value(index); + if (widget) { + const QRectF selectionToggleRect = widget->selectionToggleRect(); + if (!selectionToggleRect.isEmpty()) { + const QPointF mappedPos = widget->mapFromItem(this, pos); + return selectionToggleRect.contains(mappedPos); + } + } return false; } @@ -404,14 +435,60 @@ QHash KItemListView::visibleRolesSizes(const KItemRangeList& return QHash(); } +bool KItemListView::supportsItemExpanding() const +{ + return false; +} + QRectF KItemListView::itemRect(int index) const { return m_layouter->itemRect(index); } -int KItemListView::itemsPerOffset() const +QRectF KItemListView::itemContextRect(int index) const { - return m_layouter->itemsPerOffset(); + QRectF contextRect; + + const KItemListWidget* widget = m_visibleItems.value(index); + if (widget) { + contextRect = widget->iconRect() | widget->textRect(); + contextRect.translate(itemRect(index).topLeft()); + } + + return contextRect; +} + +void KItemListView::scrollToItem(int index) +{ + QRectF viewGeometry = geometry(); + if (m_header) { + const qreal headerHeight = m_header->size().height(); + viewGeometry.adjust(0, headerHeight, 0, 0); + } + const QRectF currentRect = itemRect(index); + + if (!viewGeometry.contains(currentRect)) { + qreal newOffset = scrollOffset(); + if (currentRect.top() < viewGeometry.top()) { + Q_ASSERT(scrollOrientation() == Qt::Vertical); + newOffset += currentRect.top() - viewGeometry.top(); + } else if ((currentRect.bottom() > viewGeometry.bottom())) { + Q_ASSERT(scrollOrientation() == Qt::Vertical); + newOffset += currentRect.bottom() - viewGeometry.bottom(); + } else if (currentRect.left() < viewGeometry.left()) { + if (scrollOrientation() == Qt::Horizontal) { + newOffset += currentRect.left() - viewGeometry.left(); + } + } else if ((currentRect.right() > viewGeometry.right())) { + if (scrollOrientation() == Qt::Horizontal) { + newOffset += currentRect.right() - viewGeometry.right(); + } + } + + if (newOffset != scrollOffset()) { + emit scrollTo(newOffset); + } + } } void KItemListView::beginTransaction() @@ -432,7 +509,7 @@ void KItemListView::endTransaction() if (m_activeTransactions == 0) { onTransactionEnd(); - updateLayout(); + doLayout(Animation); } } @@ -453,10 +530,14 @@ void KItemListView::setHeaderShown(bool show) m_header->setVisibleRolesWidths(headerRolesWidths()); m_header->setZValue(1); - m_useHeaderWidths = false; - connect(m_header, SIGNAL(visibleRoleWidthChanged(QByteArray,qreal,qreal)), this, SLOT(slotVisibleRoleWidthChanged(QByteArray,qreal,qreal))); + connect(m_header, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + connect(m_header, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SIGNAL(sortRoleChanged(QByteArray,QByteArray))); + + m_useHeaderWidths = false; m_layouter->setHeaderHeight(m_header->size().height()); } else if (!show && m_header) { @@ -697,7 +778,6 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) m_layouter->markAsDirty(); 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(); if (scrollOrientation() == Qt::Vertical) { @@ -710,7 +790,6 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) if (!hasMultipleRanges) { doLayout(Animation, index, count); - update(); } } @@ -791,7 +870,6 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) m_layouter->markAsDirty(); if (!hasMultipleRanges) { doLayout(Animation, index, -count); - update(); } } @@ -806,6 +884,13 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) void KItemListView::slotItemsMoved(const KItemRange& itemRange, const QList& movedToIndexes) { + m_sizeHintResolver->itemsMoved(itemRange.index, itemRange.count); + m_layouter->markAsDirty(); + + if (m_controller) { + m_controller->selectionManager()->itemsMoved(itemRange, movedToIndexes); + } + const int firstVisibleMovedIndex = qMax(firstVisibleIndex(), itemRange.index); const int lastVisibleMovedIndex = qMin(lastVisibleIndex(), itemRange.index + itemRange.count - 1); @@ -813,12 +898,14 @@ void KItemListView::slotItemsMoved(const KItemRange& itemRange, const QList KItemListWidget* widget = m_visibleItems.value(index); if (widget) { updateWidgetProperties(widget, index); + if (m_grouped) { + updateGroupHeaderForWidget(widget); + } + initializeItemListWidget(widget); } } - if (m_controller) { - m_controller->selectionManager()->itemsMoved(itemRange, movedToIndexes); - } + doLayout(NoAnimation); } void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, @@ -836,6 +923,7 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, if (updateSizeHints) { m_sizeHintResolver->itemsChanged(index, count, roles); m_layouter->markAsDirty(); + if (!m_layoutTimer->isActive()) { m_layoutTimer->start(); } @@ -850,24 +938,27 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, } } + if (m_grouped && roles.contains(m_model->sortRole())) { + // The sort-role has been changed which might result + // in modified group headers + updateVisibleGroupHeaders(); + doLayout(NoAnimation); + } } } void KItemListView::slotGroupedSortingChanged(bool current) { m_grouped = current; + m_layouter->markAsDirty(); + if (m_grouped) { // Apply the height of the header to the layouter const qreal groupHeaderHeight = m_styleOption.fontMetrics.height() + m_styleOption.margin * 2; m_layouter->setGroupHeaderHeight(groupHeaderHeight); - // Assure that headers from already visible items get created - QHashIterator it(m_visibleItems); - while (it.hasNext()) { - it.next(); - updateGroupHeaderForWidget(it.value()); - } + updateVisibleGroupHeaders(); } else { // Clear all visible headers QMutableHashIterator it (m_visibleGroups); @@ -878,8 +969,27 @@ void KItemListView::slotGroupedSortingChanged(bool current) Q_ASSERT(m_visibleGroups.isEmpty()); } - m_layouter->markAsDirty(); - updateLayout(); + doLayout(Animation); +} + +void KItemListView::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) +{ + Q_UNUSED(current); + Q_UNUSED(previous); + if (m_grouped) { + updateVisibleGroupHeaders(); + doLayout(Animation); + } +} + +void KItemListView::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) +{ + Q_UNUSED(current); + Q_UNUSED(previous); + if (m_grouped) { + updateVisibleGroupHeaders(); + doLayout(Animation); + } } void KItemListView::slotCurrentChanged(int current, int previous) @@ -897,33 +1007,6 @@ void KItemListView::slotCurrentChanged(int current, int previous) Q_ASSERT(!currentWidget->isCurrent()); currentWidget->setCurrent(true); } - - const QRectF viewGeometry = geometry(); - const QRectF currentRect = itemRect(current); - - if (!viewGeometry.contains(currentRect)) { - // Make sure that the new current item is fully visible in the view. - qreal newOffset = scrollOffset(); - if (currentRect.top() < viewGeometry.top()) { - Q_ASSERT(scrollOrientation() == Qt::Vertical); - newOffset += currentRect.top() - viewGeometry.top(); - } else if ((currentRect.bottom() > viewGeometry.bottom())) { - Q_ASSERT(scrollOrientation() == Qt::Vertical); - newOffset += currentRect.bottom() - viewGeometry.bottom(); - } else if (currentRect.left() < viewGeometry.left()) { - if (scrollOrientation() == Qt::Horizontal) { - newOffset += currentRect.left() - viewGeometry.left(); - } - } else if ((currentRect.right() > viewGeometry.right())) { - if (scrollOrientation() == Qt::Horizontal) { - newOffset += currentRect.right() - viewGeometry.right(); - } - } - - if (newOffset != scrollOffset()) { - emit scrollTo(newOffset); - } - } } void KItemListView::slotSelectionChanged(const QSet& current, const QSet& previous) @@ -979,7 +1062,7 @@ void KItemListView::slotAnimationFinished(QGraphicsWidget* widget, void KItemListView::slotLayoutTimerFinished() { m_layouter->setSize(geometry().size()); - doLayout(Animation, 0, 0); + doLayout(Animation); } void KItemListView::slotRubberBandPosChanged() @@ -1034,7 +1117,7 @@ void KItemListView::slotVisibleRoleWidthChanged(const QByteArray& role, widget->setVisibleRolesSizes(m_stretchedVisibleRolesSizes); } - updateLayout(); + doLayout(Animation); } } @@ -1088,7 +1171,9 @@ void KItemListView::triggerAutoScrolling() // the autoscrolling may not get skipped anymore until a new rubberband is created m_skipAutoScrollForRubberBand = false; - setScrollOffset(scrollOffset() + m_autoScrollIncrement); + const qreal maxVisibleOffset = qMax(qreal(0), maximumScrollOffset() - visibleSize); + const qreal newScrollOffset = qMin(scrollOffset() + m_autoScrollIncrement, maxVisibleOffset); + setScrollOffset(newScrollOffset); // Trigger the autoscroll timer which will periodically call // triggerAutoScrolling() @@ -1136,10 +1221,14 @@ void KItemListView::setModel(KItemModelBase* model) this, SLOT(slotItemsMoved(KItemRange,QList))); disconnect(m_model, SIGNAL(groupedSortingChanged(bool)), this, SLOT(slotGroupedSortingChanged(bool))); + disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); } m_model = model; - m_layouter->setModel(model); + m_layouter->setModel(model); m_grouped = model->groupedSorting(); if (m_model) { @@ -1153,6 +1242,10 @@ void KItemListView::setModel(KItemModelBase* model) this, SLOT(slotItemsMoved(KItemRange,QList))); connect(m_model, SIGNAL(groupedSortingChanged(bool)), this, SLOT(slotGroupedSortingChanged(bool))); + connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); } onModelChanged(model, previous); @@ -1163,20 +1256,13 @@ KItemListRubberBand* KItemListView::rubberBand() const return m_rubberBand; } -void KItemListView::updateLayout() -{ - doLayout(Animation, 0, 0); - update(); -} - void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount) { if (m_layoutTimer->isActive()) { - kDebug() << "Stopping layout timer, synchronous layout requested"; m_layoutTimer->stop(); } - if (m_model->count() < 0 || m_activeTransactions > 0) { + if (!m_model || m_model->count() < 0 || m_activeTransactions > 0) { return; } @@ -1248,7 +1334,8 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha if (animate && changedCount < 0) { // Items have been deleted, move the created item to the - // imaginary old position. + // imaginary old position. They will get animated to the new position + // later. const QRectF itemRect = m_layouter->itemRect(i - changedCount); if (itemRect.isEmpty()) { const QPointF invisibleOldPos = (scrollOrientation() == Qt::Vertical) @@ -1266,7 +1353,6 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha if (animate) { const bool itemsRemoved = (changedCount < 0); const bool itemsInserted = (changedCount > 0); - if (itemsRemoved && (i >= changedIndex + changedCount + 1)) { // The item is located after the removed items. Animate the moving of the position. m_animation->start(widget, KItemListViewAnimation::MovingAnimation, newPos); @@ -1302,7 +1388,21 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha widget->setVisible(true); if (widget->size() != itemBounds.size()) { - m_animation->start(widget, KItemListViewAnimation::ResizeAnimation, itemBounds.size()); + // Resize the widget for the item to the changed size. + if (animate) { + // If a dynamic item size is used then no animation is done in the direction + // of the dynamic size. + if (m_itemSize.width() <= 0) { + // The width is dynamic, apply the new width without animation. + widget->resize(itemBounds.width(), widget->size().height()); + } else if (m_itemSize.height() <= 0) { + // The height is dynamic, apply the new height without animation. + widget->resize(widget->size().width(), itemBounds.height()); + } + m_animation->start(widget, KItemListViewAnimation::ResizeAnimation, itemBounds.size()); + } else { + widget->resize(itemBounds.size()); + } } } @@ -1452,12 +1552,15 @@ void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index) widget->setSelected(selectionManager->isSelected(index)); widget->setHovered(false); widget->setAlternatingBackgroundColors(false); + widget->setEnabledSelectionToggle(enabledSelectionToggles()); widget->setIndex(index); widget->setData(m_model->data(index)); } void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) { + Q_ASSERT(m_grouped); + const int index = widget->index(); if (!m_layouter->isFirstGroupItem(index)) { // The widget does not represent the first item of a group @@ -1466,6 +1569,11 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) return; } + const QList > groups = model()->groups(); + if (groups.isEmpty()) { + return; + } + KItemListGroupHeader* header = m_visibleGroups.value(widget); if (!header) { header = m_groupHeaderCreator->create(this); @@ -1476,7 +1584,6 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) // Determine the shown data for the header by doing a binary // search in the groups-list - const QList > groups = model()->groups(); int min = 0; int max = groups.count() - 1; int mid = 0; @@ -1524,6 +1631,18 @@ void KItemListView::recycleGroupHeaderForWidget(KItemListWidget* widget) } } +void KItemListView::updateVisibleGroupHeaders() +{ + Q_ASSERT(m_grouped); + m_layouter->markAsDirty(); + + QHashIterator it(m_visibleItems); + while (it.hasNext()) { + it.next(); + updateGroupHeaderForWidget(it.value()); + } +} + QHash KItemListView::headerRolesWidths() const { QHash rolesWidths; @@ -1597,6 +1716,10 @@ void KItemListView::updateVisibleRolesSizes(const KItemRangeList& itemRanges) void KItemListView::updateVisibleRolesSizes() { + if (!m_model) { + return; + } + const int itemCount = m_model->count(); if (itemCount > 0) { updateVisibleRolesSizes(KItemRangeList() << KItemRange(0, itemCount)); @@ -1605,7 +1728,7 @@ void KItemListView::updateVisibleRolesSizes() void KItemListView::updateStretchedVisibleRolesSizes() { - if (!m_itemSize.isEmpty() || m_useHeaderWidths) { + if (!m_itemSize.isEmpty() || m_useHeaderWidths || m_visibleRoles.isEmpty()) { return; } @@ -1614,7 +1737,7 @@ void KItemListView::updateStretchedVisibleRolesSizes() // size does not use the available view-size it the size of the // first role will get stretched. m_stretchedVisibleRolesSizes = m_visibleRolesSizes; - const QByteArray role = visibleRoles().first(); + const QByteArray role = m_visibleRoles.first(); QSizeF firstRoleSize = m_stretchedVisibleRolesSizes.value(role); QSizeF dynamicItemSize = m_itemSize;