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