File indexing completed on 2025-01-05 04:00:09
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2007-11-15 0007 * Description : widget item delegate for setup collection view 0008 * 0009 * SPDX-FileCopyrightText: 2015-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2007-2008 by Rafael Fernández López <ereslibre at kde dot org> 0011 * SPDX-FileCopyrightText: 2008 by Kevin Ottens <ervin at kde dot org> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "dwitemdelegatepool.h" 0018 0019 // Qt includes 0020 0021 #include <QWidget> 0022 #include <QInputEvent> 0023 #include <QApplication> 0024 #include <QAbstractItemView> 0025 #include <QAbstractProxyModel> 0026 0027 // Local includes 0028 0029 #include "digikam_debug.h" 0030 #include "dwitemdelegate.h" 0031 #include "dwitemdelegate_p.h" 0032 0033 namespace Digikam 0034 { 0035 0036 class Q_DECL_HIDDEN DWItemDelegateEventListener : public QObject 0037 { 0038 Q_OBJECT 0039 0040 public: 0041 0042 explicit DWItemDelegateEventListener(DWItemDelegatePoolPrivate* const poolPrivate, 0043 QObject* const parent = nullptr) 0044 : QObject (parent), 0045 poolPrivate(poolPrivate) 0046 { 0047 } 0048 0049 bool eventFilter(QObject* watched, QEvent* event) override; 0050 0051 private: 0052 0053 DWItemDelegatePoolPrivate* poolPrivate; 0054 }; 0055 0056 // ------------------------------------------------------------------------------------------- 0057 0058 DWItemDelegatePoolPrivate::DWItemDelegatePoolPrivate(DWItemDelegate* const d) 0059 : delegate (d), 0060 eventListener(new DWItemDelegateEventListener(this)), 0061 clearing (false) 0062 { 0063 } 0064 0065 // ------------------------------------------------------------------------------------------- 0066 0067 DWItemDelegatePool::DWItemDelegatePool(DWItemDelegate* const delegate) 0068 : d(new DWItemDelegatePoolPrivate(delegate)) 0069 { 0070 } 0071 0072 DWItemDelegatePool::~DWItemDelegatePool() 0073 { 0074 if (!d->widgetInIndex.isEmpty()) 0075 { 0076 fullClear(); 0077 } 0078 0079 delete d->eventListener; 0080 delete d; 0081 } 0082 0083 QList<QWidget*> DWItemDelegatePool::findWidgets(const QPersistentModelIndex& idx, 0084 const QStyleOptionViewItem& option, 0085 UpdateWidgetsEnum updateWidgets) const 0086 { 0087 QList<QWidget*> result; 0088 0089 if (!idx.isValid()) 0090 { 0091 return result; 0092 } 0093 0094 QModelIndex index; 0095 0096 if (const QAbstractProxyModel* proxyModel = qobject_cast<const QAbstractProxyModel*>(idx.model())) 0097 { 0098 index = proxyModel->mapToSource(idx); 0099 } 0100 else 0101 { 0102 index = idx; 0103 } 0104 0105 if (!index.isValid()) 0106 { 0107 return result; 0108 } 0109 0110 if (d->usedWidgets.contains(index)) 0111 { 0112 result = d->usedWidgets[index]; 0113 } 0114 else 0115 { 0116 result = d->delegate->createItemWidgets(index); 0117 d->usedWidgets[index] = result; 0118 0119 Q_FOREACH (QWidget* const widget, result) 0120 { 0121 d->widgetInIndex[widget] = index; 0122 widget->setParent(d->delegate->d->itemView->viewport()); 0123 widget->installEventFilter(d->eventListener); 0124 widget->setVisible(true); 0125 } 0126 } 0127 0128 if (updateWidgets == UpdateWidgets) 0129 { 0130 Q_FOREACH (QWidget* const widget, result) 0131 { 0132 widget->setVisible(true); 0133 } 0134 0135 d->delegate->updateItemWidgets(result, option, idx); 0136 0137 Q_FOREACH (QWidget* const widget, result) 0138 { 0139 widget->move(widget->x() + option.rect.left(), widget->y() + option.rect.top()); 0140 } 0141 } 0142 0143 return result; 0144 } 0145 0146 QList<QWidget*> DWItemDelegatePool::invalidIndexesWidgets() const 0147 { 0148 QList<QWidget*> result; 0149 0150 Q_FOREACH (QWidget* const widget, d->widgetInIndex.keys()) 0151 { 0152 const QAbstractProxyModel* const proxyModel = qobject_cast<const QAbstractProxyModel*>(d->delegate->d->model); 0153 QModelIndex index; 0154 0155 if (proxyModel) 0156 { 0157 index = proxyModel->mapFromSource(d->widgetInIndex[widget]); 0158 } 0159 else 0160 { 0161 index = d->widgetInIndex[widget]; 0162 } 0163 0164 if (!index.isValid()) 0165 { 0166 result << widget; 0167 } 0168 } 0169 0170 return result; 0171 } 0172 0173 void DWItemDelegatePool::fullClear() 0174 { 0175 d->clearing = true; 0176 qDeleteAll(d->widgetInIndex.keyBegin(), d->widgetInIndex.keyEnd()); 0177 d->clearing = false; 0178 d->usedWidgets.clear(); 0179 d->widgetInIndex.clear(); 0180 } 0181 0182 bool DWItemDelegateEventListener::eventFilter(QObject* watched, QEvent* event) 0183 { 0184 QWidget* const widget = static_cast<QWidget*>(watched); 0185 0186 if ((event->type() == QEvent::Destroy) && !poolPrivate->clearing) 0187 { 0188 // qCDebug(DIGIKAM_GENERAL_LOG) << "Delete widget created by createItemWidgets" << widget; 0189 0190 poolPrivate->widgetInIndex.remove(widget); 0191 } 0192 0193 if (dynamic_cast<QInputEvent*>(event) && !poolPrivate->delegate->blockedEventTypes(widget).contains(event->type())) 0194 { 0195 QWidget* const viewport = poolPrivate->delegate->d->itemView->viewport(); 0196 0197 switch (event->type()) 0198 { 0199 case QEvent::MouseMove: 0200 case QEvent::MouseButtonPress: 0201 case QEvent::MouseButtonRelease: 0202 case QEvent::MouseButtonDblClick: 0203 { 0204 QMouseEvent* const mouseEvent = static_cast<QMouseEvent*>(event); 0205 0206 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0207 0208 QMouseEvent evt(event->type(), viewport->mapFromGlobal(mouseEvent->globalPosition().toPoint()), 0209 mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); 0210 0211 #else 0212 0213 QMouseEvent evt(event->type(), viewport->mapFromGlobal(mouseEvent->globalPos()), 0214 mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); 0215 0216 #endif 0217 0218 QApplication::sendEvent(viewport, &evt); 0219 break; 0220 } 0221 0222 case QEvent::Wheel: 0223 { 0224 QWheelEvent* const wheelEvent = static_cast<QWheelEvent*>(event); 0225 0226 QWheelEvent evt(wheelEvent->position(), wheelEvent->globalPosition(),wheelEvent->pixelDelta(), 0227 wheelEvent->angleDelta(), wheelEvent->buttons(), wheelEvent->modifiers(), 0228 wheelEvent->phase(), wheelEvent->inverted(), wheelEvent->source()); 0229 0230 QApplication::sendEvent(viewport, &evt); 0231 break; 0232 } 0233 0234 case QEvent::TabletMove: 0235 case QEvent::TabletPress: 0236 case QEvent::TabletRelease: 0237 case QEvent::TabletEnterProximity: 0238 case QEvent::TabletLeaveProximity: 0239 { 0240 QTabletEvent* const tabletEvent = static_cast<QTabletEvent*>(event); 0241 0242 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0243 0244 QTabletEvent evt(event->type(), 0245 tabletEvent->pointingDevice(), 0246 QPointF(viewport->mapFromGlobal(tabletEvent->globalPosition().toPoint())), 0247 tabletEvent->globalPosition(), 0248 tabletEvent->pressure(), 0249 tabletEvent->xTilt(), 0250 tabletEvent->yTilt(), 0251 tabletEvent->tangentialPressure(), 0252 tabletEvent->rotation(), 0253 tabletEvent->z(), 0254 tabletEvent->modifiers(), 0255 tabletEvent->button(), 0256 tabletEvent->buttons() 0257 ); 0258 0259 #else 0260 0261 QTabletEvent evt(event->type(), 0262 QPointF(viewport->mapFromGlobal(tabletEvent->globalPos())), 0263 tabletEvent->globalPosF(), 0264 tabletEvent->deviceType(), 0265 tabletEvent->pointerType(), 0266 tabletEvent->pressure(), 0267 tabletEvent->xTilt(), 0268 tabletEvent->yTilt(), 0269 tabletEvent->tangentialPressure(), 0270 tabletEvent->rotation(), 0271 tabletEvent->z(), 0272 tabletEvent->modifiers(), 0273 tabletEvent->uniqueId(), 0274 tabletEvent->button(), 0275 tabletEvent->buttons() 0276 ); 0277 0278 #endif 0279 0280 QApplication::sendEvent(viewport, &evt); 0281 break; 0282 } 0283 0284 default: 0285 { 0286 QApplication::sendEvent(viewport, event); 0287 break; 0288 } 0289 } 0290 } 0291 0292 return QObject::eventFilter(watched, event); 0293 } 0294 0295 } // namespace Digikam 0296 0297 #include "dwitemdelegatepool.moc"