]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistwidget.cpp
Clazy fix
[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_expansionAreaHovered(false)
38 , m_alternateBackground(false)
39 , m_enabledSelectionToggle(false)
40 , m_data()
41 , m_visibleRoles()
42 , m_columnWidths()
43 , m_leftPadding(0)
44 , m_rightPadding(0)
45 , m_styleOption()
46 , m_siblingsInfo()
47 , m_hoverOpacity(0)
48 , m_hoverCache(nullptr)
49 , m_hoverSequenceIndex(0)
50 , m_selectionToggle(nullptr)
51 , m_editedRole()
52 , m_iconSize(-1)
53 {
54 connect(&m_hoverSequenceTimer, &QTimer::timeout, this, &KItemListWidget::slotHoverSequenceTimerTimeout);
55 }
56
57 KItemListWidget::~KItemListWidget()
58 {
59 clearHoverCache();
60 }
61
62 void KItemListWidget::setIndex(int index)
63 {
64 if (m_index != index) {
65 delete m_selectionToggle;
66 m_selectionToggle = nullptr;
67
68 m_hoverOpacity = 0;
69
70 clearHoverCache();
71
72 m_index = index;
73 }
74 }
75
76 int KItemListWidget::index() const
77 {
78 return m_index;
79 }
80
81 void KItemListWidget::setData(const QHash<QByteArray, QVariant> &data, 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 QVariant KItemListWidget::value(const QByteArray &key) const
102 {
103 return m_data.value(key);
104 }
105
106 void KItemListWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
107 {
108 Q_UNUSED(option)
109
110 if (m_alternateBackground) {
111 QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase);
112 if (!widget->hasFocus()) {
113 QColor baseColor = m_styleOption.palette.color(QPalette::Base);
114 if (baseColor.lightnessF() > 0.5) {
115 // theme seems light
116 backgroundColor = backgroundColor.lighter(101);
117 } else {
118 // theme seems dark
119 backgroundColor = backgroundColor.darker(101);
120 }
121 }
122
123 const QRectF backgroundRect(0, 0, size().width(), size().height());
124 painter->fillRect(backgroundRect, backgroundColor);
125 }
126
127 if (m_selected && m_editedRole.isEmpty()) {
128 const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active : 0);
129 drawItemStyleOption(painter, widget, activeState | QStyle::State_Enabled | QStyle::State_Selected | QStyle::State_Item);
130 }
131
132 if (m_current && m_editedRole.isEmpty()) {
133 QStyleOptionFocusRect focusRectOption;
134 initStyleOption(&focusRectOption);
135 focusRectOption.rect = textFocusRect().toRect();
136 focusRectOption.state = QStyle::State_Enabled | QStyle::State_Item | QStyle::State_KeyboardFocusChange;
137 if (m_selected && widget->hasFocus()) {
138 focusRectOption.state |= QStyle::State_Selected;
139 }
140
141 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focusRectOption, painter, widget);
142 }
143
144 if (m_hoverOpacity > 0.0) {
145 if (!m_hoverCache) {
146 // Initialize the m_hoverCache pixmap to improve the drawing performance
147 // when fading the hover background
148 m_hoverCache = new QPixmap(size().toSize());
149 m_hoverCache->fill(Qt::transparent);
150
151 QPainter pixmapPainter(m_hoverCache);
152 const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active | QStyle::State_Enabled : 0);
153 drawItemStyleOption(&pixmapPainter, widget, activeState | QStyle::State_MouseOver | QStyle::State_Item);
154 }
155
156 const qreal opacity = painter->opacity();
157 painter->setOpacity(m_hoverOpacity * opacity);
158 painter->drawPixmap(0, 0, *m_hoverCache);
159 painter->setOpacity(opacity);
160 }
161 }
162
163 void KItemListWidget::setVisibleRoles(const QList<QByteArray> &roles)
164 {
165 const QList<QByteArray> previousRoles = m_visibleRoles;
166 m_visibleRoles = roles;
167
168 visibleRolesChanged(roles, previousRoles);
169 update();
170 }
171
172 QList<QByteArray> KItemListWidget::visibleRoles() const
173 {
174 return m_visibleRoles;
175 }
176
177 void KItemListWidget::setColumnWidth(const QByteArray &role, qreal width)
178 {
179 const qreal previousWidth = m_columnWidths.value(role);
180 if (previousWidth != width) {
181 m_columnWidths.insert(role, width);
182 columnWidthChanged(role, width, previousWidth);
183 update();
184 }
185 }
186
187 qreal KItemListWidget::columnWidth(const QByteArray &role) const
188 {
189 return m_columnWidths.value(role);
190 }
191
192 void KItemListWidget::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth)
193 {
194 bool changed = false;
195 if (m_leftPadding != leftPaddingWidth) {
196 m_leftPadding = leftPaddingWidth;
197 changed = true;
198 }
199
200 if (m_rightPadding != rightPaddingWidth) {
201 m_rightPadding = rightPaddingWidth;
202 changed = true;
203 }
204
205 if (!changed) {
206 return;
207 }
208
209 sidePaddingChanged(leftPaddingWidth, rightPaddingWidth);
210 update();
211 }
212
213 qreal KItemListWidget::leftPadding() const
214 {
215 return m_leftPadding;
216 }
217
218 qreal KItemListWidget::rightPadding() const
219 {
220 return m_rightPadding;
221 }
222
223 void KItemListWidget::setStyleOption(const KItemListStyleOption &option)
224 {
225 if (m_styleOption == option) {
226 return;
227 }
228
229 const KItemListStyleOption previous = m_styleOption;
230 clearHoverCache();
231 m_styleOption = option;
232 styleOptionChanged(option, previous);
233 update();
234 }
235
236 const KItemListStyleOption &KItemListWidget::styleOption() const
237 {
238 return m_styleOption;
239 }
240
241 void KItemListWidget::setSelected(bool selected)
242 {
243 if (m_selected != selected) {
244 m_selected = selected;
245 if (m_selectionToggle) {
246 m_selectionToggle->setChecked(selected);
247 }
248 selectedChanged(selected);
249 update();
250 }
251 }
252
253 bool KItemListWidget::isSelected() const
254 {
255 return m_selected;
256 }
257
258 void KItemListWidget::setCurrent(bool current)
259 {
260 if (m_current != current) {
261 m_current = current;
262 currentChanged(current);
263 update();
264 }
265 }
266
267 bool KItemListWidget::isCurrent() const
268 {
269 return m_current;
270 }
271
272 void KItemListWidget::setHovered(bool hovered)
273 {
274 if (hovered == m_hovered) {
275 return;
276 }
277
278 m_hovered = hovered;
279
280 m_hoverSequenceIndex = 0;
281
282 if (hovered) {
283 setHoverOpacity(1.0);
284
285 if (m_enabledSelectionToggle && !(QApplication::mouseButtons() & Qt::LeftButton)) {
286 initializeSelectionToggle();
287 }
288
289 hoverSequenceStarted();
290
291 const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings"));
292 const int interval = globalConfig.readEntry("HoverSequenceInterval", 700);
293
294 m_hoverSequenceTimer.start(interval);
295 } else {
296 setHoverOpacity(0.0);
297
298 if (m_selectionToggle) {
299 m_selectionToggle->deleteLater();
300 m_selectionToggle = nullptr;
301 }
302
303 hoverSequenceEnded();
304 m_hoverSequenceTimer.stop();
305 }
306
307 hoveredChanged(hovered);
308 update();
309 }
310
311 bool KItemListWidget::isHovered() const
312 {
313 return m_hovered;
314 }
315
316 void KItemListWidget::setExpansionAreaHovered(bool hovered)
317 {
318 if (hovered == m_expansionAreaHovered) {
319 return;
320 }
321 m_expansionAreaHovered = hovered;
322 update();
323 }
324
325 bool KItemListWidget::expansionAreaHovered() const
326 {
327 return m_expansionAreaHovered;
328 }
329
330 void KItemListWidget::setHoverPosition(const QPointF &pos)
331 {
332 if (m_selectionToggle) {
333 m_selectionToggle->setHovered(selectionToggleRect().contains(pos));
334 }
335 }
336
337 void KItemListWidget::setAlternateBackground(bool enable)
338 {
339 if (m_alternateBackground != enable) {
340 m_alternateBackground = enable;
341 alternateBackgroundChanged(enable);
342 update();
343 }
344 }
345
346 bool KItemListWidget::alternateBackground() const
347 {
348 return m_alternateBackground;
349 }
350
351 void KItemListWidget::setEnabledSelectionToggle(bool enable)
352 {
353 if (m_enabledSelectionToggle != enable) {
354 m_enabledSelectionToggle = enable;
355
356 // We want the change to take effect immediately.
357 if (m_enabledSelectionToggle) {
358 if (m_hovered) {
359 initializeSelectionToggle();
360 }
361 } else if (m_selectionToggle) {
362 m_selectionToggle->deleteLater();
363 m_selectionToggle = nullptr;
364 }
365
366 update();
367 }
368 }
369
370 bool KItemListWidget::enabledSelectionToggle() const
371 {
372 return m_enabledSelectionToggle;
373 }
374
375 void KItemListWidget::setSiblingsInformation(const QBitArray &siblings)
376 {
377 const QBitArray previous = m_siblingsInfo;
378 m_siblingsInfo = siblings;
379 siblingsInformationChanged(m_siblingsInfo, previous);
380 update();
381 }
382
383 QBitArray KItemListWidget::siblingsInformation() const
384 {
385 return m_siblingsInfo;
386 }
387
388 void KItemListWidget::setEditedRole(const QByteArray &role)
389 {
390 if (m_editedRole != role) {
391 const QByteArray previous = m_editedRole;
392 m_editedRole = role;
393 editedRoleChanged(role, previous);
394 }
395 }
396
397 QByteArray KItemListWidget::editedRole() const
398 {
399 return m_editedRole;
400 }
401
402 void KItemListWidget::setIconSize(int iconSize)
403 {
404 if (m_iconSize != iconSize) {
405 const int previousIconSize = m_iconSize;
406 m_iconSize = iconSize;
407 iconSizeChanged(iconSize, previousIconSize);
408 }
409 }
410
411 int KItemListWidget::iconSize() const
412 {
413 return m_iconSize;
414 }
415
416 bool KItemListWidget::contains(const QPointF &point) const
417 {
418 if (!QGraphicsWidget::contains(point)) {
419 return false;
420 }
421
422 return iconRect().contains(point) || textRect().contains(point) || expansionToggleRect().contains(point) || selectionToggleRect().contains(point);
423 }
424
425 QRectF KItemListWidget::textFocusRect() const
426 {
427 return textRect();
428 }
429
430 QRectF KItemListWidget::selectionToggleRect() const
431 {
432 return QRectF();
433 }
434
435 QRectF KItemListWidget::expansionToggleRect() const
436 {
437 return QRectF();
438 }
439
440 QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem *option, QWidget *widget)
441 {
442 QPixmap pixmap(size().toSize() * widget->devicePixelRatio());
443 pixmap.setDevicePixelRatio(widget->devicePixelRatio());
444 pixmap.fill(Qt::transparent);
445
446 QPainter painter(&pixmap);
447
448 const bool oldAlternateBackground = m_alternateBackground;
449 const bool wasSelected = m_selected;
450 const bool wasHovered = m_hovered;
451
452 setAlternateBackground(false);
453 setHovered(false);
454
455 paint(&painter, option, widget);
456
457 setAlternateBackground(oldAlternateBackground);
458 setSelected(wasSelected);
459 setHovered(wasHovered);
460
461 return pixmap;
462 }
463
464 void KItemListWidget::startActivateSoonAnimation(int timeUntilActivation)
465 {
466 Q_UNUSED(timeUntilActivation)
467 }
468
469 void KItemListWidget::dataChanged(const QHash<QByteArray, QVariant> &current, const QSet<QByteArray> &roles)
470 {
471 Q_UNUSED(current)
472 Q_UNUSED(roles)
473 }
474
475 void KItemListWidget::visibleRolesChanged(const QList<QByteArray> &current, const QList<QByteArray> &previous)
476 {
477 Q_UNUSED(current)
478 Q_UNUSED(previous)
479 }
480
481 void KItemListWidget::columnWidthChanged(const QByteArray &role, qreal current, qreal previous)
482 {
483 Q_UNUSED(role)
484 Q_UNUSED(current)
485 Q_UNUSED(previous)
486 }
487
488 void KItemListWidget::sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth)
489 {
490 Q_UNUSED(leftPaddingWidth)
491 Q_UNUSED(rightPaddingWidth)
492 }
493
494 void KItemListWidget::styleOptionChanged(const KItemListStyleOption &current, const KItemListStyleOption &previous)
495 {
496 Q_UNUSED(previous)
497
498 // set the initial value of m_iconSize if not set
499 if (m_iconSize == -1) {
500 m_iconSize = current.iconSize;
501 }
502 }
503
504 void KItemListWidget::currentChanged(bool current)
505 {
506 Q_UNUSED(current)
507 }
508
509 void KItemListWidget::selectedChanged(bool selected)
510 {
511 Q_UNUSED(selected)
512 }
513
514 void KItemListWidget::hoveredChanged(bool hovered)
515 {
516 Q_UNUSED(hovered)
517 }
518
519 void KItemListWidget::alternateBackgroundChanged(bool enabled)
520 {
521 Q_UNUSED(enabled)
522 }
523
524 void KItemListWidget::siblingsInformationChanged(const QBitArray &current, const QBitArray &previous)
525 {
526 Q_UNUSED(current)
527 Q_UNUSED(previous)
528 }
529
530 void KItemListWidget::editedRoleChanged(const QByteArray &current, const QByteArray &previous)
531 {
532 Q_UNUSED(current)
533 Q_UNUSED(previous)
534 }
535
536 void KItemListWidget::iconSizeChanged(int current, int previous)
537 {
538 Q_UNUSED(current)
539 Q_UNUSED(previous)
540 }
541
542 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
543 {
544 QGraphicsWidget::resizeEvent(event);
545 clearHoverCache();
546
547 if (m_selectionToggle) {
548 const QRectF &toggleRect = selectionToggleRect();
549 m_selectionToggle->setPos(toggleRect.topLeft());
550 m_selectionToggle->resize(toggleRect.size());
551 }
552 }
553
554 void KItemListWidget::hoverSequenceStarted()
555 {
556 }
557
558 void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex)
559 {
560 Q_UNUSED(sequenceIndex);
561 }
562
563 void KItemListWidget::hoverSequenceEnded()
564 {
565 }
566
567 qreal KItemListWidget::hoverOpacity() const
568 {
569 return m_hoverOpacity;
570 }
571
572 int KItemListWidget::hoverSequenceIndex() const
573 {
574 return m_hoverSequenceIndex;
575 }
576
577 void KItemListWidget::slotHoverSequenceTimerTimeout()
578 {
579 m_hoverSequenceIndex++;
580 hoverSequenceIndexChanged(m_hoverSequenceIndex);
581 }
582
583 void KItemListWidget::initializeSelectionToggle()
584 {
585 Q_ASSERT(m_enabledSelectionToggle);
586
587 if (!m_selectionToggle) {
588 m_selectionToggle = new KItemListSelectionToggle(this);
589 }
590
591 const QRectF toggleRect = selectionToggleRect();
592 m_selectionToggle->setPos(toggleRect.topLeft());
593 m_selectionToggle->resize(toggleRect.size());
594
595 m_selectionToggle->setChecked(isSelected());
596 }
597
598 void KItemListWidget::setHoverOpacity(qreal opacity)
599 {
600 m_hoverOpacity = opacity;
601 if (m_selectionToggle) {
602 m_selectionToggle->setOpacity(opacity);
603 }
604
605 if (m_hoverOpacity <= 0.0) {
606 delete m_hoverCache;
607 m_hoverCache = nullptr;
608 }
609
610 update();
611 }
612
613 void KItemListWidget::clearHoverCache()
614 {
615 delete m_hoverCache;
616 m_hoverCache = nullptr;
617 }
618
619 void KItemListWidget::drawItemStyleOption(QPainter *painter, QWidget *widget, QStyle::State styleState)
620 {
621 QStyleOptionViewItem viewItemOption;
622 initStyleOption(&viewItemOption);
623 viewItemOption.state = styleState;
624 viewItemOption.viewItemPosition = QStyleOptionViewItem::OnlyOne;
625 viewItemOption.showDecorationSelected = true;
626 viewItemOption.rect = selectionRect().toRect();
627 style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget);
628 }
629
630 #include "moc_kitemlistwidget.cpp"