]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistheader.cpp
Improve drawing of list-header
[dolphin.git] / src / kitemviews / kitemlistheader.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
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. *
8 * *
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. *
13 * *
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 ***************************************************************************/
19
20 #include "kitemlistheader_p.h"
21
22 #include "kitemmodelbase.h"
23
24 #include <QFontMetricsF>
25 #include <QGraphicsSceneHoverEvent>
26 #include <QPainter>
27 #include <QStyleOptionHeader>
28
29 #include <KDebug>
30
31 KItemListHeader::KItemListHeader(QGraphicsWidget* parent) :
32 QGraphicsWidget(parent),
33 m_model(0),
34 m_visibleRoles(),
35 m_visibleRolesWidths(),
36 m_hoveredRoleIndex(-1),
37 m_pressedRoleIndex(-1),
38 m_resizePressedRole(false)
39 {
40 setAcceptHoverEvents(true);
41
42 QStyleOptionHeader option;
43 const QSize headerSize = style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize());
44 resize(0, headerSize.height());
45 }
46
47 KItemListHeader::~KItemListHeader()
48 {
49 }
50
51 void KItemListHeader::setModel(KItemModelBase* model)
52 {
53 if (m_model == model) {
54 return;
55 }
56
57 if (m_model) {
58 disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
59 this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
60 disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
61 this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
62 }
63
64 m_model = model;
65
66 if (m_model) {
67 connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
68 this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
69 connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
70 this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
71 }
72 }
73
74 KItemModelBase* KItemListHeader::model() const
75 {
76 return m_model;
77 }
78
79 void KItemListHeader::setVisibleRoles(const QList<QByteArray>& roles)
80 {
81 m_visibleRoles = roles;
82 update();
83 }
84
85 QList<QByteArray> KItemListHeader::visibleRoles() const
86 {
87 return m_visibleRoles;
88 }
89
90 void KItemListHeader::setVisibleRolesWidths(const QHash<QByteArray, qreal> rolesWidths)
91 {
92 m_visibleRolesWidths = rolesWidths;
93 update();
94 }
95
96 QHash<QByteArray, qreal> KItemListHeader::visibleRolesWidths() const
97 {
98 return m_visibleRolesWidths;
99 }
100
101 void KItemListHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
102 {
103 Q_UNUSED(option);
104 Q_UNUSED(widget);
105
106 if (!m_model) {
107 return;
108 }
109
110 // Draw roles
111 painter->setFont(font());
112 painter->setPen(palette().text().color());
113
114 qreal x = 0;
115 int orderIndex = 0;
116 foreach (const QByteArray& role, m_visibleRoles) {
117 const qreal roleWidth = m_visibleRolesWidths.value(role);
118 const QRectF rect(x, 0, roleWidth, size().height());
119 paintRole(painter, role, rect, orderIndex);
120 x += roleWidth;
121 ++orderIndex;
122 }
123
124 // Draw background without roles
125 QStyleOption opt;
126 opt.init(widget);
127 opt.rect = QRect(x, 0, size().width() - x, size().height());
128 opt.state |= QStyle::State_Horizontal;
129 style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter);
130 }
131
132 void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent* event)
133 {
134 event->accept();
135 updatePressedRoleIndex(event->pos());
136 }
137
138 void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
139 {
140 QGraphicsWidget::mouseReleaseEvent(event);
141 if (m_pressedRoleIndex != -1) {
142 m_pressedRoleIndex = -1;
143 update();
144 }
145 }
146
147 void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
148 {
149 QGraphicsWidget::mouseMoveEvent(event);
150 updatePressedRoleIndex(event->pos());
151 }
152
153 void KItemListHeader::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
154 {
155 QGraphicsWidget::hoverEnterEvent(event);
156 updateHoveredRoleIndex(event->pos());
157 }
158
159 void KItemListHeader::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
160 {
161 QGraphicsWidget::hoverLeaveEvent(event);
162 if (m_hoveredRoleIndex != -1) {
163 m_hoveredRoleIndex = -1;
164 update();
165 }
166 }
167
168 void KItemListHeader::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
169 {
170 QGraphicsWidget::hoverMoveEvent(event);
171
172 const QPointF& pos = event->pos();
173 updateHoveredRoleIndex(pos);
174 if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
175 setCursor(Qt::SplitHCursor);
176 } else {
177 unsetCursor();
178 }
179 }
180
181 void KItemListHeader::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
182 {
183 Q_UNUSED(current);
184 Q_UNUSED(previous);
185 }
186
187 void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
188 {
189 Q_UNUSED(current);
190 Q_UNUSED(previous);
191 }
192
193 void KItemListHeader::paintRole(QPainter* painter,
194 const QByteArray& role,
195 const QRectF& rect,
196 int orderIndex)
197 {
198 // The following code is based on the code from QHeaderView::paintSection().
199 // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
200 QStyleOptionHeader option;
201 option.section = orderIndex;
202 option.state = QStyle::State_None | QStyle::State_Raised;
203 if (isEnabled()) {
204 option.state |= QStyle::State_Enabled;
205 }
206 if (window() && window()->isActiveWindow()) {
207 option.state |= QStyle::State_Active;
208 }
209 if (m_hoveredRoleIndex == orderIndex) {
210 option.state |= QStyle::State_MouseOver;
211 }
212 if (m_pressedRoleIndex == orderIndex) {
213 option.state |= QStyle::State_Sunken;
214 }
215 /*if (m_model->sortRole() == role) {
216 option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ?
217 QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
218 }*/
219 option.rect = rect.toRect();
220
221 if (m_visibleRoles.count() == 1) {
222 option.position = QStyleOptionHeader::OnlyOneSection;
223 } else if (orderIndex == 0) {
224 option.position = QStyleOptionHeader::Beginning;
225 } else if (orderIndex == m_visibleRoles.count() - 1) {
226 option.position = QStyleOptionHeader::End;
227 } else {
228 option.position = QStyleOptionHeader::Middle;
229 }
230
231 option.selectedPosition = QStyleOptionHeader::NotAdjacent;
232
233 const QString text = m_model->roleDescription(role);
234 const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
235 option.text = option.fontMetrics.elidedText(text, Qt::ElideRight, option.rect.width() - grip);
236
237 style()->drawControl(QStyle::CE_Header, &option, painter);
238 }
239
240 void KItemListHeader::updatePressedRoleIndex(const QPointF& pos)
241 {
242 const int pressedIndex = roleIndexAt(pos);
243 if (m_pressedRoleIndex != pressedIndex) {
244 m_pressedRoleIndex = pressedIndex;
245 update();
246 }
247 }
248
249 void KItemListHeader::updateHoveredRoleIndex(const QPointF& pos)
250 {
251 const int hoverIndex = roleIndexAt(pos);
252 if (m_hoveredRoleIndex != hoverIndex) {
253 m_hoveredRoleIndex = hoverIndex;
254 update();
255 }
256 }
257
258 int KItemListHeader::roleIndexAt(const QPointF& pos) const
259 {
260 int index = -1;
261
262 qreal x = 0;
263 foreach (const QByteArray& role, m_visibleRoles) {
264 ++index;
265 x += m_visibleRolesWidths.value(role);
266 if (pos.x() <= x) {
267 break;
268 }
269 }
270
271 return index;
272 }
273
274 bool KItemListHeader::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
275 {
276 qreal x = 0;
277 for (int i = 0; i <= roleIndex; ++i) {
278 const QByteArray role = m_visibleRoles.at(i);
279 x += m_visibleRolesWidths.value(role);
280 }
281
282 const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
283 return pos.x() >= (x - grip) && pos.x() <= x;
284 }
285
286 #include "kitemlistheader_p.moc"