X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/90e27974a4a4a3cb4d08717b5270bea8645b063e..ad9c9558357598e95997afa7b9fa520c5304d04e:/src/kitemviews/kitemlistview.cpp diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 222a29cf5..96c337de3 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -1,52 +1,34 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * Based on the Itemviews NG project from Trolltech Labs: * - * http://qt.gitorious.org/qt-labs/itemviews-ng * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2011 Peter Penz + * + * Based on the Itemviews NG project from Trolltech Labs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "kitemlistview.h" -#include +#include "dolphindebug.h" #include "kitemlistcontainer.h" #include "kitemlistcontroller.h" #include "kitemlistheader.h" #include "kitemlistselectionmanager.h" -#include "kitemlistwidget.h" +#include "kitemlistviewaccessible.h" +#include "kstandarditemlistwidget.h" #include "private/kitemlistheaderwidget.h" #include "private/kitemlistrubberband.h" #include "private/kitemlistsizehintresolver.h" #include "private/kitemlistviewlayouter.h" -#include "private/kitemlistviewanimation.h" -#include +#include #include #include -#include #include -#include #include #include +#include -#include - -#include "kitemlistviewaccessible.h" namespace { // Time in ms until reaching the autoscroll margin triggers @@ -55,10 +37,15 @@ namespace { // Delay in ms for triggering the next autoscroll const int RepeatingAutoScrollDelay = 1000 / 60; + + // Copied from the Kirigami.Units.shortDuration + const int RubberFadeSpeed = 150; + + const char* RubberPropertyName = "_kitemviews_rubberBandPosition"; } #ifndef QT_NO_ACCESSIBILITY -QAccessibleInterface* accessibleInterfaceFactory(const QString &key, QObject *object) +QAccessibleInterface* accessibleInterfaceFactory(const QString& key, QObject* object) { Q_UNUSED(key) @@ -68,7 +55,7 @@ QAccessibleInterface* accessibleInterfaceFactory(const QString &key, QObject *ob return new KItemListViewAccessible(view); } - return 0; + return nullptr; } #endif @@ -81,49 +68,69 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_activeTransactions(0), m_endTransactionAnimationHint(Animation), m_itemSize(), - m_controller(0), - m_model(0), + m_controller(nullptr), + m_model(nullptr), m_visibleRoles(), - m_widgetCreator(0), - m_groupHeaderCreator(0), + m_widgetCreator(nullptr), + m_groupHeaderCreator(nullptr), m_styleOption(), m_visibleItems(), m_visibleGroups(), m_visibleCells(), - m_sizeHintResolver(0), - m_layouter(0), - m_animation(0), - m_layoutTimer(0), + m_sizeHintResolver(nullptr), + m_layouter(nullptr), + m_animation(nullptr), + m_layoutTimer(nullptr), m_oldScrollOffset(0), m_oldMaximumScrollOffset(0), m_oldItemOffset(0), m_oldMaximumItemOffset(0), m_skipAutoScrollForRubberBand(false), - m_rubberBand(0), + m_rubberBand(nullptr), + m_tapAndHoldIndicator(nullptr), m_mousePos(), m_autoScrollIncrement(0), - m_autoScrollTimer(0), - m_header(0), - m_headerWidget(0), + m_autoScrollTimer(nullptr), + m_header(nullptr), + m_headerWidget(nullptr), + m_indicatorAnimation(nullptr), m_dropIndicator() { setAcceptHoverEvents(true); + setAcceptTouchEvents(true); m_sizeHintResolver = new KItemListSizeHintResolver(this); m_layouter = new KItemListViewLayouter(m_sizeHintResolver, this); m_animation = new KItemListViewAnimation(this); - connect(m_animation, SIGNAL(finished(QGraphicsWidget*,KItemListViewAnimation::AnimationType)), - this, SLOT(slotAnimationFinished(QGraphicsWidget*,KItemListViewAnimation::AnimationType))); + connect(m_animation, &KItemListViewAnimation::finished, + this, &KItemListView::slotAnimationFinished); m_layoutTimer = new QTimer(this); m_layoutTimer->setInterval(300); m_layoutTimer->setSingleShot(true); - connect(m_layoutTimer, SIGNAL(timeout()), this, SLOT(slotLayoutTimerFinished())); + connect(m_layoutTimer, &QTimer::timeout, this, &KItemListView::slotLayoutTimerFinished); m_rubberBand = new KItemListRubberBand(this); - connect(m_rubberBand, SIGNAL(activationChanged(bool)), this, SLOT(slotRubberBandActivationChanged(bool))); + connect(m_rubberBand, &KItemListRubberBand::activationChanged, this, &KItemListView::slotRubberBandActivationChanged); + + m_tapAndHoldIndicator = new KItemListRubberBand(this); + m_indicatorAnimation = new QPropertyAnimation(m_tapAndHoldIndicator, "endPosition", this); + connect(m_tapAndHoldIndicator, &KItemListRubberBand::activationChanged, this, [this](bool active) { + if (active) { + m_indicatorAnimation->setDuration(150); + m_indicatorAnimation->setStartValue(QPointF(1, 1)); + m_indicatorAnimation->setEndValue(QPointF(40, 40)); + m_indicatorAnimation->start(); + } + update(); + }); + connect(m_tapAndHoldIndicator, &KItemListRubberBand::endPositionChanged, this, [this]() { + if (m_tapAndHoldIndicator->isActive()) { + update(); + } + }); m_headerWidget = new KItemListHeaderWidget(this); m_headerWidget->setVisible(false); @@ -142,13 +149,13 @@ KItemListView::~KItemListView() // widgetCreator(). So it is mandatory to delete the group headers // first. delete m_groupHeaderCreator; - m_groupHeaderCreator = 0; + m_groupHeaderCreator = nullptr; delete m_widgetCreator; - m_widgetCreator = 0; + m_widgetCreator = nullptr; delete m_sizeHintResolver; - m_sizeHintResolver = 0; + m_sizeHintResolver = nullptr; } void KItemListView::setScrollOffset(qreal offset) @@ -229,7 +236,7 @@ void KItemListView::setVisibleRoles(const QList& roles) if (!m_headerWidget->automaticColumnResizing()) { // The column-width of new roles are still 0. Apply the preferred // column-width as default with. - foreach (const QByteArray& role, m_visibleRoles) { + for (const QByteArray& role : qAsConst(m_visibleRoles)) { if (m_headerWidget->columnWidth(role) == 0) { const qreal width = m_headerWidget->preferredColumnWidth(role); m_headerWidget->setColumnWidth(role, width); @@ -267,17 +274,17 @@ void KItemListView::setAutoScroll(bool enabled) if (enabled && !m_autoScrollTimer) { m_autoScrollTimer = new QTimer(this); m_autoScrollTimer->setSingleShot(true); - connect(m_autoScrollTimer, SIGNAL(timeout()), this, SLOT(triggerAutoScrolling())); + connect(m_autoScrollTimer, &QTimer::timeout, this, &KItemListView::triggerAutoScrolling); m_autoScrollTimer->start(InitialAutoScrollDelay); } else if (!enabled && m_autoScrollTimer) { delete m_autoScrollTimer; - m_autoScrollTimer = 0; + m_autoScrollTimer = nullptr; } } bool KItemListView::autoScroll() const { - return m_autoScrollTimer != 0; + return m_autoScrollTimer != nullptr; } void KItemListView::setEnabledSelectionToggles(bool enabled) @@ -310,9 +317,7 @@ KItemModelBase* KItemListView::model() const void KItemListView::setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator) { - if (m_widgetCreator) { - delete m_widgetCreator; - } + delete m_widgetCreator; m_widgetCreator = widgetCreator; } @@ -326,9 +331,7 @@ KItemListWidgetCreatorBase* KItemListView::widgetCreator() const void KItemListView::setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator) { - if (m_groupHeaderCreator) { - delete m_groupHeaderCreator; - } + delete m_groupHeaderCreator; m_groupHeaderCreator = groupHeaderCreator; } @@ -449,6 +452,19 @@ bool KItemListView::isAboveExpansionToggle(int index, const QPointF& pos) const return false; } +bool KItemListView::isAboveText(int index, const QPointF &pos) const +{ + const KItemListWidget* widget = m_visibleItems.value(index); + if (widget) { + const QRectF &textRect = widget->textRect(); + if (!textRect.isEmpty()) { + const QPointF mappedPos = widget->mapFromItem(this, pos); + return textRect.contains(mappedPos); + } + } + return false; +} + int KItemListView::firstVisibleIndex() const { return m_layouter->firstVisibleIndex(); @@ -459,9 +475,9 @@ int KItemListView::lastVisibleIndex() const return m_layouter->lastVisibleIndex(); } -void KItemListView::calculateItemSizeHints(QVector& sizeHints) const +void KItemListView::calculateItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint) const { - widgetCreator()->calculateItemSizeHints(sizeHints, this); + widgetCreator()->calculateItemSizeHints(logicalHeightHints, logicalWidthHint, this); } void KItemListView::setSupportsItemExpanding(bool supportsExpanding) @@ -526,7 +542,7 @@ void KItemListView::scrollToItem(int index) } if (newOffset != scrollOffset()) { - emit scrollTo(newOffset); + Q_EMIT scrollTo(newOffset); } } } @@ -544,7 +560,7 @@ void KItemListView::endTransaction() --m_activeTransactions; if (m_activeTransactions < 0) { m_activeTransactions = 0; - kWarning() << "Mismatch between beginTransaction()/endTransaction()"; + qCWarning(DolphinDebug) << "Mismatch between beginTransaction()/endTransaction()"; } if (m_activeTransactions == 0) { @@ -572,26 +588,26 @@ void KItemListView::setHeaderVisible(bool visible) m_headerWidget->setColumns(m_visibleRoles); m_headerWidget->setZValue(1); - connect(m_headerWidget, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)), - this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); - connect(m_headerWidget, SIGNAL(columnMoved(QByteArray,int,int)), - this, SLOT(slotHeaderColumnMoved(QByteArray,int,int))); - connect(m_headerWidget, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), - this, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder))); - connect(m_headerWidget, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), - this, SIGNAL(sortRoleChanged(QByteArray,QByteArray))); + connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged, + this, &KItemListView::slotHeaderColumnWidthChanged); + connect(m_headerWidget, &KItemListHeaderWidget::columnMoved, + this, &KItemListView::slotHeaderColumnMoved); + connect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged, + this, &KItemListView::sortOrderChanged); + connect(m_headerWidget, &KItemListHeaderWidget::sortRoleChanged, + this, &KItemListView::sortRoleChanged); m_layouter->setHeaderHeight(headerSize.height()); m_headerWidget->setVisible(true); } else if (!visible && m_headerWidget->isVisible()) { - disconnect(m_headerWidget, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)), - this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); - disconnect(m_headerWidget, SIGNAL(columnMoved(QByteArray,int,int)), - this, SLOT(slotHeaderColumnMoved(QByteArray,int,int))); - disconnect(m_headerWidget, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), - this, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder))); - disconnect(m_headerWidget, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), - this, SIGNAL(sortRoleChanged(QByteArray,QByteArray))); + disconnect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged, + this, &KItemListView::slotHeaderColumnWidthChanged); + disconnect(m_headerWidget, &KItemListHeaderWidget::columnMoved, + this, &KItemListView::slotHeaderColumnMoved); + disconnect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged, + this, &KItemListView::sortOrderChanged); + disconnect(m_headerWidget, &KItemListHeaderWidget::sortRoleChanged, + this, &KItemListView::sortRoleChanged); m_layouter->setHeaderHeight(0); m_headerWidget->setVisible(false); @@ -616,7 +632,7 @@ QPixmap KItemListView::createDragPixmap(const KItemSet& indexes) const KItemListWidget* item = m_visibleItems.value(indexes.first()); QGraphicsView* graphicsView = scene()->views()[0]; if (item && graphicsView) { - pixmap = item->createDragPixmap(0, graphicsView); + pixmap = item->createDragPixmap(nullptr, graphicsView); } } else { // TODO: Not implemented yet. Probably extend the interface @@ -629,7 +645,7 @@ QPixmap KItemListView::createDragPixmap(const KItemSet& indexes) const void KItemListView::editRole(int index, const QByteArray& role) { - KItemListWidget* widget = m_visibleItems.value(index); + KStandardItemListWidget* widget = qobject_cast(m_visibleItems.value(index)); if (!widget || m_editingRole) { return; } @@ -637,16 +653,43 @@ void KItemListView::editRole(int index, const QByteArray& role) m_editingRole = true; widget->setEditedRole(role); - connect(widget, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)), - this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant))); - connect(widget, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), - this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant))); + connect(widget, &KItemListWidget::roleEditingCanceled, + this, &KItemListView::slotRoleEditingCanceled); + connect(widget, &KItemListWidget::roleEditingFinished, + this, &KItemListView::slotRoleEditingFinished); + + connect(this, &KItemListView::scrollOffsetChanged, + widget, &KStandardItemListWidget::finishRoleEditing); } void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { QGraphicsWidget::paint(painter, option, widget); + for (auto animation : qAsConst(m_rubberBandAnimations)) { + QRectF rubberBandRect = animation->property(RubberPropertyName).toRectF(); + + const QPointF topLeft = rubberBandRect.topLeft(); + if (scrollOrientation() == Qt::Vertical) { + rubberBandRect.moveTo(topLeft.x(), topLeft.y() - scrollOffset()); + } else { + rubberBandRect.moveTo(topLeft.x() - scrollOffset(), topLeft.y()); + } + + QStyleOptionRubberBand opt; + initStyleOption(&opt); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = rubberBandRect.toRect(); + + painter->save(); + + painter->setOpacity(animation->currentValue().toReal()); + style()->drawControl(QStyle::CE_RubberBand, &opt, painter); + + painter->restore(); + } + if (m_rubberBand->isActive()) { QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(), m_rubberBand->endPosition()).normalized(); @@ -659,7 +702,19 @@ void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt } QStyleOptionRubberBand opt; - opt.initFrom(widget); + initStyleOption(&opt); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = rubberBandRect.toRect(); + style()->drawControl(QStyle::CE_RubberBand, &opt, painter); + } + + if (m_tapAndHoldIndicator->isActive()) { + const QPointF indicatorSize = m_tapAndHoldIndicator->endPosition(); + const QRectF rubberBandRect = QRectF(m_tapAndHoldIndicator->startPosition() - indicatorSize, + (m_tapAndHoldIndicator->startPosition()) + indicatorSize).normalized(); + QStyleOptionRubberBand opt; + initStyleOption(&opt); opt.shape = QRubberBand::Rectangle; opt.opaque = false; opt.rect = rubberBandRect.toRect(); @@ -669,7 +724,7 @@ void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt if (!m_dropIndicator.isEmpty()) { const QRectF r = m_dropIndicator.toRect(); - QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color(); + QColor color = palette().brush(QPalette::Normal, QPalette::Text).color(); painter->setPen(color); // TODO: The following implementation works only for a vertical scroll-orientation @@ -741,6 +796,10 @@ void KItemListView::setItemSize(const QSizeF& size) void KItemListView::setStyleOption(const KItemListStyleOption& option) { + if (m_styleOption == option) { + return; + } + const KItemListStyleOption previousOption = m_styleOption; m_styleOption = option; @@ -808,7 +867,7 @@ void KItemListView::setScrollOrientation(Qt::Orientation orientation) doLayout(NoAnimation); onScrollOrientationChanged(orientation, previousOrientation); - emit scrollOrientationChanged(orientation, previousOrientation); + Q_EMIT scrollOrientationChanged(orientation, previousOrientation); } Qt::Orientation KItemListView::scrollOrientation() const @@ -818,70 +877,70 @@ Qt::Orientation KItemListView::scrollOrientation() const KItemListWidgetCreatorBase* KItemListView::defaultWidgetCreator() const { - return 0; + return nullptr; } KItemListGroupHeaderCreatorBase* KItemListView::defaultGroupHeaderCreator() const { - return 0; + return nullptr; } void KItemListView::initializeItemListWidget(KItemListWidget* item) { - Q_UNUSED(item); + Q_UNUSED(item) } bool KItemListView::itemSizeHintUpdateRequired(const QSet& changedRoles) const { - Q_UNUSED(changedRoles); + Q_UNUSED(changedRoles) return true; } void KItemListView::onControllerChanged(KItemListController* current, KItemListController* previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onModelChanged(KItemModelBase* current, KItemModelBase* previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onScrollOffsetChanged(qreal current, qreal previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onVisibleRolesChanged(const QList& current, const QList& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } void KItemListView::onSupportsItemExpandingChanged(bool supportsExpanding) { - Q_UNUSED(supportsExpanding); + Q_UNUSED(supportsExpanding) } void KItemListView::onTransactionBegin() @@ -936,7 +995,7 @@ void KItemListView::dragEnterEvent(QGraphicsSceneDragDropEvent* event) setAutoScroll(true); } -void KItemListView::dragMoveEvent(QGraphicsSceneDragDropEvent *event) +void KItemListView::dragMoveEvent(QGraphicsSceneDragDropEvent* event) { QGraphicsWidget::dragMoveEvent(event); @@ -946,7 +1005,7 @@ void KItemListView::dragMoveEvent(QGraphicsSceneDragDropEvent *event) } } -void KItemListView::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) +void KItemListView::dragLeaveEvent(QGraphicsSceneDragDropEvent* event) { QGraphicsWidget::dragLeaveEvent(event); setAutoScroll(false); @@ -1000,14 +1059,14 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) m_sizeHintResolver->itemsInserted(itemRanges); int previouslyInsertedCount = 0; - foreach (const KItemRange& range, itemRanges) { + for (const KItemRange& range : itemRanges) { // range.index is related to the model before anything has been inserted. // As in each loop the current item-range gets inserted the index must // be increased by the already previously inserted items. const int index = range.index + previouslyInsertedCount; const int count = range.count; if (index < 0 || count <= 0) { - kWarning() << "Invalid item range (index:" << index << ", count:" << count << ")"; + qCWarning(DolphinDebug) << "Invalid item range (index:" << index << ", count:" << count << ")"; continue; } previouslyInsertedCount += count; @@ -1026,7 +1085,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) // Update the indexes of all KItemListWidget instances that are located // after the inserted items. It is important to adjust the indexes in the order // from the highest index to the lowest index to prevent overlaps when setting the new index. - qSort(itemsToMove); + std::sort(itemsToMove.begin(), itemsToMove.end()); for (int i = itemsToMove.count() - 1; i >= 0; --i) { KItemListWidget* widget = m_visibleItems.value(itemsToMove[i]); Q_ASSERT(widget); @@ -1115,18 +1174,21 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) const int index = range.index; const int count = range.count; if (index < 0 || count <= 0) { - kWarning() << "Invalid item range (index:" << index << ", count:" << count << ")"; + qCWarning(DolphinDebug) << "Invalid item range (index:" << index << ", count:" << count << ")"; continue; } const int firstRemovedIndex = index; const int lastRemovedIndex = index + count - 1; - // Remeber which items have to be moved because they are behind the removed range. + // Remember which items have to be moved because they are behind the removed range. QVector itemsToMove; // Remove all KItemListWidget instances that got deleted - foreach (KItemListWidget* widget, m_visibleItems) { + // Iterate over a const copy because the container is mutated within the loop + // directly and in `recycleWidget()` (https://bugs.kde.org/show_bug.cgi?id=428374) + const auto visibleItems = m_visibleItems; + for (KItemListWidget* widget : visibleItems) { const int i = widget->index(); if (i < firstRemovedIndex) { continue; @@ -1162,7 +1224,7 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) // after the deleted items. It is important to update them in ascending // order to prevent overlaps when setting the new index. std::sort(itemsToMove.begin(), itemsToMove.end()); - foreach (int i, itemsToMove) { + for (int i : qAsConst(itemsToMove)) { KItemListWidget* widget = m_visibleItems.value(i); Q_ASSERT(widget); const int newIndex = i - count; @@ -1240,7 +1302,7 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, updatePreferredColumnWidths(itemRanges); } - foreach (const KItemRange& itemRange, itemRanges) { + for (const KItemRange& itemRange : itemRanges) { const int index = itemRange.index; const int count = itemRange.count; @@ -1268,8 +1330,12 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, updateVisibleGroupHeaders(); doLayout(NoAnimation); } + + QAccessibleTableModelChangeEvent ev(this, QAccessibleTableModelChangeEvent::DataChanged); + ev.setFirstRow(itemRange.index); + ev.setLastRow(itemRange.index + itemRange.count); + QAccessible::updateAccessibility(&ev); } - QAccessible::updateAccessibility(this, 0, QAccessible::TableModelChanged); } void KItemListView::slotGroupsChanged() @@ -1310,8 +1376,8 @@ void KItemListView::slotGroupedSortingChanged(bool current) void KItemListView::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) if (m_grouped) { updateVisibleGroupHeaders(); doLayout(NoAnimation); @@ -1320,8 +1386,8 @@ void KItemListView::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder pr void KItemListView::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) if (m_grouped) { updateVisibleGroupHeaders(); doLayout(NoAnimation); @@ -1330,23 +1396,30 @@ void KItemListView::slotSortRoleChanged(const QByteArray& current, const QByteAr void KItemListView::slotCurrentChanged(int current, int previous) { - Q_UNUSED(previous); + Q_UNUSED(previous) - KItemListWidget* previousWidget = m_visibleItems.value(previous, 0); - if (previousWidget) { - previousWidget->setCurrent(false); - } + // In SingleSelection mode (e.g., in the Places Panel), the current item is + // always the selected item. It is not necessary to highlight the current item then. + if (m_controller->selectionBehavior() != KItemListController::SingleSelection) { + KItemListWidget* previousWidget = m_visibleItems.value(previous, nullptr); + if (previousWidget) { + previousWidget->setCurrent(false); + } - KItemListWidget* currentWidget = m_visibleItems.value(current, 0); - if (currentWidget) { - currentWidget->setCurrent(true); + KItemListWidget* currentWidget = m_visibleItems.value(current, nullptr); + if (currentWidget) { + currentWidget->setCurrent(true); + } } - QAccessible::updateAccessibility(this, current+1, QAccessible::Focus); + + QAccessibleEvent ev(this, QAccessible::Focus); + ev.setChild(current); + QAccessible::updateAccessibility(&ev); } void KItemListView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous) { - Q_UNUSED(previous); + Q_UNUSED(previous) QHashIterator it(m_visibleItems); while (it.hasNext()) { @@ -1408,12 +1481,36 @@ void KItemListView::slotRubberBandPosChanged() void KItemListView::slotRubberBandActivationChanged(bool active) { if (active) { - connect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); - connect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + connect(m_rubberBand, &KItemListRubberBand::startPositionChanged, this, &KItemListView::slotRubberBandPosChanged); + connect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged); m_skipAutoScrollForRubberBand = true; } else { - disconnect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); - disconnect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(), + m_rubberBand->endPosition()).normalized(); + + auto animation = new QVariantAnimation(this); + animation->setStartValue(1.0); + animation->setEndValue(0.0); + animation->setDuration(RubberFadeSpeed); + animation->setProperty(RubberPropertyName, rubberBandRect); + + QEasingCurve curve; + curve.setType(QEasingCurve::BezierSpline); + curve.addCubicBezierSegment(QPointF(0.4, 0.0), QPointF(1.0, 1.0), QPointF(1.0, 1.0)); + animation->setEasingCurve(curve); + + connect(animation, &QVariantAnimation::valueChanged, this, [=](const QVariant&) { + update(); + }); + connect(animation, &QVariantAnimation::finished, this, [=]() { + m_rubberBandAnimations.removeAll(animation); + delete animation; + }); + animation->start(); + m_rubberBandAnimations << animation; + + disconnect(m_rubberBand, &KItemListRubberBand::startPositionChanged, this, &KItemListView::slotRubberBandPosChanged); + disconnect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged); m_skipAutoScrollForRubberBand = false; } @@ -1424,9 +1521,9 @@ void KItemListView::slotHeaderColumnWidthChanged(const QByteArray& role, qreal currentWidth, qreal previousWidth) { - Q_UNUSED(role); - Q_UNUSED(currentWidth); - Q_UNUSED(previousWidth); + Q_UNUSED(role) + Q_UNUSED(currentWidth) + Q_UNUSED(previousWidth) m_headerWidget->setAutomaticColumnResizing(false); applyColumnWidthsFromHeader(); @@ -1447,7 +1544,7 @@ void KItemListView::slotHeaderColumnMoved(const QByteArray& role, setVisibleRoles(current); - emit visibleRolesChanged(current, previous); + Q_EMIT visibleRolesChanged(current, previous); } void KItemListView::triggerAutoScrolling() @@ -1522,7 +1619,7 @@ void KItemListView::slotRoleEditingCanceled(int index, const QByteArray& role, c { disconnectRoleEditingSignals(index); - emit roleEditingCanceled(index, role, value); + Q_EMIT roleEditingCanceled(index, role, value); m_editingRole = false; } @@ -1530,7 +1627,7 @@ void KItemListView::slotRoleEditingFinished(int index, const QByteArray& role, c { disconnectRoleEditingSignals(index); - emit roleEditingFinished(index, role, value); + Q_EMIT roleEditingFinished(index, role, value); m_editingRole = false; } @@ -1540,16 +1637,16 @@ void KItemListView::setController(KItemListController* controller) KItemListController* previous = m_controller; if (previous) { KItemListSelectionManager* selectionManager = previous->selectionManager(); - disconnect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int))); - disconnect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet))); + disconnect(selectionManager, &KItemListSelectionManager::currentChanged, this, &KItemListView::slotCurrentChanged); + disconnect(selectionManager, &KItemListSelectionManager::selectionChanged, this, &KItemListView::slotSelectionChanged); } m_controller = controller; if (controller) { KItemListSelectionManager* selectionManager = controller->selectionManager(); - connect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int))); - connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet))); + connect(selectionManager, &KItemListSelectionManager::currentChanged, this, &KItemListView::slotCurrentChanged); + connect(selectionManager, &KItemListSelectionManager::selectionChanged, this, &KItemListView::slotSelectionChanged); } onControllerChanged(controller, previous); @@ -1565,22 +1662,22 @@ void KItemListView::setModel(KItemModelBase* model) KItemModelBase* previous = m_model; if (m_model) { - disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - disconnect(m_model, SIGNAL(itemsInserted(KItemRangeList)), - this, SLOT(slotItemsInserted(KItemRangeList))); - disconnect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), - this, SLOT(slotItemsRemoved(KItemRangeList))); - disconnect(m_model, SIGNAL(itemsMoved(KItemRange,QList)), - this, SLOT(slotItemsMoved(KItemRange,QList))); - disconnect(m_model, SIGNAL(groupsChanged()), - this, SLOT(slotGroupsChanged())); - 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))); + disconnect(m_model, &KItemModelBase::itemsChanged, + this, &KItemListView::slotItemsChanged); + disconnect(m_model, &KItemModelBase::itemsInserted, + this, &KItemListView::slotItemsInserted); + disconnect(m_model, &KItemModelBase::itemsRemoved, + this, &KItemListView::slotItemsRemoved); + disconnect(m_model, &KItemModelBase::itemsMoved, + this, &KItemListView::slotItemsMoved); + disconnect(m_model, &KItemModelBase::groupsChanged, + this, &KItemListView::slotGroupsChanged); + disconnect(m_model, &KItemModelBase::groupedSortingChanged, + this, &KItemListView::slotGroupedSortingChanged); + disconnect(m_model, &KItemModelBase::sortOrderChanged, + this, &KItemListView::slotSortOrderChanged); + disconnect(m_model, &KItemModelBase::sortRoleChanged, + this, &KItemListView::slotSortRoleChanged); m_sizeHintResolver->itemsRemoved(KItemRangeList() << KItemRange(0, m_model->count())); } @@ -1590,22 +1687,22 @@ void KItemListView::setModel(KItemModelBase* model) m_grouped = model->groupedSorting(); if (m_model) { - connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - connect(m_model, SIGNAL(itemsInserted(KItemRangeList)), - this, SLOT(slotItemsInserted(KItemRangeList))); - connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), - this, SLOT(slotItemsRemoved(KItemRangeList))); - connect(m_model, SIGNAL(itemsMoved(KItemRange,QList)), - this, SLOT(slotItemsMoved(KItemRange,QList))); - connect(m_model, SIGNAL(groupsChanged()), - this, SLOT(slotGroupsChanged())); - 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))); + connect(m_model, &KItemModelBase::itemsChanged, + this, &KItemListView::slotItemsChanged); + connect(m_model, &KItemModelBase::itemsInserted, + this, &KItemListView::slotItemsInserted); + connect(m_model, &KItemModelBase::itemsRemoved, + this, &KItemListView::slotItemsRemoved); + connect(m_model, &KItemModelBase::itemsMoved, + this, &KItemListView::slotItemsMoved); + connect(m_model, &KItemModelBase::groupsChanged, + this, &KItemListView::slotGroupsChanged); + connect(m_model, &KItemModelBase::groupedSortingChanged, + this, &KItemListView::slotGroupedSortingChanged); + connect(m_model, &KItemModelBase::sortOrderChanged, + this, &KItemListView::slotSortOrderChanged); + connect(m_model, &KItemModelBase::sortRoleChanged, + this, &KItemListView::slotSortRoleChanged); const int itemCount = m_model->count(); if (itemCount > 0) { @@ -1783,7 +1880,7 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha } // Delete invisible KItemListWidget instances that have not been reused - foreach (int index, reusableItems) { + for (int index : qAsConst(reusableItems)) { recycleWidget(m_visibleItems.value(index)); } @@ -1886,25 +1983,25 @@ void KItemListView::emitOffsetChanges() { const qreal newScrollOffset = m_layouter->scrollOffset(); if (m_oldScrollOffset != newScrollOffset) { - emit scrollOffsetChanged(newScrollOffset, m_oldScrollOffset); + Q_EMIT scrollOffsetChanged(newScrollOffset, m_oldScrollOffset); m_oldScrollOffset = newScrollOffset; } const qreal newMaximumScrollOffset = m_layouter->maximumScrollOffset(); if (m_oldMaximumScrollOffset != newMaximumScrollOffset) { - emit maximumScrollOffsetChanged(newMaximumScrollOffset, m_oldMaximumScrollOffset); + Q_EMIT maximumScrollOffsetChanged(newMaximumScrollOffset, m_oldMaximumScrollOffset); m_oldMaximumScrollOffset = newMaximumScrollOffset; } const qreal newItemOffset = m_layouter->itemOffset(); if (m_oldItemOffset != newItemOffset) { - emit itemOffsetChanged(newItemOffset, m_oldItemOffset); + Q_EMIT itemOffsetChanged(newItemOffset, m_oldItemOffset); m_oldItemOffset = newItemOffset; } const qreal newMaximumItemOffset = m_layouter->maximumItemOffset(); if (m_oldMaximumItemOffset != newMaximumItemOffset) { - emit maximumItemOffsetChanged(newMaximumItemOffset, m_oldMaximumItemOffset); + Q_EMIT maximumItemOffsetChanged(newMaximumItemOffset, m_oldMaximumItemOffset); m_oldMaximumItemOffset = newMaximumItemOffset; } } @@ -1978,7 +2075,12 @@ void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index) widget->setStyleOption(m_styleOption); const KItemListSelectionManager* selectionManager = m_controller->selectionManager(); - widget->setCurrent(index == selectionManager->currentItem()); + + // In SingleSelection mode (e.g., in the Places Panel), the current item is + // always the selected item. It is not necessary to highlight the current item then. + if (m_controller->selectionBehavior() != KItemListController::SingleSelection) { + widget->setCurrent(index == selectionManager->currentItem()); + } widget->setSelected(selectionManager->isSelected(index)); widget->setHovered(false); widget->setEnabledSelectionToggle(enabledSelectionToggles()); @@ -2014,7 +2116,7 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) groupHeader = groupHeaderCreator()->create(this); groupHeader->setParentItem(widget); m_visibleGroups.insert(widget, groupHeader); - connect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged())); + connect(widget, &KItemListWidget::geometryChanged, this, &KItemListView::slotGeometryOfGroupHeaderParentChanged); } Q_ASSERT(groupHeader->parentItem() == widget); @@ -2058,10 +2160,10 @@ void KItemListView::recycleGroupHeaderForWidget(KItemListWidget* widget) { KItemListGroupHeader* header = m_visibleGroups.value(widget); if (header) { - header->setParentItem(0); + header->setParentItem(nullptr); groupHeaderCreator()->recycle(header); m_visibleGroups.remove(widget); - disconnect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged())); + disconnect(widget, &KItemListWidget::geometryChanged, this, &KItemListView::slotGeometryOfGroupHeaderParentChanged); } } @@ -2152,7 +2254,7 @@ QHash KItemListView::preferredColumnWidths(const KItemRangeLi const QFontMetricsF fontMetrics(m_headerWidget->font()); const int gripMargin = m_headerWidget->style()->pixelMetric(QStyle::PM_HeaderGripMargin); const int headerMargin = m_headerWidget->style()->pixelMetric(QStyle::PM_HeaderMargin); - foreach (const QByteArray& visibleRole, visibleRoles()) { + for (const QByteArray& visibleRole : qAsConst(m_visibleRoles)) { const QString headerText = m_model->roleDescription(visibleRole); const qreal headerWidth = fontMetrics.width(headerText) + gripMargin + headerMargin * 2; widths.insert(visibleRole, headerWidth); @@ -2163,12 +2265,12 @@ QHash KItemListView::preferredColumnWidths(const KItemRangeLi const KItemListWidgetCreatorBase* creator = widgetCreator(); int calculatedItemCount = 0; bool maxTimeExceeded = false; - foreach (const KItemRange& itemRange, itemRanges) { + for (const KItemRange& itemRange : itemRanges) { const int startIndex = itemRange.index; const int endIndex = startIndex + itemRange.count - 1; for (int i = startIndex; i <= endIndex; ++i) { - foreach (const QByteArray& visibleRole, visibleRoles()) { + for (const QByteArray& visibleRole : qAsConst(m_visibleRoles)) { qreal maxWidth = widths.value(visibleRole, 0); const qreal width = creator->preferredRoleColumnWidth(visibleRole, i, this); maxWidth = qMax(width, maxWidth); @@ -2210,7 +2312,7 @@ void KItemListView::applyColumnWidthsFromHeader() void KItemListView::updateWidgetColumnWidths(KItemListWidget* widget) { - foreach (const QByteArray& role, m_visibleRoles) { + for (const QByteArray& role : qAsConst(m_visibleRoles)) { widget->setColumnWidth(role, m_headerWidget->columnWidth(role)); } } @@ -2220,13 +2322,13 @@ void KItemListView::updatePreferredColumnWidths(const KItemRangeList& itemRanges Q_ASSERT(m_itemSize.isEmpty()); const int itemCount = m_model->count(); int rangesItemCount = 0; - foreach (const KItemRange& range, itemRanges) { + for (const KItemRange& range : itemRanges) { rangesItemCount += range.count; } if (itemCount == rangesItemCount) { const QHash preferredWidths = preferredColumnWidths(itemRanges); - foreach (const QByteArray& role, m_visibleRoles) { + for (const QByteArray& role : qAsConst(m_visibleRoles)) { m_headerWidget->setPreferredColumnWidth(role, preferredWidths.value(role)); } } else { @@ -2281,7 +2383,7 @@ void KItemListView::applyAutomaticColumnWidths() // size does not use the available view-size the size of the // first role will get stretched. - foreach (const QByteArray& role, m_visibleRoles) { + for (const QByteArray& role : qAsConst(m_visibleRoles)) { const qreal preferredWidth = m_headerWidget->preferredColumnWidth(role); m_headerWidget->setColumnWidth(role, preferredWidth); } @@ -2328,7 +2430,7 @@ void KItemListView::applyAutomaticColumnWidths() qreal KItemListView::columnWidthsSum() const { qreal widthsSum = 0; - foreach (const QByteArray& role, m_visibleRoles) { + for (const QByteArray& role : qAsConst(m_visibleRoles)) { widthsSum += m_headerWidget->columnWidth(role); } return widthsSum; @@ -2422,7 +2524,7 @@ int KItemListView::showDropIndicator(const QPointF& pos) if (mappedPos.y() >= 0 && mappedPos.y() <= rect.height()) { if (m_model->supportsDropping(widget->index())) { // Keep 30% of the rectangle as the gap instead of always having a fixed gap - const int gap = qMax(4.0, 0.3 * rect.height()); + const int gap = qMax(qreal(4.0), qreal(0.3) * rect.height()); if (mappedPos.y() >= gap && mappedPos.y() <= rect.height() - gap) { return -1; } @@ -2469,7 +2571,7 @@ void KItemListView::updateGroupHeaderHeight() groupHeaderHeight += 2 * m_styleOption.horizontalMargin; groupHeaderMargin = m_styleOption.horizontalMargin; } else if (m_itemSize.isEmpty()){ - groupHeaderHeight += 4 * m_styleOption.padding; + groupHeaderHeight += 2 * m_styleOption.padding; groupHeaderMargin = m_styleOption.iconSize / 2; } else { groupHeaderHeight += 2 * m_styleOption.padding + m_styleOption.verticalMargin; @@ -2519,7 +2621,7 @@ void KItemListView::updateSiblingsInformation(int firstIndex, int lastIndex) const int parents = m_model->expandedParentsCount(lastIndex + 1); for (int i = lastIndex; i >= firstIndex; --i) { if (m_model->expandedParentsCount(i) != parents) { - widget = 0; + widget = nullptr; break; } } @@ -2610,13 +2712,14 @@ bool KItemListView::hasSiblingSuccessor(int index) const void KItemListView::disconnectRoleEditingSignals(int index) { - KItemListWidget* widget = m_visibleItems.value(index); + KStandardItemListWidget* widget = qobject_cast(m_visibleItems.value(index)); if (!widget) { return; } - widget->disconnect(SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)), this); - widget->disconnect(SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), this); + disconnect(widget, &KItemListWidget::roleEditingCanceled, this, nullptr); + disconnect(widget, &KItemListWidget::roleEditingFinished, this, nullptr); + disconnect(this, &KItemListView::scrollOffsetChanged, widget, nullptr); } int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc) @@ -2681,7 +2784,7 @@ void KItemListCreatorBase::pushRecycleableWidget(QGraphicsWidget* widget) QGraphicsWidget* KItemListCreatorBase::popRecycleableWidget() { if (m_recycleableWidgets.isEmpty()) { - return 0; + return nullptr; } QGraphicsWidget* widget = m_recycleableWidgets.takeLast(); @@ -2695,7 +2798,7 @@ KItemListWidgetCreatorBase::~KItemListWidgetCreatorBase() void KItemListWidgetCreatorBase::recycle(KItemListWidget* widget) { - widget->setParentItem(0); + widget->setParentItem(nullptr); widget->setOpacity(1.0); pushRecycleableWidget(widget); } @@ -2710,4 +2813,3 @@ void KItemListGroupHeaderCreatorBase::recycle(KItemListGroupHeader* header) pushRecycleableWidget(header); } -#include "kitemlistview.moc"