]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistheader.cpp
GIT_SILENT Sync po/docbooks with svn
[dolphin.git] / src / kitemviews / kitemlistheader.cpp
index dfe76bc95eb52bd7dec8b376a9d67fd96d3359a6..97d0cdfbf3f5e908af417a4dd7a632dfa7388872 100644 (file)
-/***************************************************************************
- *   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: 2012 Peter Penz <peter.penz19@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
 
-#include "kitemlistheader_p.h"
-
-#include <KAction>
-#include <KMenu>
-#include "kitemmodelbase.h"
-
-#include <QApplication>
-#include <QGraphicsSceneHoverEvent>
-#include <QPainter>
-#include <QStyleOptionHeader>
-
-#include <KDebug>
-
-KItemListHeader::KItemListHeader(QGraphicsWidget* parent) :
-    QGraphicsWidget(parent),
-    m_model(0),
-    m_visibleRoles(),
-    m_visibleRolesWidths(),
-    m_hoveredRoleIndex(-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);
-
-    QStyleOptionHeader option;
-    const QSize headerSize = style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize());
-    resize(0, headerSize.height());
-}
+#include "kitemlistheader.h"
+#include "kitemlistview.h"
+#include "private/kitemlistheaderwidget.h"
 
 KItemListHeader::~KItemListHeader()
 {
 }
 
-void KItemListHeader::setModel(KItemModelBase* model)
+void KItemListHeader::setAutomaticColumnResizing(bool automatic)
 {
-    if (m_model == model) {
-        return;
-    }
-
-    if (m_model) {
-        disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
-                   this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
-        disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
-                   this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
-    }
-
-    m_model = model;
-
-    if (m_model) {
-        connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
-                this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
-        connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
-                this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
-    }
-}
-
-KItemModelBase* KItemListHeader::model() const
-{
-    return m_model;
-}
-
-void KItemListHeader::setVisibleRoles(const QList<QByteArray>& roles)
-{
-    m_visibleRoles = roles;
-    update();
-}
-
-QList<QByteArray> KItemListHeader::visibleRoles() const
-{
-    return m_visibleRoles;
-}
-
-void KItemListHeader::setVisibleRolesWidths(const QHash<QByteArray, qreal> rolesWidths)
-{
-    m_visibleRolesWidths = rolesWidths;
-
-    // Assure that no width is smaller than the minimum allowed width
-    const qreal minWidth = minimumRoleWidth();
-    QMutableHashIterator<QByteArray, qreal> it(m_visibleRolesWidths);
-    while (it.hasNext()) {
-        it.next();
-        if (it.value() < minWidth) {
-            m_visibleRolesWidths.insert(it.key(), minWidth);
+    if (m_headerWidget->automaticColumnResizing() != automatic) {
+        m_headerWidget->setAutomaticColumnResizing(automatic);
+        if (automatic) {
+            m_view->applyAutomaticColumnWidths();
+            m_view->doLayout(KItemListView::NoAnimation);
         }
     }
-
-    update();
-}
-
-QHash<QByteArray, qreal> KItemListHeader::visibleRolesWidths() const
-{
-    return m_visibleRolesWidths;
 }
 
-qreal KItemListHeader::minimumRoleWidth() const
+bool KItemListHeader::automaticColumnResizing() const
 {
-    QFontMetricsF fontMetrics(font());
-    return fontMetrics.height() * 4;
+    return m_headerWidget->automaticColumnResizing();
 }
 
-void KItemListHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+void KItemListHeader::setColumnWidth(const QByteArray &role, qreal width)
 {
-    Q_UNUSED(option);
-    Q_UNUSED(widget);
-
-    if (!m_model) {
-        return;
-    }
-
-    // Draw roles
-    painter->setFont(font());
-    painter->setPen(palette().text().color());
-
-    qreal x = 0;
-    int orderIndex = 0;
-    foreach (const QByteArray& role, m_visibleRoles) {
-        const qreal roleWidth = m_visibleRolesWidths.value(role);
-        const QRectF rect(x, 0, roleWidth, size().height());
-        paintRole(painter, role, rect, orderIndex, widget);
-        x += roleWidth;
-        ++orderIndex;
-    }
-
-    // Draw background without roles
-    QStyleOption opt;
-    opt.init(widget);
-    opt.rect = QRect(x, 0, size().width() - x, size().height());
-    opt.state |= QStyle::State_Horizontal;
-    style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter);
-
-    if (!m_movingRole.pixmap.isNull()) {
-        Q_ASSERT(m_roleOperation == MoveRoleOperation);
-        painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap);
+    if (!m_headerWidget->automaticColumnResizing()) {
+        m_headerWidget->setColumnWidth(role, width);
+        m_view->applyColumnWidthsFromHeader();
+        m_view->doLayout(KItemListView::NoAnimation);
     }
 }
 
-void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent* event)
+qreal KItemListHeader::columnWidth(const QByteArray &role) const
 {
-    if (event->button() & Qt::LeftButton) {
-        updatePressedRoleIndex(event->pos());
-        m_pressedMousePos = event->pos();
-        m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
-                          ResizeRoleOperation : NoRoleOperation;
-        event->accept();
-    } else {
-        event->ignore();
-    }
-}
-
-void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
-{
-    QGraphicsWidget::mouseReleaseEvent(event);
-
-    if (m_pressedRoleIndex == -1) {
-        return;
-    }
-
-    switch (m_roleOperation) {
-    case NoRoleOperation: {
-        // Only a click has been done and no moving or resizing has been started
-        const QByteArray sortRole = m_model->sortRole();
-        const int sortRoleIndex = m_visibleRoles.indexOf(sortRole);
-        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;
-            m_model->setSortOrder(current);
-            emit sortOrderChanged(current, previous);
-        } else {
-            // Change the sort role
-            const QByteArray previous = m_model->sortRole();
-            const QByteArray current = m_visibleRoles[m_pressedRoleIndex];
-            m_model->setSortRole(current);
-            emit sortRoleChanged(current, previous);
-        }
-        break;
-    }
-
-    case MoveRoleOperation:
-        m_movingRole.pixmap = QPixmap();
-        m_movingRole.x = 0;
-        m_movingRole.xDec = 0;
-        m_movingRole.index = -1;
-        break;
-
-    default:
-        break;
-    }
-
-    m_pressedRoleIndex = -1;
-    m_roleOperation = NoRoleOperation;
-    update();
-
-    QApplication::restoreOverrideCursor();
+    return m_headerWidget->columnWidth(role);
 }
 
-void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
+void KItemListHeader::setColumnWidths(const QHash<QByteArray, qreal> &columnWidths)
 {
-    QGraphicsWidget::mouseMoveEvent(event);
-
-    switch (m_roleOperation) {
-    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.
-            m_roleOperation = MoveRoleOperation;
-            const int roleIndex = roleIndexAt(m_pressedMousePos);
-            m_movingRole.index = roleIndex;
-            if (roleIndex == 0) {
-                // TODO: It should be configurable whether moving the first role is allowed.
-                // In the context of Dolphin this is not required, however this should be
-                // changed if KItemViews are used in a more generic way.
-                QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor));
-            } else {
-                m_movingRole.pixmap = createRolePixmap(roleIndex);
-
-                qreal roleX = 0;
-                for (int i = 0; i < roleIndex; ++i) {
-                    const QByteArray role = m_visibleRoles[i];
-                    roleX += m_visibleRolesWidths.value(role);
-                }
-
-                m_movingRole.xDec = event->pos().x() - roleX;
-                m_movingRole.x = roleX;
-                update();
-            }
-        }
-        break;
-
-    case ResizeRoleOperation: {
-        const QByteArray pressedRole = m_visibleRoles[m_pressedRoleIndex];
-
-        qreal previousWidth = m_visibleRolesWidths.value(pressedRole);
-        qreal currentWidth = previousWidth;
-        currentWidth += event->pos().x() - event->lastPos().x();
-        currentWidth = qMax(minimumRoleWidth(), currentWidth);
-
-        m_visibleRolesWidths.insert(pressedRole, currentWidth);
-        update();
-
-        emit visibleRoleWidthChanged(pressedRole, currentWidth, previousWidth);
-        break;
-    }
-
-    case MoveRoleOperation: {
-        // TODO: It should be configurable whether moving the first role is allowed.
-        // In the context of Dolphin this is not required, however this should be
-        // changed if KItemViews are used in a more generic way.
-        if (m_movingRole.index > 0) {
-            m_movingRole.x = event->pos().x() - m_movingRole.xDec;
-            update();
-
-            const int targetIndex = targetOfMovingRole();
-            if (targetIndex > 0 && targetIndex != m_movingRole.index) {
-                const QByteArray role = m_visibleRoles[m_movingRole.index];
-                const int previousIndex = m_movingRole.index;
-                m_movingRole.index = targetIndex;
-                emit visibleRoleMoved(role, targetIndex, previousIndex);
-
-                m_movingRole.xDec = event->pos().x() - roleXPosition(role);
-            }
+    if (!m_headerWidget->automaticColumnResizing()) {
+        const auto visibleRoles = m_view->visibleRoles();
+        for (const QByteArray &role : visibleRoles) {
+            const qreal width = columnWidths.value(role);
+            m_headerWidget->setColumnWidth(role, width);
         }
-        break;
-    }
-
-    default:
-        break;
-    }
-}
-
-void KItemListHeader::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverEnterEvent(event);
-    updateHoveredRoleIndex(event->pos());
-}
-
-void KItemListHeader::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverLeaveEvent(event);
-    if (m_hoveredRoleIndex != -1) {
-        m_hoveredRoleIndex = -1;
-        update();
-    }
-}
-
-void KItemListHeader::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverMoveEvent(event);
 
-    const QPointF& pos = event->pos();
-    updateHoveredRoleIndex(pos);
-    if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
-        setCursor(Qt::SplitHCursor);
-    } else {
-        unsetCursor();
+        m_view->applyColumnWidthsFromHeader();
+        m_view->doLayout(KItemListView::NoAnimation);
     }
 }
 
-void KItemListHeader::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+qreal KItemListHeader::preferredColumnWidth(const QByteArray &role) const
 {
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
-    update();
-}
-
-void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
-{
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
-    update();
-}
-
-void KItemListHeader::paintRole(QPainter* painter,
-                                const QByteArray& role,
-                                const QRectF& rect,
-                                int orderIndex,
-                                QWidget* widget) const
-{
-    // The following code is based on the code from QHeaderView::paintSection().
-    // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    QStyleOptionHeader option;
-    option.section = orderIndex;
-    option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
-    if (isEnabled()) {
-        option.state |= QStyle::State_Enabled;
-    }
-    if (window() && window()->isActiveWindow()) {
-        option.state |= QStyle::State_Active;
-    }
-    if (m_hoveredRoleIndex == 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.rect = rect.toRect();
-
-    if (m_visibleRoles.count() == 1) {
-        option.position = QStyleOptionHeader::OnlyOneSection;
-    } else if (orderIndex == 0) {
-        option.position = QStyleOptionHeader::Beginning;
-    } else if (orderIndex == m_visibleRoles.count() - 1) {
-        option.position = QStyleOptionHeader::End;
-    } else {
-        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);
+    return m_headerWidget->preferredColumnWidth(role);
 }
 
-void KItemListHeader::updatePressedRoleIndex(const QPointF& pos)
+void KItemListHeader::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth)
 {
-    const int pressedIndex = roleIndexAt(pos);
-    if (m_pressedRoleIndex != pressedIndex) {
-        m_pressedRoleIndex = pressedIndex;
-        update();
-    }
-}
-
-void KItemListHeader::updateHoveredRoleIndex(const QPointF& pos)
-{
-    const int hoverIndex = roleIndexAt(pos);
-    if (m_hoveredRoleIndex != hoverIndex) {
-        m_hoveredRoleIndex = hoverIndex;
-        update();
-    }
-}
-
-int KItemListHeader::roleIndexAt(const QPointF& pos) const
-{
-    int index = -1;
-
-    qreal x = 0;
-    foreach (const QByteArray& role, m_visibleRoles) {
-        ++index;
-        x += m_visibleRolesWidths.value(role);
-        if (pos.x() <= x) {
-            break;
+    if (m_headerWidget->leftPadding() != leftPaddingWidth || m_headerWidget->rightPadding() != rightPaddingWidth) {
+        m_headerWidget->setSidePadding(leftPaddingWidth, rightPaddingWidth);
+        if (m_headerWidget->automaticColumnResizing()) {
+            m_view->applyAutomaticColumnWidths();
         }
+        m_view->doLayout(KItemListView::NoAnimation);
     }
-
-    return index;
-}
-
-bool KItemListHeader::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
-{
-    qreal x = 0;
-    for (int i = 0; i <= roleIndex; ++i) {
-        const QByteArray role = m_visibleRoles[i];
-        x += m_visibleRolesWidths.value(role);
-    }
-
-    const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
-    return pos.x() >= (x - grip) && pos.x() <= x;
 }
 
-QPixmap KItemListHeader::createRolePixmap(int roleIndex) const
+qreal KItemListHeader::leftPadding() const
 {
-    const QByteArray role = m_visibleRoles[roleIndex];
-    const qreal roleWidth = m_visibleRolesWidths.value(role);
-    const QRect rect(0, 0, roleWidth, size().height());
-
-    QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied);
-
-    QPainter painter(&image);
-    paintRole(&painter, role, rect, roleIndex);
-
-    // Apply a highlighting-color
-    const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
-    QColor highlightColor = palette().color(group, QPalette::Highlight);
-    highlightColor.setAlpha(64);
-    painter.fillRect(rect, highlightColor);
-
-    // Make the image transparent
-    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
-    painter.fillRect(0, 0, image.width(), image.height(), QColor(0, 0, 0, 192));
-
-    return QPixmap::fromImage(image);
+    return m_headerWidget->leftPadding();
 }
 
-int KItemListHeader::targetOfMovingRole() const
+qreal KItemListHeader::rightPadding() const
 {
-    const int movingWidth = m_movingRole.pixmap.width();
-    const int movingLeft = m_movingRole.x;
-    const int movingRight = movingLeft + movingWidth - 1;
-
-    int targetIndex = 0;
-    qreal targetLeft = 0;
-    while (targetIndex < m_visibleRoles.count()) {
-        const QByteArray role = m_visibleRoles[targetIndex];
-        const qreal targetWidth = m_visibleRolesWidths.value(role);
-        const qreal targetRight = targetLeft + targetWidth - 1;
-
-        const bool isInTarget = (targetWidth >= movingWidth &&
-                                 movingLeft  >= targetLeft  &&
-                                 movingRight <= targetRight) ||
-                                (targetWidth <  movingWidth &&
-                                 movingLeft  <= targetLeft  &&
-                                 movingRight >= targetRight);
-
-        if (isInTarget) {
-            return targetIndex;
-        }
-
-        targetLeft += targetWidth;
-        ++targetIndex;
-    }
-
-    return m_movingRole.index;
+    return m_headerWidget->rightPadding();
 }
 
-qreal KItemListHeader::roleXPosition(const QByteArray& role) const
+KItemListHeader::KItemListHeader(KItemListView *listView)
+    : QObject(listView)
+    , m_view(listView)
 {
-    qreal x = 0;
-    foreach (const QByteArray& visibleRole, m_visibleRoles) {
-        if (visibleRole == role) {
-            return x;
-        }
-
-        x += m_visibleRolesWidths.value(visibleRole);
-    }
+    m_headerWidget = m_view->m_headerWidget;
+    Q_ASSERT(m_headerWidget);
 
-    return -1;
+    connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged, this, &KItemListHeader::columnWidthChanged);
+    connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChangeFinished, this, &KItemListHeader::columnWidthChangeFinished);
+    connect(m_headerWidget, &KItemListHeaderWidget::sidePaddingChanged, this, &KItemListHeader::sidePaddingChanged);
 }
 
-#include "kitemlistheader_p.moc"
+#include "moc_kitemlistheader.cpp"