]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistwidget.cpp
Merge branch 'release/20.08'
[dolphin.git] / src / kitemviews / kitemlistwidget.cpp
1 /*
2 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
3 *
4 * Based on the Itemviews NG project from Trolltech Labs
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "kitemlistwidget.h"
10
11 #include "kitemlistview.h"
12 #include "private/kitemlistselectiontoggle.h"
13
14 #include <QApplication>
15 #include <QPainter>
16 #include <QPropertyAnimation>
17 #include <QStyleOption>
18
19 KItemListWidgetInformant::KItemListWidgetInformant()
20 {
21 }
22
23 KItemListWidgetInformant::~KItemListWidgetInformant()
24 {
25 }
26
27 KItemListWidget::KItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
28 QGraphicsWidget(parent),
29 m_informant(informant),
30 m_index(-1),
31 m_selected(false),
32 m_current(false),
33 m_hovered(false),
34 m_alternateBackground(false),
35 m_enabledSelectionToggle(false),
36 m_data(),
37 m_visibleRoles(),
38 m_columnWidths(),
39 m_styleOption(),
40 m_siblingsInfo(),
41 m_hoverOpacity(0),
42 m_hoverCache(nullptr),
43 m_hoverAnimation(nullptr),
44 m_selectionToggle(nullptr),
45 m_editedRole()
46 {
47 }
48
49 KItemListWidget::~KItemListWidget()
50 {
51 clearHoverCache();
52 }
53
54 void KItemListWidget::setIndex(int index)
55 {
56 if (m_index != index) {
57 delete m_selectionToggle;
58 m_selectionToggle = nullptr;
59
60 if (m_hoverAnimation) {
61 m_hoverAnimation->stop();
62 m_hoverOpacity = 0;
63 }
64 clearHoverCache();
65
66 m_index = index;
67 }
68 }
69
70 int KItemListWidget::index() const
71 {
72 return m_index;
73 }
74
75 void KItemListWidget::setData(const QHash<QByteArray, QVariant>& data,
76 const QSet<QByteArray>& roles)
77 {
78 clearHoverCache();
79 if (roles.isEmpty()) {
80 m_data = data;
81 dataChanged(m_data);
82 } else {
83 foreach (const QByteArray& role, roles) {
84 m_data[role] = data[role];
85 }
86 dataChanged(m_data, roles);
87 }
88 update();
89 }
90
91 QHash<QByteArray, QVariant> KItemListWidget::data() const
92 {
93 return m_data;
94 }
95
96 void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
97 {
98 Q_UNUSED(option)
99
100 if (m_alternateBackground) {
101 const QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase);
102 const QRectF backgroundRect(0, 0, size().width(), size().height());
103 painter->fillRect(backgroundRect, backgroundColor);
104 }
105
106 if (m_selected && m_editedRole.isEmpty()) {
107 const QStyle::State activeState(isActiveWindow() ? QStyle::State_Active : 0);
108 drawItemStyleOption(painter, widget, activeState |
109 QStyle::State_Enabled |
110 QStyle::State_Selected |
111 QStyle::State_Item);
112 }
113
114 if (m_current && m_editedRole.isEmpty()) {
115 QStyleOptionFocusRect focusRectOption;
116 initStyleOption(&focusRectOption);
117 focusRectOption.rect = textFocusRect().toRect();
118 focusRectOption.state = QStyle::State_Enabled | QStyle::State_Item | QStyle::State_KeyboardFocusChange;
119 if (m_selected) {
120 focusRectOption.state |= QStyle::State_Selected;
121 }
122
123 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focusRectOption, painter, widget);
124 }
125
126 if (m_hoverOpacity > 0.0) {
127 if (!m_hoverCache) {
128 // Initialize the m_hoverCache pixmap to improve the drawing performance
129 // when fading the hover background
130 m_hoverCache = new QPixmap(size().toSize());
131 m_hoverCache->fill(Qt::transparent);
132
133 QPainter pixmapPainter(m_hoverCache);
134 const QStyle::State activeState(isActiveWindow() ? QStyle::State_Active : 0);
135 drawItemStyleOption(&pixmapPainter, widget, activeState |
136 QStyle::State_Enabled |
137 QStyle::State_MouseOver |
138 QStyle::State_Item);
139 }
140
141 const qreal opacity = painter->opacity();
142 painter->setOpacity(m_hoverOpacity * opacity);
143 painter->drawPixmap(0, 0, *m_hoverCache);
144 painter->setOpacity(opacity);
145 }
146 }
147
148 void KItemListWidget::setVisibleRoles(const QList<QByteArray>& roles)
149 {
150 const QList<QByteArray> previousRoles = m_visibleRoles;
151 m_visibleRoles = roles;
152
153 visibleRolesChanged(roles, previousRoles);
154 update();
155 }
156
157 QList<QByteArray> KItemListWidget::visibleRoles() const
158 {
159 return m_visibleRoles;
160 }
161
162
163 void KItemListWidget::setColumnWidth(const QByteArray& role, qreal width)
164 {
165 const qreal previousWidth = m_columnWidths.value(role);
166 if (previousWidth != width) {
167 m_columnWidths.insert(role, width);
168 columnWidthChanged(role, width, previousWidth);
169 update();
170 }
171 }
172
173 qreal KItemListWidget::columnWidth(const QByteArray& role) const
174 {
175 return m_columnWidths.value(role);
176 }
177
178 void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
179 {
180 if (m_styleOption == option) {
181 return;
182 }
183
184 const KItemListStyleOption previous = m_styleOption;
185 clearHoverCache();
186 m_styleOption = option;
187 styleOptionChanged(option, previous);
188 update();
189 }
190
191 const KItemListStyleOption& KItemListWidget::styleOption() const
192 {
193 return m_styleOption;
194 }
195
196 void KItemListWidget::setSelected(bool selected)
197 {
198 if (m_selected != selected) {
199 m_selected = selected;
200 if (m_selectionToggle) {
201 m_selectionToggle->setChecked(selected);
202 }
203 selectedChanged(selected);
204 update();
205 }
206 }
207
208 bool KItemListWidget::isSelected() const
209 {
210 return m_selected;
211 }
212
213 void KItemListWidget::setCurrent(bool current)
214 {
215 if (m_current != current) {
216 m_current = current;
217 currentChanged(current);
218 update();
219 }
220 }
221
222 bool KItemListWidget::isCurrent() const
223 {
224 return m_current;
225 }
226
227 void KItemListWidget::setHovered(bool hovered)
228 {
229 if (hovered == m_hovered) {
230 return;
231 }
232
233 m_hovered = hovered;
234
235 if (!m_hoverAnimation) {
236 m_hoverAnimation = new QPropertyAnimation(this, "hoverOpacity", this);
237 const int duration = style()->styleHint(QStyle::SH_Widget_Animate) ? 200 : 1;
238 m_hoverAnimation->setDuration(duration);
239 connect(m_hoverAnimation, &QPropertyAnimation::finished, this, &KItemListWidget::slotHoverAnimationFinished);
240 }
241 m_hoverAnimation->stop();
242
243 if (hovered) {
244 const qreal startValue = qMax(hoverOpacity(), qreal(0.1));
245 m_hoverAnimation->setStartValue(startValue);
246 m_hoverAnimation->setEndValue(1.0);
247 if (m_enabledSelectionToggle && !(QApplication::mouseButtons() & Qt::LeftButton)) {
248 initializeSelectionToggle();
249 }
250 } else {
251 m_hoverAnimation->setStartValue(hoverOpacity());
252 m_hoverAnimation->setEndValue(0.0);
253 }
254
255 m_hoverAnimation->start();
256
257 hoveredChanged(hovered);
258 update();
259 }
260
261 bool KItemListWidget::isHovered() const
262 {
263 return m_hovered;
264 }
265
266 void KItemListWidget::setHoverPosition(const QPointF& pos)
267 {
268 if (m_selectionToggle) {
269 m_selectionToggle->setHovered(selectionToggleRect().contains(pos));
270 }
271 }
272
273 void KItemListWidget::setAlternateBackground(bool enable)
274 {
275 if (m_alternateBackground != enable) {
276 m_alternateBackground = enable;
277 alternateBackgroundChanged(enable);
278 update();
279 }
280 }
281
282 bool KItemListWidget::alternateBackground() const
283 {
284 return m_alternateBackground;
285 }
286
287 void KItemListWidget::setEnabledSelectionToggle(bool enable)
288 {
289 if (m_enabledSelectionToggle != enable) {
290 m_enabledSelectionToggle = enable;
291 update();
292 }
293 }
294
295 bool KItemListWidget::enabledSelectionToggle() const
296 {
297 return m_enabledSelectionToggle;
298 }
299
300 void KItemListWidget::setSiblingsInformation(const QBitArray& siblings)
301 {
302 const QBitArray previous = m_siblingsInfo;
303 m_siblingsInfo = siblings;
304 siblingsInformationChanged(m_siblingsInfo, previous);
305 update();
306 }
307
308 QBitArray KItemListWidget::siblingsInformation() const
309 {
310 return m_siblingsInfo;
311 }
312
313 void KItemListWidget::setEditedRole(const QByteArray& role)
314 {
315 if (m_editedRole != role) {
316 const QByteArray previous = m_editedRole;
317 m_editedRole = role;
318 editedRoleChanged(role, previous);
319 }
320 }
321
322 QByteArray KItemListWidget::editedRole() const
323 {
324 return m_editedRole;
325 }
326
327 bool KItemListWidget::contains(const QPointF& point) const
328 {
329 if (!QGraphicsWidget::contains(point)) {
330 return false;
331 }
332
333 return iconRect().contains(point) ||
334 textRect().contains(point) ||
335 expansionToggleRect().contains(point) ||
336 selectionToggleRect().contains(point);
337 }
338
339 QRectF KItemListWidget::textFocusRect() const
340 {
341 return textRect();
342 }
343
344 QRectF KItemListWidget::selectionToggleRect() const
345 {
346 return QRectF();
347 }
348
349 QRectF KItemListWidget::expansionToggleRect() const
350 {
351 return QRectF();
352 }
353
354 QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem* option,
355 QWidget* widget)
356 {
357 QPixmap pixmap(size().toSize() * widget->devicePixelRatio());
358 pixmap.setDevicePixelRatio(widget->devicePixelRatio());
359 pixmap.fill(Qt::transparent);
360
361 QPainter painter(&pixmap);
362
363 const bool oldAlternateBackground = m_alternateBackground;
364 const bool wasSelected = m_selected;
365 const bool wasHovered = m_hovered;
366
367 setAlternateBackground(false);
368 setHovered(false);
369
370 paint(&painter, option, widget);
371
372 setAlternateBackground(oldAlternateBackground);
373 setSelected(wasSelected);
374 setHovered(wasHovered);
375
376 return pixmap;
377 }
378
379 void KItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
380 const QSet<QByteArray>& roles)
381 {
382 Q_UNUSED(current)
383 Q_UNUSED(roles)
384 }
385
386 void KItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
387 const QList<QByteArray>& previous)
388 {
389 Q_UNUSED(current)
390 Q_UNUSED(previous)
391 }
392
393 void KItemListWidget::columnWidthChanged(const QByteArray& role,
394 qreal current,
395 qreal previous)
396 {
397 Q_UNUSED(role)
398 Q_UNUSED(current)
399 Q_UNUSED(previous)
400 }
401
402 void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
403 const KItemListStyleOption& previous)
404 {
405 Q_UNUSED(current)
406 Q_UNUSED(previous)
407 }
408
409 void KItemListWidget::currentChanged(bool current)
410 {
411 Q_UNUSED(current)
412 }
413
414 void KItemListWidget::selectedChanged(bool selected)
415 {
416 Q_UNUSED(selected)
417 }
418
419 void KItemListWidget::hoveredChanged(bool hovered)
420 {
421 Q_UNUSED(hovered)
422 }
423
424 void KItemListWidget::alternateBackgroundChanged(bool enabled)
425 {
426 Q_UNUSED(enabled)
427 }
428
429 void KItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
430 {
431 Q_UNUSED(current)
432 Q_UNUSED(previous)
433 }
434
435 void KItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous)
436 {
437 Q_UNUSED(current)
438 Q_UNUSED(previous)
439 }
440
441 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
442 {
443 QGraphicsWidget::resizeEvent(event);
444 clearHoverCache();
445
446 if (m_selectionToggle) {
447 const QRectF& toggleRect = selectionToggleRect();
448 m_selectionToggle->setPos(toggleRect.topLeft());
449 m_selectionToggle->resize(toggleRect.size());
450 }
451 }
452
453 qreal KItemListWidget::hoverOpacity() const
454 {
455 return m_hoverOpacity;
456 }
457
458 void KItemListWidget::slotHoverAnimationFinished()
459 {
460 if (!m_hovered && m_selectionToggle) {
461 m_selectionToggle->deleteLater();
462 m_selectionToggle = nullptr;
463 }
464 }
465
466 void KItemListWidget::initializeSelectionToggle()
467 {
468 Q_ASSERT(m_enabledSelectionToggle);
469
470 if (!m_selectionToggle) {
471 m_selectionToggle = new KItemListSelectionToggle(this);
472 }
473
474 const QRectF toggleRect = selectionToggleRect();
475 m_selectionToggle->setPos(toggleRect.topLeft());
476 m_selectionToggle->resize(toggleRect.size());
477
478 m_selectionToggle->setChecked(isSelected());
479 }
480
481 void KItemListWidget::setHoverOpacity(qreal opacity)
482 {
483 m_hoverOpacity = opacity;
484 if (m_selectionToggle) {
485 m_selectionToggle->setOpacity(opacity);
486 }
487
488 if (m_hoverOpacity <= 0.0) {
489 delete m_hoverCache;
490 m_hoverCache = nullptr;
491 }
492
493 update();
494 }
495
496 void KItemListWidget::clearHoverCache()
497 {
498 delete m_hoverCache;
499 m_hoverCache = nullptr;
500 }
501
502 void KItemListWidget::drawItemStyleOption(QPainter* painter, QWidget* widget, QStyle::State styleState)
503 {
504 QStyleOptionViewItem viewItemOption;
505 initStyleOption(&viewItemOption);
506 viewItemOption.state = styleState;
507 viewItemOption.viewItemPosition = QStyleOptionViewItem::OnlyOne;
508 viewItemOption.showDecorationSelected = true;
509 viewItemOption.rect = selectionRect().toRect();
510 style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget);
511 }
512