1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
20 #include "kitemlistheader_p.h"
22 #include "kitemmodelbase.h"
24 #include <QApplication>
25 #include <QGraphicsSceneHoverEvent>
27 #include <QStyleOptionHeader>
31 KItemListHeader::KItemListHeader(QGraphicsWidget
* parent
) :
32 QGraphicsWidget(parent
),
35 m_visibleRolesWidths(),
36 m_hoveredRoleIndex(-1),
37 m_pressedRoleIndex(-1),
38 m_roleOperation(NoRoleOperation
),
41 setAcceptHoverEvents(true);
43 QStyleOptionHeader option
;
44 const QSize headerSize
= style()->sizeFromContents(QStyle::CT_HeaderSection
, &option
, QSize());
45 resize(0, headerSize
.height());
48 KItemListHeader::~KItemListHeader()
52 void KItemListHeader::setModel(KItemModelBase
* model
)
54 if (m_model
== model
) {
59 disconnect(m_model
, SIGNAL(sortRoleChanged(QByteArray
,QByteArray
)),
60 this, SLOT(slotSortRoleChanged(QByteArray
,QByteArray
)));
61 disconnect(m_model
, SIGNAL(sortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)),
62 this, SLOT(slotSortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)));
68 connect(m_model
, SIGNAL(sortRoleChanged(QByteArray
,QByteArray
)),
69 this, SLOT(slotSortRoleChanged(QByteArray
,QByteArray
)));
70 connect(m_model
, SIGNAL(sortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)),
71 this, SLOT(slotSortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)));
75 KItemModelBase
* KItemListHeader::model() const
80 void KItemListHeader::setVisibleRoles(const QList
<QByteArray
>& roles
)
82 m_visibleRoles
= roles
;
86 QList
<QByteArray
> KItemListHeader::visibleRoles() const
88 return m_visibleRoles
;
91 void KItemListHeader::setVisibleRolesWidths(const QHash
<QByteArray
, qreal
> rolesWidths
)
93 m_visibleRolesWidths
= rolesWidths
;
95 // Assure that no width is smaller than the minimum allowed width
96 const qreal minWidth
= minimumRoleWidth();
97 QMutableHashIterator
<QByteArray
, qreal
> it(m_visibleRolesWidths
);
98 while (it
.hasNext()) {
100 if (it
.value() < minWidth
) {
101 m_visibleRolesWidths
.insert(it
.key(), minWidth
);
108 QHash
<QByteArray
, qreal
> KItemListHeader::visibleRolesWidths() const
110 return m_visibleRolesWidths
;
113 void KItemListHeader::paint(QPainter
* painter
, const QStyleOptionGraphicsItem
* option
, QWidget
* widget
)
123 painter
->setFont(font());
124 painter
->setPen(palette().text().color());
128 foreach (const QByteArray
& role
, m_visibleRoles
) {
129 const qreal roleWidth
= m_visibleRolesWidths
.value(role
);
130 const QRectF
rect(x
, 0, roleWidth
, size().height());
131 paintRole(painter
, role
, rect
, orderIndex
);
136 // Draw background without roles
139 opt
.rect
= QRect(x
, 0, size().width() - x
, size().height());
140 opt
.state
|= QStyle::State_Horizontal
;
141 style()->drawControl(QStyle::CE_HeaderEmptyArea
, &opt
, painter
);
144 void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent
* event
)
147 updatePressedRoleIndex(event
->pos());
148 m_pressedMousePos
= event
->pos();
149 m_roleOperation
= isAboveRoleGrip(m_pressedMousePos
, m_pressedRoleIndex
) ?
150 ResizeRoleOperation
: NoRoleOperation
;
153 void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent
* event
)
155 QGraphicsWidget::mouseReleaseEvent(event
);
157 if (m_pressedRoleIndex
== -1) {
161 if (m_roleOperation
== NoRoleOperation
) {
162 // Only a click has been done and no moving or resizing has been started
163 const QByteArray sortRole
= m_model
->sortRole();
164 const int sortRoleIndex
= m_visibleRoles
.indexOf(sortRole
);
165 if (m_pressedRoleIndex
== sortRoleIndex
) {
166 // Toggle the sort order
167 const Qt::SortOrder toggled
= (m_model
->sortOrder() == Qt::AscendingOrder
) ?
168 Qt::DescendingOrder
: Qt::AscendingOrder
;
169 m_model
->setSortOrder(toggled
);
171 // Change the sort role
172 const QByteArray sortRole
= m_visibleRoles
.at(m_pressedRoleIndex
);
173 m_model
->setSortRole(sortRole
);
177 m_pressedRoleIndex
= -1;
178 m_roleOperation
= NoRoleOperation
;
182 void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent
* event
)
184 QGraphicsWidget::mouseMoveEvent(event
);
186 if (m_roleOperation
== ResizeRoleOperation
) {
187 const QByteArray pressedRole
= m_visibleRoles
.at(m_pressedRoleIndex
);
189 qreal previousWidth
= m_visibleRolesWidths
.value(pressedRole
);
190 qreal currentWidth
= previousWidth
;
191 currentWidth
+= event
->pos().x() - event
->lastPos().x();
192 currentWidth
= qMax(minimumRoleWidth(), currentWidth
);
194 m_visibleRolesWidths
.insert(pressedRole
, currentWidth
);
197 emit
visibleRoleWidthChanged(pressedRole
, currentWidth
, previousWidth
);
198 } else if ((event
->pos() - m_pressedMousePos
).manhattanLength() >= QApplication::startDragDistance()) {
199 kDebug() << "Moving of role not supported yet";
200 m_roleOperation
= MoveRoleOperation
;
204 void KItemListHeader::hoverEnterEvent(QGraphicsSceneHoverEvent
* event
)
206 QGraphicsWidget::hoverEnterEvent(event
);
207 updateHoveredRoleIndex(event
->pos());
210 void KItemListHeader::hoverLeaveEvent(QGraphicsSceneHoverEvent
* event
)
212 QGraphicsWidget::hoverLeaveEvent(event
);
213 if (m_hoveredRoleIndex
!= -1) {
214 m_hoveredRoleIndex
= -1;
219 void KItemListHeader::hoverMoveEvent(QGraphicsSceneHoverEvent
* event
)
221 QGraphicsWidget::hoverMoveEvent(event
);
223 const QPointF
& pos
= event
->pos();
224 updateHoveredRoleIndex(pos
);
225 if (m_hoveredRoleIndex
>= 0 && isAboveRoleGrip(pos
, m_hoveredRoleIndex
)) {
226 setCursor(Qt::SplitHCursor
);
232 void KItemListHeader::slotSortRoleChanged(const QByteArray
& current
, const QByteArray
& previous
)
239 void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current
, Qt::SortOrder previous
)
246 void KItemListHeader::paintRole(QPainter
* painter
,
247 const QByteArray
& role
,
251 // The following code is based on the code from QHeaderView::paintSection().
252 // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
253 QStyleOptionHeader option
;
254 option
.section
= orderIndex
;
255 option
.state
= QStyle::State_None
| QStyle::State_Raised
| QStyle::State_Horizontal
;
257 option
.state
|= QStyle::State_Enabled
;
259 if (window() && window()->isActiveWindow()) {
260 option
.state
|= QStyle::State_Active
;
262 if (m_hoveredRoleIndex
== orderIndex
) {
263 option
.state
|= QStyle::State_MouseOver
;
265 if (m_pressedRoleIndex
== orderIndex
) {
266 option
.state
|= QStyle::State_Sunken
;
268 if (m_model
->sortRole() == role
) {
269 option
.sortIndicator
= (m_model
->sortOrder() == Qt::AscendingOrder
) ?
270 QStyleOptionHeader::SortDown
: QStyleOptionHeader::SortUp
;
272 option
.rect
= rect
.toRect();
274 if (m_visibleRoles
.count() == 1) {
275 option
.position
= QStyleOptionHeader::OnlyOneSection
;
276 } else if (orderIndex
== 0) {
277 option
.position
= QStyleOptionHeader::Beginning
;
278 } else if (orderIndex
== m_visibleRoles
.count() - 1) {
279 option
.position
= QStyleOptionHeader::End
;
281 option
.position
= QStyleOptionHeader::Middle
;
284 option
.orientation
= Qt::Horizontal
;
285 option
.selectedPosition
= QStyleOptionHeader::NotAdjacent
;
286 option
.text
= m_model
->roleDescription(role
);
288 style()->drawControl(QStyle::CE_Header
, &option
, painter
);
291 void KItemListHeader::updatePressedRoleIndex(const QPointF
& pos
)
293 const int pressedIndex
= roleIndexAt(pos
);
294 if (m_pressedRoleIndex
!= pressedIndex
) {
295 m_pressedRoleIndex
= pressedIndex
;
300 void KItemListHeader::updateHoveredRoleIndex(const QPointF
& pos
)
302 const int hoverIndex
= roleIndexAt(pos
);
303 if (m_hoveredRoleIndex
!= hoverIndex
) {
304 m_hoveredRoleIndex
= hoverIndex
;
309 int KItemListHeader::roleIndexAt(const QPointF
& pos
) const
314 foreach (const QByteArray
& role
, m_visibleRoles
) {
316 x
+= m_visibleRolesWidths
.value(role
);
325 bool KItemListHeader::isAboveRoleGrip(const QPointF
& pos
, int roleIndex
) const
328 for (int i
= 0; i
<= roleIndex
; ++i
) {
329 const QByteArray role
= m_visibleRoles
.at(i
);
330 x
+= m_visibleRolesWidths
.value(role
);
333 const int grip
= style()->pixelMetric(QStyle::PM_HeaderGripMargin
);
334 return pos
.x() >= (x
- grip
) && pos
.x() <= x
;
337 qreal
KItemListHeader::minimumRoleWidth() const
339 QFontMetricsF
fontMetrics(font());
340 return fontMetrics
.averageCharWidth() * 8;
343 #include "kitemlistheader_p.moc"