File indexing completed on 2024-09-08 06:42:14
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2008 Rafael Fernández López <ereslibre@kde.org> 0004 SPDX-FileCopyrightText: 2008 Kevin Ottens <ervin@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kwidgetitemdelegatepool_p.h" 0010 0011 #include <QAbstractItemView> 0012 #include <QAbstractProxyModel> 0013 #include <QApplication> 0014 #include <QHash> 0015 #include <QInputEvent> 0016 #include <QList> 0017 #include <QMetaMethod> 0018 #include <QWidget> 0019 #include <qobjectdefs.h> 0020 0021 #include "kwidgetitemdelegate.h" 0022 #include "kwidgetitemdelegate_p.h" 0023 #include <kitemviews_debug.h> 0024 0025 /** 0026 Private class that helps to provide binary compatibility between releases. 0027 @internal 0028 */ 0029 //@cond PRIVATE 0030 class KWidgetItemDelegateEventListener : public QObject 0031 { 0032 public: 0033 KWidgetItemDelegateEventListener(KWidgetItemDelegatePoolPrivate *poolPrivate, QObject *parent = nullptr) 0034 : QObject(parent) 0035 , poolPrivate(poolPrivate) 0036 { 0037 } 0038 0039 bool eventFilter(QObject *watched, QEvent *event) override; 0040 0041 private: 0042 KWidgetItemDelegatePoolPrivate *const poolPrivate; 0043 }; 0044 0045 KWidgetItemDelegatePoolPrivate::KWidgetItemDelegatePoolPrivate(KWidgetItemDelegate *d) 0046 : delegate(d) 0047 , eventListener(new KWidgetItemDelegateEventListener(this)) 0048 { 0049 } 0050 0051 KWidgetItemDelegatePool::KWidgetItemDelegatePool(KWidgetItemDelegate *delegate) 0052 : d(new KWidgetItemDelegatePoolPrivate(delegate)) 0053 { 0054 } 0055 0056 KWidgetItemDelegatePool::~KWidgetItemDelegatePool() 0057 { 0058 delete d->eventListener; 0059 delete d; 0060 } 0061 0062 QList<QWidget *> 0063 KWidgetItemDelegatePool::findWidgets(const QPersistentModelIndex &idx, const QStyleOptionViewItem &option, UpdateWidgetsEnum updateWidgets) const 0064 { 0065 QList<QWidget *> result; 0066 0067 if (!idx.isValid()) { 0068 return result; 0069 } 0070 0071 QModelIndex index; 0072 if (const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel *>(idx.model())) { 0073 index = proxyModel->mapToSource(idx); 0074 } else { 0075 index = idx; 0076 } 0077 0078 if (!index.isValid()) { 0079 return result; 0080 } 0081 0082 if (d->usedWidgets.contains(index)) { 0083 result = d->usedWidgets[index]; 0084 } else { 0085 result = d->delegate->createItemWidgets(index); 0086 d->allocatedWidgets << result; 0087 d->usedWidgets[index] = result; 0088 for (QWidget *widget : std::as_const(result)) { 0089 d->widgetInIndex[widget] = index; 0090 widget->setParent(d->delegate->d->itemView->viewport()); 0091 widget->installEventFilter(d->eventListener); 0092 widget->setVisible(true); 0093 } 0094 } 0095 0096 if (updateWidgets == UpdateWidgets) { 0097 for (QWidget *widget : std::as_const(result)) { 0098 widget->setVisible(true); 0099 } 0100 0101 d->delegate->updateItemWidgets(result, option, idx); 0102 0103 for (QWidget *widget : std::as_const(result)) { 0104 widget->move(widget->x() + option.rect.left(), widget->y() + option.rect.top()); 0105 } 0106 } 0107 0108 return result; 0109 } 0110 0111 QList<QWidget *> KWidgetItemDelegatePool::invalidIndexesWidgets() const 0112 { 0113 QList<QWidget *> result; 0114 QHashIterator<QWidget *, QPersistentModelIndex> i(d->widgetInIndex); 0115 while (i.hasNext()) { 0116 i.next(); 0117 const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel *>(d->delegate->d->model); 0118 QModelIndex index; 0119 if (proxyModel) { 0120 index = proxyModel->mapFromSource(i.value()); 0121 } else { 0122 index = i.value(); 0123 } 0124 if (!index.isValid()) { 0125 result << i.key(); 0126 } 0127 } 0128 return result; 0129 } 0130 0131 void KWidgetItemDelegatePool::fullClear() 0132 { 0133 d->clearing = true; 0134 qDeleteAll(d->widgetInIndex.keys()); 0135 d->clearing = false; 0136 d->allocatedWidgets.clear(); 0137 d->usedWidgets.clear(); 0138 d->widgetInIndex.clear(); 0139 } 0140 0141 bool KWidgetItemDelegateEventListener::eventFilter(QObject *watched, QEvent *event) 0142 { 0143 QWidget *widget = static_cast<QWidget *>(watched); 0144 0145 if (event->type() == QEvent::Destroy && !poolPrivate->clearing) { 0146 qCWarning(KITEMVIEWS_LOG) << "User of KWidgetItemDelegate should not delete widgets created by createItemWidgets!"; 0147 // assume the application has kept a list of widgets and tries to delete them manually 0148 // they have been reparented to the view in any case, so no leaking occurs 0149 poolPrivate->widgetInIndex.remove(widget); 0150 QWidget *viewport = poolPrivate->delegate->d->itemView->viewport(); 0151 QApplication::sendEvent(viewport, event); 0152 } 0153 if (dynamic_cast<QInputEvent *>(event) && !poolPrivate->delegate->blockedEventTypes(widget).contains(event->type())) { 0154 QWidget *viewport = poolPrivate->delegate->d->itemView->viewport(); 0155 switch (event->type()) { 0156 case QEvent::MouseMove: 0157 case QEvent::MouseButtonPress: 0158 case QEvent::MouseButtonRelease: 0159 case QEvent::MouseButtonDblClick: { 0160 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); 0161 QMouseEvent evt(event->type(), 0162 mouseEvent->position(), 0163 viewport->mapFromGlobal(mouseEvent->globalPosition()), 0164 mouseEvent->button(), 0165 mouseEvent->buttons(), 0166 mouseEvent->modifiers()); 0167 QApplication::sendEvent(viewport, &evt); 0168 } break; 0169 case QEvent::Wheel: { 0170 QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event); 0171 QWheelEvent evt(viewport->mapFromGlobal(wheelEvent->position().toPoint()), 0172 viewport->mapFromGlobal(wheelEvent->globalPosition().toPoint()), 0173 wheelEvent->pixelDelta(), 0174 wheelEvent->angleDelta(), 0175 wheelEvent->buttons(), 0176 wheelEvent->modifiers(), 0177 wheelEvent->phase(), 0178 wheelEvent->inverted(), 0179 wheelEvent->source()); 0180 QApplication::sendEvent(viewport, &evt); 0181 } break; 0182 case QEvent::TabletMove: 0183 case QEvent::TabletPress: 0184 case QEvent::TabletRelease: 0185 case QEvent::TabletEnterProximity: 0186 case QEvent::TabletLeaveProximity: { 0187 QTabletEvent *tabletEvent = static_cast<QTabletEvent *>(event); 0188 QTabletEvent evt(event->type(), 0189 tabletEvent->pointingDevice(), 0190 viewport->mapFromGlobal(tabletEvent->globalPosition()), 0191 tabletEvent->globalPosition(), 0192 tabletEvent->pressure(), 0193 tabletEvent->xTilt(), 0194 tabletEvent->yTilt(), 0195 tabletEvent->tangentialPressure(), 0196 tabletEvent->rotation(), 0197 tabletEvent->z(), 0198 tabletEvent->modifiers(), 0199 tabletEvent->button(), 0200 tabletEvent->buttons()); 0201 QApplication::sendEvent(viewport, &evt); 0202 break; 0203 } 0204 default: 0205 QApplication::sendEvent(viewport, event); 0206 break; 0207 } 0208 } 0209 0210 return QObject::eventFilter(watched, event); 0211 } 0212 //@endcond