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"