1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2008 Rafael Fernández López <ereslibre@kde.org>
4 SPDX-FileCopyrightText: 2008 Kevin Ottens <ervin@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "kwidgetitemdelegatepool_p.h"
10
11#include <QAbstractItemView>
12#include <QAbstractProxyModel>
13#include <QApplication>
14#include <QHash>
15#include <QInputEvent>
16#include <QList>
17#include <QMetaMethod>
18#include <QWidget>
19#include <qobjectdefs.h>
20
21#include "kwidgetitemdelegate.h"
22#include "kwidgetitemdelegate_p.h"
23#include <kitemviews_debug.h>
24
25class KWidgetItemDelegateEventListener : public QObject
26{
27public:
28 KWidgetItemDelegateEventListener(KWidgetItemDelegatePoolPrivate *poolPrivate, QObject *parent = nullptr)
29 : QObject(parent)
30 , poolPrivate(poolPrivate)
31 {
32 }
33
34 bool eventFilter(QObject *watched, QEvent *event) override;
35
36private:
37 KWidgetItemDelegatePoolPrivate *const poolPrivate;
38};
39
40KWidgetItemDelegatePoolPrivate::KWidgetItemDelegatePoolPrivate(KWidgetItemDelegate *d)
41 : delegate(d)
42 , eventListener(new KWidgetItemDelegateEventListener(this))
43{
44}
45
46KWidgetItemDelegatePool::KWidgetItemDelegatePool(KWidgetItemDelegate *delegate)
47 : d(new KWidgetItemDelegatePoolPrivate(delegate))
48{
49}
50
51KWidgetItemDelegatePool::~KWidgetItemDelegatePool()
52{
53 delete d->eventListener;
54 delete d;
55}
56
57QList<QWidget *>
58KWidgetItemDelegatePool::findWidgets(const QPersistentModelIndex &idx, const QStyleOptionViewItem &option, UpdateWidgetsEnum updateWidgets) const
59{
60 QList<QWidget *> result;
61
62 if (!idx.isValid()) {
63 return result;
64 }
65
66 QModelIndex index;
67 if (const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel *>(object: idx.model())) {
68 index = proxyModel->mapToSource(proxyIndex: idx);
69 } else {
70 index = idx;
71 }
72
73 if (!index.isValid()) {
74 return result;
75 }
76
77 if (d->usedWidgets.contains(key: index)) {
78 result = d->usedWidgets[index];
79 } else {
80 result = d->delegate->createItemWidgets(index);
81 d->usedWidgets[index] = result;
82 for (QWidget *widget : std::as_const(t&: result)) {
83 d->widgetInIndex[widget] = index;
84 widget->setParent(d->delegate->d->itemView->viewport());
85 widget->installEventFilter(filterObj: d->eventListener);
86 widget->setVisible(true);
87 }
88 }
89
90 if (updateWidgets == UpdateWidgets) {
91 for (QWidget *widget : std::as_const(t&: result)) {
92 widget->setVisible(true);
93 }
94
95 d->delegate->updateItemWidgets(widgets: result, option, index: idx);
96
97 for (QWidget *widget : std::as_const(t&: result)) {
98 widget->move(ax: widget->x() + option.rect.left(), ay: widget->y() + option.rect.top());
99 }
100 }
101
102 return result;
103}
104
105QList<QWidget *> KWidgetItemDelegatePool::invalidIndexesWidgets() const
106{
107 QList<QWidget *> result;
108 QHashIterator<QWidget *, QPersistentModelIndex> i(d->widgetInIndex);
109 while (i.hasNext()) {
110 i.next();
111 const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel *>(object: d->delegate->d->model);
112 QModelIndex index;
113 if (proxyModel) {
114 index = proxyModel->mapFromSource(sourceIndex: i.value());
115 } else {
116 index = i.value();
117 }
118 if (!index.isValid()) {
119 result << i.key();
120 }
121 }
122 return result;
123}
124
125void KWidgetItemDelegatePool::fullClear()
126{
127 d->clearing = true;
128 qDeleteAll(c: d->widgetInIndex.keys());
129 d->clearing = false;
130 d->usedWidgets.clear();
131 d->widgetInIndex.clear();
132}
133
134bool KWidgetItemDelegateEventListener::eventFilter(QObject *watched, QEvent *event)
135{
136 QWidget *widget = static_cast<QWidget *>(watched);
137
138 if (event->type() == QEvent::Destroy && !poolPrivate->clearing) {
139 qCWarning(KITEMVIEWS_LOG) << "User of KWidgetItemDelegate should not delete widgets created by createItemWidgets!";
140 // assume the application has kept a list of widgets and tries to delete them manually
141 // they have been reparented to the view in any case, so no leaking occurs
142 poolPrivate->widgetInIndex.remove(key: widget);
143 }
144 if (dynamic_cast<QInputEvent *>(event) && !poolPrivate->delegate->blockedEventTypes(widget).contains(t: event->type())) {
145 QWidget *viewport = poolPrivate->delegate->d->itemView->viewport();
146 switch (event->type()) {
147 case QEvent::MouseMove:
148 case QEvent::MouseButtonPress:
149 case QEvent::MouseButtonRelease:
150 case QEvent::MouseButtonDblClick: {
151 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
152 QMouseEvent evt(event->type(),
153 mouseEvent->position(),
154 viewport->mapFromGlobal(mouseEvent->globalPosition()),
155 mouseEvent->button(),
156 mouseEvent->buttons(),
157 mouseEvent->modifiers());
158 QApplication::sendEvent(receiver: viewport, event: &evt);
159 } break;
160 case QEvent::Wheel: {
161 QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
162 QWheelEvent evt(viewport->mapFromGlobal(wheelEvent->position().toPoint()),
163 viewport->mapFromGlobal(wheelEvent->globalPosition().toPoint()),
164 wheelEvent->pixelDelta(),
165 wheelEvent->angleDelta(),
166 wheelEvent->buttons(),
167 wheelEvent->modifiers(),
168 wheelEvent->phase(),
169 wheelEvent->inverted(),
170 wheelEvent->source());
171 QApplication::sendEvent(receiver: viewport, event: &evt);
172 } break;
173 case QEvent::TabletMove:
174 case QEvent::TabletPress:
175 case QEvent::TabletRelease:
176 case QEvent::TabletEnterProximity:
177 case QEvent::TabletLeaveProximity: {
178 QTabletEvent *tabletEvent = static_cast<QTabletEvent *>(event);
179 QTabletEvent evt(event->type(),
180 tabletEvent->pointingDevice(),
181 viewport->mapFromGlobal(tabletEvent->globalPosition()),
182 tabletEvent->globalPosition(),
183 tabletEvent->pressure(),
184 tabletEvent->xTilt(),
185 tabletEvent->yTilt(),
186 tabletEvent->tangentialPressure(),
187 tabletEvent->rotation(),
188 tabletEvent->z(),
189 tabletEvent->modifiers(),
190 tabletEvent->button(),
191 tabletEvent->buttons());
192 QApplication::sendEvent(receiver: viewport, event: &evt);
193 break;
194 }
195 default:
196 QApplication::sendEvent(receiver: viewport, event);
197 break;
198 }
199 }
200
201 return QObject::eventFilter(watched, event);
202}
203

source code of kitemviews/src/kwidgetitemdelegatepool.cpp