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

source code of kitemviews/src/kwidgetitemdelegatepool.cpp