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"
24 #include "kitemmodelbase.h"
26 #include <QApplication>
27 #include <QGraphicsSceneHoverEvent>
29 #include <QStyleOptionHeader>
33 KItemListHeader::KItemListHeader(QGraphicsWidget
* parent
) :
34 QGraphicsWidget(parent
),
37 m_visibleRolesWidths(),
38 m_hoveredRoleIndex(-1),
39 m_pressedRoleIndex(-1),
40 m_roleOperation(NoRoleOperation
),
43 setAcceptHoverEvents(true);
45 QStyleOptionHeader option
;
46 const QSize headerSize
= style()->sizeFromContents(QStyle::CT_HeaderSection
, &option
, QSize());
47 resize(0, headerSize
.height());
50 KItemListHeader::~KItemListHeader()
54 void KItemListHeader::setModel(KItemModelBase
* model
)
56 if (m_model
== model
) {
61 disconnect(m_model
, SIGNAL(sortRoleChanged(QByteArray
,QByteArray
)),
62 this, SLOT(slotSortRoleChanged(QByteArray
,QByteArray
)));
63 disconnect(m_model
, SIGNAL(sortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)),
64 this, SLOT(slotSortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)));
70 connect(m_model
, SIGNAL(sortRoleChanged(QByteArray
,QByteArray
)),
71 this, SLOT(slotSortRoleChanged(QByteArray
,QByteArray
)));
72 connect(m_model
, SIGNAL(sortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)),
73 this, SLOT(slotSortOrderChanged(Qt::SortOrder
,Qt::SortOrder
)));
77 KItemModelBase
* KItemListHeader::model() const
82 void KItemListHeader::setVisibleRoles(const QList
<QByteArray
>& roles
)
84 m_visibleRoles
= roles
;
88 QList
<QByteArray
> KItemListHeader::visibleRoles() const
90 return m_visibleRoles
;
93 void KItemListHeader::setVisibleRolesWidths(const QHash
<QByteArray
, qreal
> rolesWidths
)
95 m_visibleRolesWidths
= rolesWidths
;
97 // Assure that no width is smaller than the minimum allowed width
98 const qreal minWidth
= minimumRoleWidth();
99 QMutableHashIterator
<QByteArray
, qreal
> it(m_visibleRolesWidths
);
100 while (it
.hasNext()) {
102 if (it
.value() < minWidth
) {
103 m_visibleRolesWidths
.insert(it
.key(), minWidth
);
110 QHash
<QByteArray
, qreal
> KItemListHeader::visibleRolesWidths() const
112 return m_visibleRolesWidths
;
115 void KItemListHeader::paint(QPainter
* painter
, const QStyleOptionGraphicsItem
* option
, QWidget
* widget
)
125 painter
->setFont(font());
126 painter
->setPen(palette().text().color());
130 foreach (const QByteArray
& role
, m_visibleRoles
) {
131 const qreal roleWidth
= m_visibleRolesWidths
.value(role
);
132 const QRectF
rect(x
, 0, roleWidth
, size().height());
133 paintRole(painter
, role
, rect
, orderIndex
);
138 // Draw background without roles
141 opt
.rect
= QRect(x
, 0, size().width() - x
, size().height());
142 opt
.state
|= QStyle::State_Horizontal
;
143 style()->drawControl(QStyle::CE_HeaderEmptyArea
, &opt
, painter
);
146 void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent
* event
)
148 if (event
->button() & Qt::LeftButton
) {
149 updatePressedRoleIndex(event
->pos());
150 m_pressedMousePos
= event
->pos();
151 m_roleOperation
= isAboveRoleGrip(m_pressedMousePos
, m_pressedRoleIndex
) ?
152 ResizeRoleOperation
: NoRoleOperation
;
159 void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent
* event
)
161 QGraphicsWidget::mouseReleaseEvent(event
);
163 if (m_pressedRoleIndex
== -1) {
167 if (m_roleOperation
== NoRoleOperation
) {
168 // Only a click has been done and no moving or resizing has been started
169 const QByteArray sortRole
= m_model
->sortRole();
170 const int sortRoleIndex
= m_visibleRoles
.indexOf(sortRole
);
171 if (m_pressedRoleIndex
== sortRoleIndex
) {
172 // Toggle the sort order
173 const Qt::SortOrder toggled
= (m_model
->sortOrder() == Qt::AscendingOrder
) ?
174 Qt::DescendingOrder
: Qt::AscendingOrder
;
175 m_model
->setSortOrder(toggled
);
177 // Change the sort role
178 const QByteArray sortRole
= m_visibleRoles
.at(m_pressedRoleIndex
);
179 m_model
->setSortRole(sortRole
);
183 m_pressedRoleIndex
= -1;
184 m_roleOperation
= NoRoleOperation
;
188 void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent
* event
)
190 QGraphicsWidget::mouseMoveEvent(event
);
192 if (m_roleOperation
== ResizeRoleOperation
) {
193 const QByteArray pressedRole
= m_visibleRoles
.at(m_pressedRoleIndex
);
195 qreal previousWidth
= m_visibleRolesWidths
.value(pressedRole
);
196 qreal currentWidth
= previousWidth
;
197 currentWidth
+= event
->pos().x() - event
->lastPos().x();
198 currentWidth
= qMax(minimumRoleWidth(), currentWidth
);
200 m_visibleRolesWidths
.insert(pressedRole
, currentWidth
);
203 emit
visibleRoleWidthChanged(pressedRole
, currentWidth
, previousWidth
);
204 } else if ((event
->pos() - m_pressedMousePos
).manhattanLength() >= QApplication::startDragDistance()) {
205 kDebug() << "Moving of role not supported yet";
206 m_roleOperation
= MoveRoleOperation
;
210 void KItemListHeader::hoverEnterEvent(QGraphicsSceneHoverEvent
* event
)
212 QGraphicsWidget::hoverEnterEvent(event
);
213 updateHoveredRoleIndex(event
->pos());
216 void KItemListHeader::hoverLeaveEvent(QGraphicsSceneHoverEvent
* event
)
218 QGraphicsWidget::hoverLeaveEvent(event
);
219 if (m_hoveredRoleIndex
!= -1) {
220 m_hoveredRoleIndex
= -1;
225 void KItemListHeader::hoverMoveEvent(QGraphicsSceneHoverEvent
* event
)
227 QGraphicsWidget::hoverMoveEvent(event
);
229 const QPointF
& pos
= event
->pos();
230 updateHoveredRoleIndex(pos
);
231 if (m_hoveredRoleIndex
>= 0 && isAboveRoleGrip(pos
, m_hoveredRoleIndex
)) {
232 setCursor(Qt::SplitHCursor
);
238 void KItemListHeader::slotSortRoleChanged(const QByteArray
& current
, const QByteArray
& previous
)
245 void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current
, Qt::SortOrder previous
)
252 void KItemListHeader::paintRole(QPainter
* painter
,
253 const QByteArray
& role
,
257 // The following code is based on the code from QHeaderView::paintSection().
258 // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
259 QStyleOptionHeader option
;
260 option
.section
= orderIndex
;
261 option
.state
= QStyle::State_None
| QStyle::State_Raised
| QStyle::State_Horizontal
;
263 option
.state
|= QStyle::State_Enabled
;
265 if (window() && window()->isActiveWindow()) {
266 option
.state
|= QStyle::State_Active
;
268 if (m_hoveredRoleIndex
== orderIndex
) {
269 option
.state
|= QStyle::State_MouseOver
;
271 if (m_pressedRoleIndex
== orderIndex
) {
272 option
.state
|= QStyle::State_Sunken
;
274 if (m_model
->sortRole() == role
) {
275 option
.sortIndicator
= (m_model
->sortOrder() == Qt::AscendingOrder
) ?
276 QStyleOptionHeader::SortDown
: QStyleOptionHeader::SortUp
;
278 option
.rect
= rect
.toRect();
280 if (m_visibleRoles
.count() == 1) {
281 option
.position
= QStyleOptionHeader::OnlyOneSection
;
282 } else if (orderIndex
== 0) {
283 option
.position
= QStyleOptionHeader::Beginning
;
284 } else if (orderIndex
== m_visibleRoles
.count() - 1) {
285 option
.position
= QStyleOptionHeader::End
;
287 option
.position
= QStyleOptionHeader::Middle
;
290 option
.orientation
= Qt::Horizontal
;
291 option
.selectedPosition
= QStyleOptionHeader::NotAdjacent
;
292 option
.text
= m_model
->roleDescription(role
);
294 style()->drawControl(QStyle::CE_Header
, &option
, painter
);
297 void KItemListHeader::updatePressedRoleIndex(const QPointF
& pos
)
299 const int pressedIndex
= roleIndexAt(pos
);
300 if (m_pressedRoleIndex
!= pressedIndex
) {
301 m_pressedRoleIndex
= pressedIndex
;
306 void KItemListHeader::updateHoveredRoleIndex(const QPointF
& pos
)
308 const int hoverIndex
= roleIndexAt(pos
);
309 if (m_hoveredRoleIndex
!= hoverIndex
) {
310 m_hoveredRoleIndex
= hoverIndex
;
315 int KItemListHeader::roleIndexAt(const QPointF
& pos
) const
320 foreach (const QByteArray
& role
, m_visibleRoles
) {
322 x
+= m_visibleRolesWidths
.value(role
);
331 bool KItemListHeader::isAboveRoleGrip(const QPointF
& pos
, int roleIndex
) const
334 for (int i
= 0; i
<= roleIndex
; ++i
) {
335 const QByteArray role
= m_visibleRoles
.at(i
);
336 x
+= m_visibleRolesWidths
.value(role
);
339 const int grip
= style()->pixelMetric(QStyle::PM_HeaderGripMargin
);
340 return pos
.x() >= (x
- grip
) && pos
.x() <= x
;
343 qreal
KItemListHeader::minimumRoleWidth() const
345 QFontMetricsF
fontMetrics(font());
346 return fontMetrics
.height() * 4;
349 #include "kitemlistheader_p.moc"