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