From 08a485349f2bd73682ac806b97d3630c3a7dd3fd Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Wed, 7 Mar 2012 22:12:07 +0100 Subject: Allow custom sorting of details-view columns Fix regression that Dolphin 2.0 did not allow to adjust the sorting of the details-view columns. BUG: 164696 FIXED-IN: 4.8.2 --- src/kitemviews/kitemlistheader.cpp | 166 ++++++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 10 deletions(-) (limited to 'src/kitemviews/kitemlistheader.cpp') diff --git a/src/kitemviews/kitemlistheader.cpp b/src/kitemviews/kitemlistheader.cpp index 7b5549c73..bd7dfb831 100644 --- a/src/kitemviews/kitemlistheader.cpp +++ b/src/kitemviews/kitemlistheader.cpp @@ -38,8 +38,13 @@ KItemListHeader::KItemListHeader(QGraphicsWidget* parent) : m_hoveredRoleIndex(-1), m_pressedRoleIndex(-1), m_roleOperation(NoRoleOperation), - m_pressedMousePos() + m_pressedMousePos(), + m_movingRole() { + m_movingRole.x = 0; + m_movingRole.xDec = 0; + m_movingRole.index = -1; + setAcceptHoverEvents(true); QStyleOptionHeader option; @@ -147,6 +152,11 @@ void KItemListHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* o 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); + } } void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent* event) @@ -170,7 +180,8 @@ void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) return; } - if (m_roleOperation == NoRoleOperation) { + 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); @@ -184,23 +195,66 @@ void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) } else { // Change the sort role const QByteArray previous = m_model->sortRole(); - const QByteArray current = m_visibleRoles.at(m_pressedRoleIndex); + 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(); } void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { QGraphicsWidget::mouseMoveEvent(event); - if (m_roleOperation == ResizeRoleOperation) { - const QByteArray pressedRole = m_visibleRoles.at(m_pressedRoleIndex); + 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; @@ -211,9 +265,32 @@ void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent* event) update(); emit visibleRoleWidthChanged(pressedRole, currentWidth, previousWidth); - } else if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { - kDebug() << "Moving of role not supported yet"; - m_roleOperation = MoveRoleOperation; + 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); + } + } + break; + } + + default: + break; } } @@ -262,7 +339,7 @@ void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder void KItemListHeader::paintRole(QPainter* painter, const QByteArray& role, const QRectF& rect, - int orderIndex) + int orderIndex) const { // The following code is based on the code from QHeaderView::paintSection(). // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). @@ -342,7 +419,7 @@ bool KItemListHeader::isAboveRoleGrip(const QPointF& pos, int roleIndex) const { qreal x = 0; for (int i = 0; i <= roleIndex; ++i) { - const QByteArray role = m_visibleRoles.at(i); + const QByteArray role = m_visibleRoles[i]; x += m_visibleRolesWidths.value(role); } @@ -350,4 +427,73 @@ bool KItemListHeader::isAboveRoleGrip(const QPointF& pos, int roleIndex) const return pos.x() >= (x - grip) && pos.x() <= x; } +QPixmap KItemListHeader::createRolePixmap(int roleIndex) 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); +} + +int KItemListHeader::targetOfMovingRole() 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; +} + +qreal KItemListHeader::roleXPosition(const QByteArray& role) const +{ + qreal x = 0; + foreach (const QByteArray& visibleRole, m_visibleRoles) { + if (visibleRole == role) { + return x; + } + + x += m_visibleRolesWidths.value(visibleRole); + } + + return -1; +} + #include "kitemlistheader_p.moc" -- cgit v1.3