]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistview.cpp
Merge branch 'release/22.04'
[dolphin.git] / src / kitemviews / kitemlistview.cpp
index 0d0304afcb5accd3221881986ffe360280147342..562a45e1877a2e22be67d09b295b0862b4abd495 100644 (file)
@@ -1,51 +1,34 @@
-/***************************************************************************
- *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
- *                                                                         *
- *   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 <peter.penz19@gmail.com>
+ *
+ * Based on the Itemviews NG project from Trolltech Labs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
 
 #include "kitemlistview.h"
 
-#include <QDebug>
+#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 <QElapsedTimer>
 #include <QGraphicsSceneMouseEvent>
 #include <QGraphicsView>
-#include <QPainter>
-#include <QStyle>
+#include <QPropertyAnimation>
 #include <QStyleOptionRubberBand>
 #include <QTimer>
-#include <QElapsedTimer>
-
-#include <algorithm>
+#include <QVariantAnimation>
 
-#include "kitemlistviewaccessible.h"
 
 namespace {
     // Time in ms until reaching the autoscroll margin triggers
@@ -54,6 +37,11 @@ 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
@@ -67,7 +55,7 @@ QAccessibleInterface* accessibleInterfaceFactory(const QString& key, QObject* ob
         return new KItemListViewAccessible(view);
     }
 
-    return 0;
+    return nullptr;
 }
 #endif
 
@@ -80,33 +68,35 @@ 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_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);
 
@@ -116,14 +106,26 @@ KItemListView::KItemListView(QGraphicsWidget* parent) :
     connect(m_animation, &KItemListViewAnimation::finished,
             this, &KItemListView::slotAnimationFinished);
 
-    m_layoutTimer = new QTimer(this);
-    m_layoutTimer->setInterval(300);
-    m_layoutTimer->setSingleShot(true);
-    connect(m_layoutTimer, &QTimer::timeout, this, &KItemListView::slotLayoutTimerFinished);
-
     m_rubberBand = new KItemListRubberBand(this);
     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);
 
@@ -141,13 +143,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)
@@ -228,7 +230,7 @@ void KItemListView::setVisibleRoles(const QList<QByteArray>& 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);
@@ -270,13 +272,13 @@ void KItemListView::setAutoScroll(bool enabled)
         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)
@@ -309,9 +311,7 @@ KItemModelBase* KItemListView::model() const
 
 void KItemListView::setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator)
 {
-    if (m_widgetCreator) {
-        delete m_widgetCreator;
-    }
+    delete m_widgetCreator;
     m_widgetCreator = widgetCreator;
 }
 
@@ -325,9 +325,7 @@ KItemListWidgetCreatorBase* KItemListView::widgetCreator() const
 
 void KItemListView::setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator)
 {
-    if (m_groupHeaderCreator) {
-        delete m_groupHeaderCreator;
-    }
+    delete m_groupHeaderCreator;
     m_groupHeaderCreator = groupHeaderCreator;
 }
 
@@ -368,29 +366,12 @@ void KItemListView::setGeometry(const QRectF& rect)
                                          m_itemSize.height());
             m_layouter->setItemSize(dynamicItemSize);
         }
-
-        // Triggering a synchronous layout is fine from a performance point of view,
-        // as with dynamic item sizes no moving animation must be done.
-        m_layouter->setSize(newSize);
-        doLayout(NoAnimation);
-    } else {
-        const bool animate = !changesItemGridLayout(newSize,
-                                                    m_layouter->itemSize(),
-                                                    m_layouter->itemMargin());
-        m_layouter->setSize(newSize);
-
-        if (animate) {
-            // Trigger an asynchronous relayout with m_layoutTimer to prevent
-            // performance bottlenecks. If the timer is exceeded, an animated layout
-            // will be triggered.
-            if (!m_layoutTimer->isActive()) {
-                m_layoutTimer->start();
-            }
-        } else {
-            m_layoutTimer->stop();
-            doLayout(NoAnimation);
-        }
     }
+
+    m_layouter->setSize(newSize);
+    // We don't animate the moving of the items here because
+    // it would look like the items are slow to find their position.
+    doLayout(NoAnimation);
 }
 
 qreal KItemListView::verticalPageStep() const
@@ -402,7 +383,7 @@ qreal KItemListView::verticalPageStep() const
     return size().height() - headerHeight;
 }
 
-int KItemListView::itemAt(const QPointF& pos) const
+std::optional<int> KItemListView::itemAt(const QPointF& pos) const
 {
     QHashIterator<int, KItemListWidget*> it(m_visibleItems);
     while (it.hasNext()) {
@@ -410,12 +391,12 @@ int KItemListView::itemAt(const QPointF& pos) const
 
         const KItemListWidget* widget = it.value();
         const QPointF mappedPos = widget->mapFromItem(this, pos);
-        if (widget->contains(mappedPos)) {
+        if (widget->contains(mappedPos) || widget->selectionRect().contains(mappedPos)) {
             return it.key();
         }
     }
 
-    return -1;
+    return std::nullopt;
 }
 
 bool KItemListView::isAboveSelectionToggle(int index, const QPointF& pos) const
@@ -448,6 +429,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();
@@ -458,7 +452,7 @@ int KItemListView::lastVisibleIndex() const
     return m_layouter->lastVisibleIndex();
 }
 
-void KItemListView::calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint) const
+void KItemListView::calculateItemSizeHints(QVector<std::pair<qreal, bool>>& logicalHeightHints, qreal& logicalWidthHint) const
 {
     widgetCreator()->calculateItemSizeHints(logicalHeightHints, logicalWidthHint, this);
 }
@@ -477,6 +471,32 @@ bool KItemListView::supportsItemExpanding() const
     return m_supportsItemExpanding;
 }
 
+void KItemListView::setHighlightEntireRow(bool highlightEntireRow)
+{
+    if (m_highlightEntireRow != highlightEntireRow) {
+        m_highlightEntireRow = highlightEntireRow;
+        onHighlightEntireRowChanged(highlightEntireRow);
+    }
+}
+
+bool KItemListView::highlightEntireRow() const
+{
+    return m_highlightEntireRow;
+}
+
+void KItemListView::setAlternateBackgrounds(bool alternate)
+{
+    if (m_alternateBackgrounds != alternate) {
+        m_alternateBackgrounds = alternate;
+        updateAlternateBackgrounds();
+    }
+}
+
+bool KItemListView::alternateBackgrounds() const
+{
+    return m_alternateBackgrounds;
+}
+
 QRectF KItemListView::itemRect(int index) const
 {
     return m_layouter->itemRect(index);
@@ -495,6 +515,11 @@ QRectF KItemListView::itemContextRect(int index) const
     return contextRect;
 }
 
+bool KItemListView::isElided(int index) const
+{
+    return m_sizeHintResolver->isElided(index);
+}
+
 void KItemListView::scrollToItem(int index)
 {
     QRectF viewGeometry = geometry();
@@ -525,9 +550,12 @@ void KItemListView::scrollToItem(int index)
         }
 
         if (newOffset != scrollOffset()) {
-            emit scrollTo(newOffset);
+            Q_EMIT scrollTo(newOffset);
+            return;
         }
     }
+
+    Q_EMIT scrollingStopped();
 }
 
 void KItemListView::beginTransaction()
@@ -543,7 +571,7 @@ void KItemListView::endTransaction()
     --m_activeTransactions;
     if (m_activeTransactions < 0) {
         m_activeTransactions = 0;
-        qWarning() << "Mismatch between beginTransaction()/endTransaction()";
+        qCWarning(DolphinDebug) << "Mismatch between beginTransaction()/endTransaction()";
     }
 
     if (m_activeTransactions == 0) {
@@ -573,6 +601,8 @@ void KItemListView::setHeaderVisible(bool visible)
 
         connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
                 this, &KItemListView::slotHeaderColumnWidthChanged);
+        connect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
+                this, &KItemListView::slotLeadingPaddingChanged);
         connect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
                 this, &KItemListView::slotHeaderColumnMoved);
         connect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
@@ -585,6 +615,8 @@ void KItemListView::setHeaderVisible(bool visible)
     } else if (!visible && m_headerWidget->isVisible()) {
         disconnect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
                    this, &KItemListView::slotHeaderColumnWidthChanged);
+        disconnect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
+                this, &KItemListView::slotLeadingPaddingChanged);
         disconnect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
                    this, &KItemListView::slotHeaderColumnMoved);
         disconnect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
@@ -615,7 +647,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
@@ -628,7 +660,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<KStandardItemListWidget *>(m_visibleItems.value(index));
     if (!widget || m_editingRole) {
         return;
     }
@@ -640,12 +672,39 @@ void KItemListView::editRole(int index, const QByteArray& role)
             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();
@@ -658,7 +717,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();
@@ -668,7 +739,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
@@ -706,7 +777,7 @@ void KItemListView::setItemSize(const QSizeF& size)
                                                 size,
                                                 m_layouter->itemMargin());
 
-    const bool alternateBackgroundsChanged = (m_visibleRoles.count() > 1) &&
+    const bool alternateBackgroundsChanged = m_alternateBackgrounds &&
                                              (( m_itemSize.isEmpty() && !size.isEmpty()) ||
                                               (!m_itemSize.isEmpty() && size.isEmpty()));
 
@@ -740,6 +811,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;
 
@@ -807,7 +882,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
@@ -817,70 +892,75 @@ 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<QByteArray>& 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<QByteArray>& current, const QList<QByteArray>& 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::onHighlightEntireRowChanged(bool highlightEntireRow)
+{
+    Q_UNUSED(highlightEntireRow)
 }
 
 void KItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
 {
-    Q_UNUSED(supportsExpanding);
+    Q_UNUSED(supportsExpanding)
 }
 
 void KItemListView::onTransactionBegin()
@@ -999,14 +1079,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) {
-            qWarning() << "Invalid item range (index:" << index << ", count:" << count << ")";
+            qCWarning(DolphinDebug) << "Invalid item range (index:" << index << ", count:" << count << ")";
             continue;
         }
         previouslyInsertedCount += count;
@@ -1025,7 +1105,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);
@@ -1114,18 +1194,21 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
         const int index = range.index;
         const int count = range.count;
         if (index < 0 || count <= 0) {
-            qWarning() << "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<int> 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;
@@ -1161,7 +1244,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;
@@ -1239,17 +1322,13 @@ 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;
 
         if (updateSizeHints) {
             m_sizeHintResolver->itemsChanged(index, count, roles);
             m_layouter->markAsDirty();
-
-            if (!m_layoutTimer->isActive()) {
-                m_layoutTimer->start();
-            }
         }
 
         // Apply the changed roles to the visible item-widgets
@@ -1273,6 +1352,8 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges,
         ev.setLastRow(itemRange.index + itemRange.count);
         QAccessible::updateAccessibility(&ev);
     }
+
+    doLayout(NoAnimation);
 }
 
 void KItemListView::slotGroupsChanged()
@@ -1313,8 +1394,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);
@@ -1323,8 +1404,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);
@@ -1333,17 +1414,17 @@ void KItemListView::slotSortRoleChanged(const QByteArray& current, const QByteAr
 
 void KItemListView::slotCurrentChanged(int current, int previous)
 {
-    Q_UNUSED(previous);
+    Q_UNUSED(previous)
 
     // 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, 0);
+        KItemListWidget* previousWidget = m_visibleItems.value(previous, nullptr);
         if (previousWidget) {
             previousWidget->setCurrent(false);
         }
 
-        KItemListWidget* currentWidget = m_visibleItems.value(current, 0);
+        KItemListWidget* currentWidget = m_visibleItems.value(current, nullptr);
         if (currentWidget) {
             currentWidget->setCurrent(true);
         }
@@ -1356,7 +1437,7 @@ void KItemListView::slotCurrentChanged(int current, int previous)
 
 void KItemListView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous)
 {
-    Q_UNUSED(previous);
+    Q_UNUSED(previous)
 
     QHashIterator<int, KItemListWidget*> it(m_visibleItems);
     while (it.hasNext()) {
@@ -1373,8 +1454,7 @@ void KItemListView::slotAnimationFinished(QGraphicsWidget* widget,
     KItemListWidget* itemListWidget = qobject_cast<KItemListWidget*>(widget);
     Q_ASSERT(itemListWidget);
 
-    switch (type) {
-    case KItemListViewAnimation::DeleteAnimation: {
+    if (type == KItemListViewAnimation::DeleteAnimation) {
         // As we recycle the widget in this case it is important to assure that no
         // other animation has been started. This is a convention in KItemListView and
         // not a requirement defined by KItemListViewAnimation.
@@ -1385,29 +1465,14 @@ void KItemListView::slotAnimationFinished(QGraphicsWidget* widget,
         // been finished.
         recycleGroupHeaderForWidget(itemListWidget);
         widgetCreator()->recycle(itemListWidget);
-        break;
-    }
-
-    case KItemListViewAnimation::CreateAnimation:
-    case KItemListViewAnimation::MovingAnimation:
-    case KItemListViewAnimation::ResizeAnimation: {
+    } else {
         const int index = itemListWidget->index();
         const bool invisible = (index < m_layouter->firstVisibleIndex()) ||
                                (index > m_layouter->lastVisibleIndex());
         if (invisible && !m_animation->isStarted(itemListWidget)) {
             recycleWidget(itemListWidget);
         }
-        break;
     }
-
-    default: break;
-    }
-}
-
-void KItemListView::slotLayoutTimerFinished()
-{
-    m_layouter->setSize(geometry().size());
-    doLayout(Animation);
 }
 
 void KItemListView::slotRubberBandPosChanged()
@@ -1422,6 +1487,30 @@ void KItemListView::slotRubberBandActivationChanged(bool active)
         connect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
         m_skipAutoScrollForRubberBand = true;
     } else {
+        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;
@@ -1434,15 +1523,25 @@ 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();
     doLayout(NoAnimation);
 }
 
+void KItemListView::slotLeadingPaddingChanged(qreal width)
+{
+    Q_UNUSED(width)
+    if (m_headerWidget->automaticColumnResizing()) {
+        applyAutomaticColumnWidths();
+    }
+    applyColumnWidthsFromHeader();
+    doLayout(NoAnimation);
+}
+
 void KItemListView::slotHeaderColumnMoved(const QByteArray& role,
                                           int currentIndex,
                                           int previousIndex)
@@ -1457,7 +1556,7 @@ void KItemListView::slotHeaderColumnMoved(const QByteArray& role,
 
     setVisibleRoles(current);
 
-    emit visibleRolesChanged(current, previous);
+    Q_EMIT visibleRolesChanged(current, previous);
 }
 
 void KItemListView::triggerAutoScrolling()
@@ -1532,16 +1631,16 @@ void KItemListView::slotRoleEditingCanceled(int index, const QByteArray& role, c
 {
     disconnectRoleEditingSignals(index);
 
-    emit roleEditingCanceled(index, role, value);
     m_editingRole = false;
+    Q_EMIT roleEditingCanceled(index, role, value);
 }
 
 void KItemListView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
 {
     disconnectRoleEditingSignals(index);
 
-    emit roleEditingFinished(index, role, value);
     m_editingRole = false;
+    Q_EMIT roleEditingFinished(index, role, value);
 }
 
 void KItemListView::setController(KItemListController* controller)
@@ -1633,10 +1732,6 @@ KItemListRubberBand* KItemListView::rubberBand() const
 
 void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount)
 {
-    if (m_layoutTimer->isActive()) {
-        m_layoutTimer->stop();
-    }
-
     if (m_activeTransactions > 0) {
         if (hint == NoAnimation) {
             // As soon as at least one property change should be done without animation,
@@ -1680,13 +1775,11 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
     const bool animate = (hint == Animation);
     for (int i = firstVisibleIndex; i <= lastVisibleIndex; ++i) {
         bool applyNewPos = true;
-        bool wasHidden = false;
 
         const QRectF itemBounds = m_layouter->itemRect(i);
         const QPointF newPos = itemBounds.topLeft();
         KItemListWidget* widget = m_visibleItems.value(i);
         if (!widget) {
-            wasHidden = true;
             if (!reusableItems.isEmpty()) {
                 // Reuse a KItemListWidget instance from an invisible item
                 const int oldIndex = reusableItems.takeLast();
@@ -1753,9 +1846,6 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
                     // prevents a "move animation mess" when inserting several ranges in parallel.
                     applyNewPos = !moveWidget(widget, newPos);
                 }
-            } else if (!itemsRemoved && !itemsInserted && !wasHidden) {
-                // The size of the view might have been changed. Animate the moving of the position.
-                applyNewPos = !moveWidget(widget, newPos);
             }
         } else {
             m_animation->stop(widget);
@@ -1768,6 +1858,8 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
         Q_ASSERT(widget->index() == i);
         widget->setVisible(true);
 
+        bool animateIconResizing = animate;
+
         if (widget->size() != itemBounds.size()) {
             // Resize the widget for the item to the changed size.
             if (animate) {
@@ -1784,6 +1876,17 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
             } else {
                 widget->resize(itemBounds.size());
             }
+        } else {
+            animateIconResizing = false;
+        }
+
+        const int newIconSize = widget->styleOption().iconSize;
+        if (widget->iconSize() != newIconSize) {
+            if (animateIconResizing) {
+                m_animation->start(widget, KItemListViewAnimation::IconResizeAnimation, newIconSize);
+            } else {
+                widget->setIconSize(newIconSize);
+            }
         }
 
         // Updating the cell-information must be done as last step: The decision whether the
@@ -1793,7 +1896,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));
     }
 
@@ -1896,25 +1999,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;
     }
 }
@@ -2073,7 +2176,7 @@ 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, &KItemListWidget::geometryChanged, this, &KItemListView::slotGeometryOfGroupHeaderParentChanged);
@@ -2152,7 +2255,7 @@ void KItemListView::updateAlternateBackgroundForWidget(KItemListWidget* widget)
 
 bool KItemListView::useAlternateBackgrounds() const
 {
-    return m_itemSize.isEmpty() && m_visibleRoles.count() > 1;
+    return m_alternateBackgrounds && m_itemSize.isEmpty();
 }
 
 QHash<QByteArray, qreal> KItemListView::preferredColumnWidths(const KItemRangeList& itemRanges) const
@@ -2167,23 +2270,23 @@ QHash<QByteArray, qreal> 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;
+        const qreal headerWidth = fontMetrics.horizontalAdvance(headerText) + gripMargin + headerMargin * 2;
         widths.insert(visibleRole, headerWidth);
     }
 
-    // Calculate the preferred column withs for each item and ignore values
+    // Calculate the preferred column widths for each item and ignore values
     // smaller than the width for showing the headline unclipped.
     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 +2313,7 @@ QHash<QByteArray, qreal> KItemListView::preferredColumnWidths(const KItemRangeLi
 void KItemListView::applyColumnWidthsFromHeader()
 {
     // Apply the new size to the layouter
-    const qreal requiredWidth = columnWidthsSum();
+    const qreal requiredWidth = columnWidthsSum() + m_headerWidget->leadingPadding();
     const QSizeF dynamicItemSize(qMax(size().width(), requiredWidth),
                                  m_itemSize.height());
     m_layouter->setItemSize(dynamicItemSize);
@@ -2225,9 +2328,10 @@ 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));
     }
+    widget->setLeadingPadding(m_headerWidget->leadingPadding());
 }
 
 void KItemListView::updatePreferredColumnWidths(const KItemRangeList& itemRanges)
@@ -2235,13 +2339,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<QByteArray, qreal> preferredWidths = preferredColumnWidths(itemRanges);
-        foreach (const QByteArray& role, m_visibleRoles) {
+        for (const QByteArray& role : qAsConst(m_visibleRoles)) {
             m_headerWidget->setPreferredColumnWidth(role, preferredWidths.value(role));
         }
     } else {
@@ -2296,7 +2400,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);
     }
@@ -2305,7 +2409,9 @@ void KItemListView::applyAutomaticColumnWidths()
     qreal firstColumnWidth = m_headerWidget->columnWidth(firstRole);
     QSizeF dynamicItemSize = m_itemSize;
 
-    qreal requiredWidth = columnWidthsSum();
+    qreal requiredWidth = columnWidthsSum() + m_headerWidget->leadingPadding()
+        + m_headerWidget->leadingPadding(); // Adding the padding a second time so we have the same padding symmetrically on both sides of the view.
+        // This improves UX, looks better and increases the chances of users figuring out that the padding area can be used for deselecting and dropping files.
     const qreal availableWidth = size().width();
     if (requiredWidth < availableWidth) {
         // Stretch the first column to use the whole remaining width
@@ -2343,7 +2449,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;
@@ -2437,7 +2543,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;
                 }
@@ -2534,7 +2640,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;
                 }
             }
@@ -2625,13 +2731,14 @@ bool KItemListView::hasSiblingSuccessor(int index) const
 
 void KItemListView::disconnectRoleEditingSignals(int index)
 {
-    KItemListWidget* widget = m_visibleItems.value(index);
+    KStandardItemListWidget* widget = qobject_cast<KStandardItemListWidget *>(m_visibleItems.value(index));
     if (!widget) {
         return;
     }
 
     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)
@@ -2696,7 +2803,7 @@ void KItemListCreatorBase::pushRecycleableWidget(QGraphicsWidget* widget)
 QGraphicsWidget* KItemListCreatorBase::popRecycleableWidget()
 {
     if (m_recycleableWidgets.isEmpty()) {
-        return 0;
+        return nullptr;
     }
 
     QGraphicsWidget* widget = m_recycleableWidgets.takeLast();
@@ -2710,7 +2817,7 @@ KItemListWidgetCreatorBase::~KItemListWidgetCreatorBase()
 
 void KItemListWidgetCreatorBase::recycle(KItemListWidget* widget)
 {
-    widget->setParentItem(0);
+    widget->setParentItem(nullptr);
     widget->setOpacity(1.0);
     pushRecycleableWidget(widget);
 }