#include "kitemlistheader_p.h"
+#include <KAction>
+#include <KMenu>
#include "kitemmodelbase.h"
#include <QApplication>
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;
return m_visibleRoles;
}
-void KItemListHeader::setVisibleRolesWidths(const QHash<QByteArray, qreal> rolesWidths)
+void KItemListHeader::setVisibleRolesWidths(const QHash<QByteArray, qreal>& rolesWidths)
{
m_visibleRolesWidths = rolesWidths;
return m_visibleRolesWidths;
}
+qreal KItemListHeader::minimumRoleWidth() const
+{
+ QFontMetricsF fontMetrics(font());
+ return fontMetrics.height() * 4;
+}
+
void KItemListHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option);
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);
+ paintRole(painter, role, rect, orderIndex, widget);
x += roleWidth;
++orderIndex;
}
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)
{
- event->accept();
- updatePressedRoleIndex(event->pos());
- m_pressedMousePos = event->pos();
- m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
- ResizeRoleOperation : NoRoleOperation;
+ 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)
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);
if (m_pressedRoleIndex == sortRoleIndex) {
// Toggle the sort order
- const Qt::SortOrder toggled = (m_model->sortOrder() == Qt::AscendingOrder) ?
+ const Qt::SortOrder previous = m_model->sortOrder();
+ const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ?
Qt::DescendingOrder : Qt::AscendingOrder;
- m_model->setSortOrder(toggled);
+ m_model->setSortOrder(current);
+ emit sortOrderChanged(current, previous);
} else {
// Change the sort role
- const QByteArray sortRole = m_visibleRoles.at(m_pressedRoleIndex);
- m_model->setSortRole(sortRole);
+ 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();
}
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;
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;
}
}
void KItemListHeader::paintRole(QPainter* painter,
const QByteArray& role,
const QRectF& rect,
- int orderIndex)
+ 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).
option.selectedPosition = QStyleOptionHeader::NotAdjacent;
option.text = m_model->roleDescription(role);
- style()->drawControl(QStyle::CE_Header, &option, painter);
+ style()->drawControl(QStyle::CE_Header, &option, painter, widget);
}
void KItemListHeader::updatePressedRoleIndex(const QPointF& pos)
{
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);
}
return pos.x() >= (x - grip) && pos.x() <= x;
}
-qreal KItemListHeader::minimumRoleWidth() const
+QPixmap KItemListHeader::createRolePixmap(int roleIndex) const
{
- QFontMetricsF fontMetrics(font());
- return fontMetrics.averageCharWidth() * 5;
+ 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"