]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/private/kitemlistheaderwidget.cpp
Merge remote-tracking branch 'origin/master' into kf6
[dolphin.git] / src / kitemviews / private / kitemlistheaderwidget.cpp
index a3f3f521fa4063beb9504a5fbd06893889e72d69..02a4f939d13b2e26f0b3e43ed301799a6a57e739 100644 (file)
@@ -1,21 +1,8 @@
-/***************************************************************************
- *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
- *                                                                         *
- *   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>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
 
 #include "kitemlistheaderwidget.h"
 #include "kitemviews/kitemmodelbase.h"
 #include <QPainter>
 #include <QStyleOptionHeader>
 
-
-KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) :
-    QGraphicsWidget(parent),
-    m_automaticColumnResizing(true),
-    m_model(nullptr),
-    m_offset(0),
-    m_columns(),
-    m_columnWidths(),
-    m_preferredColumnWidths(),
-    m_hoveredRoleIndex(-1),
-    m_pressedRoleIndex(-1),
-    m_roleOperation(NoRoleOperation),
-    m_pressedMousePos(),
-    m_movingRole()
+KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget *parent)
+    : QGraphicsWidget(parent)
+    , m_automaticColumnResizing(true)
+    , m_model(nullptr)
+    , m_offset(0)
+    , m_sidePadding(0)
+    , m_columns()
+    , m_columnWidths()
+    , m_preferredColumnWidths()
+    , m_hoveredIndex(-1)
+    , m_pressedRoleIndex(-1)
+    , m_roleOperation(NoRoleOperation)
+    , m_pressedMousePos()
+    m_movingRole()
 {
     m_movingRole.x = 0;
     m_movingRole.xDec = 0;
     m_movingRole.index = -1;
 
     setAcceptHoverEvents(true);
+    // TODO update when font changes at runtime
+    setFont(QApplication::font("QHeaderView"));
 }
 
 KItemListHeaderWidget::~KItemListHeaderWidget()
 {
 }
 
-void KItemListHeaderWidget::setModel(KItemModelBasemodel)
+void KItemListHeaderWidget::setModel(KItemModelBase *model)
 {
     if (m_model == model) {
         return;
     }
 
     if (m_model) {
-        disconnect(m_model, &KItemModelBase::sortRoleChanged,
-                   this, &KItemListHeaderWidget::slotSortRoleChanged);
-        disconnect(m_model, &KItemModelBase::sortOrderChanged,
-                   this, &KItemListHeaderWidget::slotSortOrderChanged);
+        disconnect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListHeaderWidget::slotSortRoleChanged);
+        disconnect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListHeaderWidget::slotSortOrderChanged);
     }
 
     m_model = model;
 
     if (m_model) {
-        connect(m_model, &KItemModelBase::sortRoleChanged,
-                this, &KItemListHeaderWidget::slotSortRoleChanged);
-        connect(m_model, &KItemModelBase::sortOrderChanged,
-                this, &KItemListHeaderWidget::slotSortOrderChanged);
+        connect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListHeaderWidget::slotSortRoleChanged);
+        connect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListHeaderWidget::slotSortOrderChanged);
     }
 }
 
-KItemModelBaseKItemListHeaderWidget::model() const
+KItemModelBase *KItemListHeaderWidget::model() const
 {
     return m_model;
 }
@@ -89,11 +74,10 @@ bool KItemListHeaderWidget::automaticColumnResizing() const
     return m_automaticColumnResizing;
 }
 
-void KItemListHeaderWidget::setColumns(const QList<QByteArray>roles)
+void KItemListHeaderWidget::setColumns(const QList<QByteArray> &roles)
 {
-    foreach (const QByteArray& role, roles) {
+    for (const QByteArray &role : roles) {
         if (!m_columnWidths.contains(role)) {
-            m_columnWidths.remove(role);
             m_preferredColumnWidths.remove(role);
         }
     }
@@ -107,7 +91,7 @@ QList<QByteArray> KItemListHeaderWidget::columns() const
     return m_columns;
 }
 
-void KItemListHeaderWidget::setColumnWidth(const QByteArrayrole, qreal width)
+void KItemListHeaderWidget::setColumnWidth(const QByteArray &role, qreal width)
 {
     const qreal minWidth = minimumColumnWidth();
     if (width < minWidth) {
@@ -120,17 +104,17 @@ void KItemListHeaderWidget::setColumnWidth(const QByteArray& role, qreal width)
     }
 }
 
-qreal KItemListHeaderWidget::columnWidth(const QByteArrayrole) const
+qreal KItemListHeaderWidget::columnWidth(const QByteArray &role) const
 {
     return m_columnWidths.value(role);
 }
 
-void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArrayrole, qreal width)
+void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArray &role, qreal width)
 {
     m_preferredColumnWidths.insert(role, width);
 }
 
-qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArrayrole) const
+qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArray &role) const
 {
     return m_preferredColumnWidths.value(role);
 }
@@ -148,16 +132,30 @@ qreal KItemListHeaderWidget::offset() const
     return m_offset;
 }
 
+void KItemListHeaderWidget::setSidePadding(qreal width)
+{
+    if (m_sidePadding != width) {
+        m_sidePadding = width;
+        Q_EMIT sidePaddingChanged(width);
+        update();
+    }
+}
+
+qreal KItemListHeaderWidget::sidePadding() const
+{
+    return m_sidePadding;
+}
+
 qreal KItemListHeaderWidget::minimumColumnWidth() const
 {
     QFontMetricsF fontMetrics(font());
     return fontMetrics.height() * 4;
 }
 
-void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+void KItemListHeaderWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
 {
-    Q_UNUSED(option);
-    Q_UNUSED(widget);
+    Q_UNUSED(option)
+    Q_UNUSED(widget)
 
     if (!m_model) {
         return;
@@ -167,9 +165,9 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI
     painter->setFont(font());
     painter->setPen(palette().text().color());
 
-    qreal x = -m_offset;
+    qreal x = -m_offset + m_sidePadding;
     int orderIndex = 0;
-    foreach (const QByteArray& role, m_columns) {
+    for (const QByteArray &role : std::as_const(m_columns)) {
         const qreal roleWidth = m_columnWidths.value(role);
         const QRectF rect(x, 0, roleWidth, size().height());
         paintRole(painter, role, rect, orderIndex, widget);
@@ -183,20 +181,23 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI
     }
 }
 
-void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEventevent)
+void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
 {
     if (event->button() & Qt::LeftButton) {
-        updatePressedRoleIndex(event->pos());
         m_pressedMousePos = event->pos();
-        m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
-                          ResizeRoleOperation : NoRoleOperation;
+        if (isAbovePaddingGrip(m_pressedMousePos, PaddingGrip::Leading)) {
+            m_roleOperation = ResizePaddingColumnOperation;
+        } else {
+            updatePressedRoleIndex(event->pos());
+            m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? ResizeRoleOperation : NoRoleOperation;
+        }
         event->accept();
     } else {
         event->ignore();
     }
 }
 
-void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEventevent)
+void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 {
     QGraphicsWidget::mouseReleaseEvent(event);
 
@@ -212,21 +213,20 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
         if (m_pressedRoleIndex == sortRoleIndex) {
             // Toggle the sort order
             const Qt::SortOrder previous = m_model->sortOrder();
-            const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ?
-                                          Qt::DescendingOrder : Qt::AscendingOrder;
+            const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder;
             m_model->setSortOrder(current);
-            emit sortOrderChanged(current, previous);
+            Q_EMIT sortOrderChanged(current, previous);
         } else {
             // Change the sort role and reset to the ascending order
             const QByteArray previous = m_model->sortRole();
             const QByteArray current = m_columns[m_pressedRoleIndex];
             const bool resetSortOrder = m_model->sortOrder() == Qt::DescendingOrder;
             m_model->setSortRole(current, !resetSortOrder);
-            emit sortRoleChanged(current, previous);
+            Q_EMIT sortRoleChanged(current, previous);
 
             if (resetSortOrder) {
                 m_model->setSortOrder(Qt::AscendingOrder);
-                emit sortOrderChanged(Qt::AscendingOrder, Qt::DescendingOrder);
+                Q_EMIT sortOrderChanged(Qt::AscendingOrder, Qt::DescendingOrder);
             }
         }
         break;
@@ -235,7 +235,7 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
     case ResizeRoleOperation: {
         const QByteArray pressedRole = m_columns[m_pressedRoleIndex];
         const qreal currentWidth = m_columnWidths.value(pressedRole);
-        emit columnWidthChangeFinished(pressedRole, currentWidth);
+        Q_EMIT columnWidthChangeFinished(pressedRole, currentWidth);
         break;
     }
 
@@ -257,7 +257,7 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
     QApplication::restoreOverrideCursor();
 }
 
-void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEventevent)
+void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 {
     QGraphicsWidget::mouseMoveEvent(event);
 
@@ -265,7 +265,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
     case NoRoleOperation:
         if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) {
             // A role gets dragged by the user. Create a pixmap of the role that will get
-            // synchronized on each furter mouse-move-event with the mouse-position.
+            // synchronized on each further mouse-move-event with the mouse-position.
             m_roleOperation = MoveRoleOperation;
             const int roleIndex = roleIndexAt(m_pressedMousePos);
             m_movingRole.index = roleIndex;
@@ -277,7 +277,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
             } else {
                 m_movingRole.pixmap = createRolePixmap(roleIndex);
 
-                qreal roleX = -m_offset;
+                qreal roleX = -m_offset + m_sidePadding;
                 for (int i = 0; i < roleIndex; ++i) {
                     const QByteArray role = m_columns[i];
                     roleX += m_columnWidths.value(role);
@@ -301,7 +301,21 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
         m_columnWidths.insert(pressedRole, currentWidth);
         update();
 
-        emit columnWidthChanged(pressedRole, currentWidth, previousWidth);
+        Q_EMIT columnWidthChanged(pressedRole, currentWidth, previousWidth);
+        break;
+    }
+
+    case ResizePaddingColumnOperation: {
+        qreal currentWidth = m_sidePadding;
+        currentWidth += event->pos().x() - event->lastPos().x();
+        currentWidth = qMax(0.0, currentWidth);
+
+        m_sidePadding = currentWidth;
+
+        update();
+
+        Q_EMIT sidePaddingChanged(currentWidth);
+
         break;
     }
 
@@ -318,7 +332,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
                 const QByteArray role = m_columns[m_movingRole.index];
                 const int previousIndex = m_movingRole.index;
                 m_movingRole.index = targetIndex;
-                emit columnMoved(role, targetIndex, previousIndex);
+                Q_EMIT columnMoved(role, targetIndex, previousIndex);
 
                 m_movingRole.xDec = event->pos().x() - roleXPosition(role);
             }
@@ -331,7 +345,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
     }
 }
 
-void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEventevent)
+void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
 {
     QGraphicsItem::mouseDoubleClickEvent(event);
 
@@ -343,62 +357,65 @@ void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* even
         setColumnWidth(role, preferredColumnWidth(role));
         qreal currentWidth = columnWidth(role);
 
-        emit columnWidthChanged(role, currentWidth, previousWidth);
-        emit columnWidthChangeFinished(role, currentWidth);
+        Q_EMIT columnWidthChanged(role, currentWidth, previousWidth);
+        Q_EMIT columnWidthChangeFinished(role, currentWidth);
     }
 }
 
-void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEventevent)
+void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
 {
     QGraphicsWidget::hoverEnterEvent(event);
-    updateHoveredRoleIndex(event->pos());
+    updateHoveredIndex(event->pos());
 }
 
-void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEventevent)
+void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
 {
     QGraphicsWidget::hoverLeaveEvent(event);
-    if (m_hoveredRoleIndex != -1) {
-        m_hoveredRoleIndex = -1;
+    if (m_hoveredIndex != -1) {
+        Q_EMIT columnUnHovered(m_hoveredIndex);
+        m_hoveredIndex = -1;
         update();
     }
 }
 
-void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEventevent)
+void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
 {
     QGraphicsWidget::hoverMoveEvent(event);
 
-    const QPointF& pos = event->pos();
-    updateHoveredRoleIndex(pos);
-    if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
+    const QPointF &pos = event->pos();
+    updateHoveredIndex(pos);
+    if ((m_hoveredIndex >= 0 && isAboveRoleGrip(pos, m_hoveredIndex)) || isAbovePaddingGrip(pos, PaddingGrip::Leading)
+        || isAbovePaddingGrip(pos, PaddingGrip::Trailing)) {
         setCursor(Qt::SplitHCursor);
     } else {
         unsetCursor();
     }
 }
 
-void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray &current, const QByteArray &previous)
 {
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
+    Q_UNUSED(current)
+    Q_UNUSED(previous)
     update();
 }
 
 void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
 {
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
+    Q_UNUSED(current)
+    Q_UNUSED(previous)
     update();
 }
 
-void KItemListHeaderWidget::paintRole(QPainter* painter,
-                                      const QByteArray& role,
-                                      const QRectF& rect,
-                                      int orderIndex,
-                                      QWidget* widget) const
+void KItemListHeaderWidget::paintRole(QPainter *painter, const QByteArray &role, const QRectF &rect, int orderIndex, QWidget *widget) const
 {
+    const auto direction = widget ? widget->layoutDirection() : qApp->layoutDirection();
+
     // The following code is based on the code from QHeaderView::paintSection().
-    // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+    // SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies).
     QStyleOptionHeader option;
+    option.direction = direction;
+    option.textAlignment = direction == Qt::LeftToRight ? Qt::AlignLeft : Qt::AlignRight;
+
     option.section = orderIndex;
     option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
     if (isEnabled()) {
@@ -407,30 +424,49 @@ void KItemListHeaderWidget::paintRole(QPainter* painter,
     if (window() && window()->isActiveWindow()) {
         option.state |= QStyle::State_Active;
     }
-    if (m_hoveredRoleIndex == orderIndex) {
+    if (m_hoveredIndex == orderIndex) {
         option.state |= QStyle::State_MouseOver;
     }
     if (m_pressedRoleIndex == orderIndex) {
         option.state |= QStyle::State_Sunken;
     }
     if (m_model->sortRole() == role) {
-        option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ?
-                                QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+        option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
     }
     option.rect = rect.toRect();
+    option.orientation = Qt::Horizontal;
+    option.selectedPosition = QStyleOptionHeader::NotAdjacent;
+    option.text = m_model->roleDescription(role);
 
-    bool paintBackgroundForEmptyArea = false;
+    // First we paint any potential empty (padding) space on left and/or right of this role's column.
+    const auto paintPadding = [&](int section, const QRectF &rect, const QStyleOptionHeader::SectionPosition &pos) {
+        QStyleOptionHeader padding;
+        padding.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
+        padding.section = section;
+        padding.sortIndicator = QStyleOptionHeader::None;
+        padding.rect = rect.toRect();
+        padding.position = pos;
+        padding.text = QString();
+        style()->drawControl(QStyle::CE_Header, &padding, painter, widget);
+    };
 
     if (m_columns.count() == 1) {
-        option.position = QStyleOptionHeader::OnlyOneSection;
+        option.position = QStyleOptionHeader::Middle;
+        paintPadding(0, QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning);
+        paintPadding(1, QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End);
     } else if (orderIndex == 0) {
-        option.position = QStyleOptionHeader::Beginning;
+        // Paint the header for the first column; check if there is some empty space to the left which needs to be filled.
+        if (rect.left() > 0) {
+            option.position = QStyleOptionHeader::Middle;
+            paintPadding(0, QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning);
+        } else {
+            option.position = QStyleOptionHeader::Beginning;
+        }
     } else if (orderIndex == m_columns.count() - 1) {
-        // We are just painting the header for the last column. Check if there
-        // is some empty space to the right which needs to be filled.
+        // Paint the header for the last column; check if there is some empty space to the right which needs to be filled.
         if (rect.right() < size().width()) {
             option.position = QStyleOptionHeader::Middle;
-            paintBackgroundForEmptyArea = true;
+            paintPadding(m_columns.count(), QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End);
         } else {
             option.position = QStyleOptionHeader::End;
         }
@@ -438,28 +474,10 @@ void KItemListHeaderWidget::paintRole(QPainter* painter,
         option.position = QStyleOptionHeader::Middle;
     }
 
-    option.orientation = Qt::Horizontal;
-    option.selectedPosition = QStyleOptionHeader::NotAdjacent;
-    option.text = m_model->roleDescription(role);
-
     style()->drawControl(QStyle::CE_Header, &option, painter, widget);
-
-    if (paintBackgroundForEmptyArea) {
-        option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
-        option.section = m_columns.count();
-        option.sortIndicator = QStyleOptionHeader::None;
-
-        qreal backgroundRectX = rect.x() + rect.width();
-        QRectF backgroundRect(backgroundRectX, 0.0, size().width() - backgroundRectX, rect.height());
-        option.rect = backgroundRect.toRect();
-        option.position = QStyleOptionHeader::End;
-        option.text = QString();
-
-        style()->drawControl(QStyle::CE_Header, &option, painter, widget);
-    }
 }
 
-void KItemListHeaderWidget::updatePressedRoleIndex(const QPointFpos)
+void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF &pos)
 {
     const int pressedIndex = roleIndexAt(pos);
     if (m_pressedRoleIndex != pressedIndex) {
@@ -468,21 +486,28 @@ void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos)
     }
 }
 
-void KItemListHeaderWidget::updateHoveredRoleIndex(const QPointF& pos)
+void KItemListHeaderWidget::updateHoveredIndex(const QPointF &pos)
 {
     const int hoverIndex = roleIndexAt(pos);
-    if (m_hoveredRoleIndex != hoverIndex) {
-        m_hoveredRoleIndex = hoverIndex;
+
+    if (m_hoveredIndex != hoverIndex) {
+        if (m_hoveredIndex != -1) {
+            Q_EMIT columnUnHovered(m_hoveredIndex);
+        }
+        m_hoveredIndex = hoverIndex;
+        if (m_hoveredIndex != -1) {
+            Q_EMIT columnHovered(m_hoveredIndex);
+        }
         update();
     }
 }
 
-int KItemListHeaderWidget::roleIndexAt(const QPointFpos) const
+int KItemListHeaderWidget::roleIndexAt(const QPointF &pos) const
 {
     int index = -1;
 
-    qreal x = -m_offset;
-    foreach (const QByteArray& role, m_columns) {
+    qreal x = -m_offset + m_sidePadding;
+    for (const QByteArray &role : std::as_const(m_columns)) {
         ++index;
         x += m_columnWidths.value(role);
         if (pos.x() <= x) {
@@ -493,9 +518,9 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const
     return index;
 }
 
-bool KItemListHeaderWidget::isAboveRoleGrip(const QPointFpos, int roleIndex) const
+bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF &pos, int roleIndex) const
 {
-    qreal x = -m_offset;
+    qreal x = -m_offset + m_sidePadding;
     for (int i = 0; i <= roleIndex; ++i) {
         const QByteArray role = m_columns[i];
         x += m_columnWidths.value(role);
@@ -505,6 +530,26 @@ bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) c
     return pos.x() >= (x - grip) && pos.x() <= x;
 }
 
+bool KItemListHeaderWidget::isAbovePaddingGrip(const QPointF &pos, PaddingGrip paddingGrip) const
+{
+    const qreal lx = -m_offset + m_sidePadding;
+    const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
+
+    switch (paddingGrip) {
+    case Leading:
+        return pos.x() >= (lx - grip) && pos.x() <= lx;
+    case Trailing: {
+        qreal rx = lx;
+        for (const QByteArray &role : std::as_const(m_columns)) {
+            rx += m_columnWidths.value(role);
+        }
+        return pos.x() >= (rx - grip) && pos.x() <= rx;
+    }
+    default:
+        return false;
+    }
+}
+
 QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const
 {
     const QByteArray role = m_columns[roleIndex];
@@ -536,18 +581,14 @@ int KItemListHeaderWidget::targetOfMovingRole() const
     const int movingRight = movingLeft + movingWidth - 1;
 
     int targetIndex = 0;
-    qreal targetLeft = -m_offset;
+    qreal targetLeft = -m_offset + m_sidePadding;
     while (targetIndex < m_columns.count()) {
         const QByteArray role = m_columns[targetIndex];
         const qreal targetWidth = m_columnWidths.value(role);
         const qreal targetRight = targetLeft + targetWidth - 1;
 
-        const bool isInTarget = (targetWidth >= movingWidth &&
-                                 movingLeft  >= targetLeft  &&
-                                 movingRight <= targetRight) ||
-                                (targetWidth <  movingWidth &&
-                                 movingLeft  <= targetLeft  &&
-                                 movingRight >= targetRight);
+        const bool isInTarget = (targetWidth >= movingWidth && movingLeft >= targetLeft && movingRight <= targetRight)
+            || (targetWidth < movingWidth && movingLeft <= targetLeft && movingRight >= targetRight);
 
         if (isInTarget) {
             return targetIndex;
@@ -560,10 +601,10 @@ int KItemListHeaderWidget::targetOfMovingRole() const
     return m_movingRole.index;
 }
 
-qreal KItemListHeaderWidget::roleXPosition(const QByteArrayrole) const
+qreal KItemListHeaderWidget::roleXPosition(const QByteArray &role) const
 {
-    qreal x = -m_offset;
-    foreach (const QByteArray& visibleRole, m_columns) {
+    qreal x = -m_offset + m_sidePadding;
+    for (const QByteArray &visibleRole : std::as_const(m_columns)) {
         if (visibleRole == role) {
             return x;
         }
@@ -574,3 +615,4 @@ qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const
     return -1;
 }
 
+#include "moc_kitemlistheaderwidget.cpp"