File indexing completed on 2025-01-19 03:59:42

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 "dwitemdelegate_p.h"
0018 
0019 // Qt includes
0020 
0021 #include <QSize>
0022 #include <QStyle>
0023 #include <QEvent>
0024 #include <QTimer>
0025 #include <QTreeView>
0026 #include <QApplication>
0027 #include <QStyleOption>
0028 #include <QAbstractItemView>
0029 
0030 // Local includes
0031 
0032 #include "dwitemdelegatepool.h"
0033 
0034 namespace Digikam
0035 {
0036 
0037 DWItemDelegatePrivate::DWItemDelegatePrivate(DWItemDelegate* const q, QObject* const parent)
0038     : QObject       (parent),
0039       itemView      (nullptr),
0040       widgetPool    (new DWItemDelegatePool(q)),
0041       model         (nullptr),
0042       selectionModel(nullptr),
0043       q             (q)
0044 {
0045 }
0046 
0047 DWItemDelegatePrivate::~DWItemDelegatePrivate()
0048 {
0049     delete widgetPool;
0050 }
0051 
0052 void DWItemDelegatePrivate::slotDWRowsInserted(const QModelIndex& parent, int start, int end)
0053 {
0054     Q_UNUSED(end);
0055 
0056     // We need to update the rows behind the inserted row as well because the widgets need to be
0057     // moved to their new position
0058 
0059     updateRowRange(parent, start, model->rowCount(parent), false);
0060 }
0061 
0062 void DWItemDelegatePrivate::slotDWRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
0063 {
0064     updateRowRange(parent, start, end, true);
0065 }
0066 
0067 void DWItemDelegatePrivate::slotDWRowsRemoved(const QModelIndex& parent, int start, int end)
0068 {
0069     Q_UNUSED(end);
0070 
0071     // We need to update the rows that come behind the deleted rows because the widgets need to be
0072     // moved to the new position
0073 
0074     updateRowRange(parent, start, model->rowCount(parent), false);
0075 }
0076 
0077 void DWItemDelegatePrivate::slotDWDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
0078 {
0079     for (int i = topLeft.row() ; i <= bottomRight.row() ; ++i)
0080     {
0081         for (int j = topLeft.column() ; j <= bottomRight.column() ; ++j)
0082         {
0083             const QModelIndex index = model->index(i, j, topLeft.parent());
0084             widgetPool->findWidgets(index, optionView(index));
0085         }
0086     }
0087 }
0088 
0089 void DWItemDelegatePrivate::slotDWLayoutChanged()
0090 {
0091     Q_FOREACH (QWidget* const widget, widgetPool->invalidIndexesWidgets())
0092     {
0093         widget->setVisible(false);
0094     }
0095 
0096     QTimer::singleShot(0, this, SLOT(initializeModel()));
0097 }
0098 
0099 void DWItemDelegatePrivate::slotDWModelReset()
0100 {
0101     widgetPool->fullClear();
0102     QTimer::singleShot(0, this, SLOT(initializeModel()));
0103 }
0104 
0105 void DWItemDelegatePrivate::slotDWSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
0106 {
0107     Q_FOREACH (const QModelIndex& index, selected.indexes())
0108     {
0109         widgetPool->findWidgets(index, optionView(index));
0110     }
0111 
0112     Q_FOREACH (const QModelIndex& index, deselected.indexes())
0113     {
0114         widgetPool->findWidgets(index, optionView(index));
0115     }
0116 }
0117 
0118 void DWItemDelegatePrivate::updateRowRange(const QModelIndex& parent, int start, int end, bool isRemoving)
0119 {
0120     int i = start;
0121 
0122     while (i <= end)
0123     {
0124         for (int j = 0 ; j < model->columnCount(parent) ; ++j)
0125         {
0126             const QModelIndex index    = model->index(i, j, parent);
0127             QList<QWidget*> widgetList = widgetPool->findWidgets(index, optionView(index), isRemoving ? DWItemDelegatePool::NotUpdateWidgets
0128                                                                                                       : DWItemDelegatePool::UpdateWidgets);
0129             if (isRemoving)
0130             {
0131                 Q_FOREACH (QWidget* const widget, widgetList)
0132                 {
0133                     const QModelIndex idx = widgetPool->d->widgetInIndex[widget];
0134                     widgetPool->d->usedWidgets.remove(idx);
0135                     widgetPool->d->widgetInIndex.remove(widget);
0136                     delete widget;
0137                 }
0138             }
0139         }
0140 
0141         i++;
0142     }
0143 }
0144 
0145 inline QStyleOptionViewItem DWItemDelegatePrivate::optionView(const QModelIndex& index)
0146 {
0147     QStyleOptionViewItem optionView;
0148     optionView.initFrom(itemView->viewport());
0149     optionView.rect           = itemView->visualRect(index);
0150     optionView.decorationSize = itemView->iconSize();
0151 
0152     return optionView;
0153 }
0154 
0155 void DWItemDelegatePrivate::initializeModel(const QModelIndex& parent)
0156 {
0157     if (!model)
0158     {
0159         return;
0160     }
0161 
0162     for (int i = 0 ; i < model->rowCount(parent) ; ++i)
0163     {
0164         for (int j = 0 ; j < model->columnCount(parent) ; ++j)
0165         {
0166             const QModelIndex index = model->index(i, j, parent);
0167 
0168             if (index.isValid())
0169             {
0170                 widgetPool->findWidgets(index, optionView(index));
0171             }
0172         }
0173 
0174         // Check if we need to go recursively through the children of parent (if any) to initialize
0175         // all possible indexes that are shown.
0176 
0177         const QModelIndex index = model->index(i, 0, parent);
0178 
0179         if (index.isValid() && model->hasChildren(index))
0180         {
0181             initializeModel(index);
0182         }
0183     }
0184 }
0185 
0186 bool DWItemDelegatePrivate::eventFilter(QObject* watched, QEvent* event)
0187 {
0188     Q_ASSERT(itemView);
0189 
0190     if (model != itemView->model())
0191     {
0192         if (model)
0193         {
0194             disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
0195                        q, SLOT(slotDWRowsInserted(QModelIndex,int,int)));
0196 
0197             disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
0198                        q, SLOT(slotDWRowsAboutToBeRemoved(QModelIndex,int,int)));
0199 
0200             disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
0201                        q, SLOT(slotDWRowsRemoved(QModelIndex,int,int)));
0202 
0203             disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0204                        q, SLOT(slotDWDataChanged(QModelIndex,QModelIndex)));
0205 
0206             disconnect(model, SIGNAL(layoutChanged()),
0207                        q, SLOT(slotDWLayoutChanged()));
0208 
0209             disconnect(model, SIGNAL(modelReset()),
0210                        q, SLOT(slotDWModelReset()));
0211         }
0212 
0213         model = itemView->model();
0214 
0215         connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
0216                 q, SLOT(slotDWRowsInserted(QModelIndex,int,int)));
0217 
0218         connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
0219                 q, SLOT(slotDWRowsAboutToBeRemoved(QModelIndex,int,int)));
0220 
0221         connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
0222                 q, SLOT(slotDWRowsRemoved(QModelIndex,int,int)));
0223 
0224         connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0225                 q, SLOT(slotDWDataChanged(QModelIndex,QModelIndex)));
0226 
0227         connect(model, SIGNAL(layoutChanged()),
0228                 q, SLOT(slotDWLayoutChanged()));
0229 
0230         connect(model, SIGNAL(modelReset()),
0231                 q, SLOT(slotDWModelReset()));
0232 
0233         QTimer::singleShot(0, this, SLOT(initializeModel()));
0234     }
0235 
0236     if (selectionModel != itemView->selectionModel())
0237     {
0238         if (selectionModel)
0239         {
0240             disconnect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0241                        q, SLOT(slotDWSelectionChanged(QItemSelection,QItemSelection)));
0242         }
0243 
0244         selectionModel = itemView->selectionModel();
0245 
0246         connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0247                 q, SLOT(slotDWSelectionChanged(QItemSelection,QItemSelection)));
0248 
0249         QTimer::singleShot(0, this, SLOT(initializeModel()));
0250     }
0251 
0252     switch (event->type())
0253     {
0254         case QEvent::Polish:
0255         case QEvent::Resize:
0256         {
0257             if (!qobject_cast<QAbstractItemView*>(watched))
0258             {
0259                 QTimer::singleShot(0, this, SLOT(initializeModel()));
0260             }
0261 
0262             break;
0263         }
0264 
0265         case QEvent::FocusIn:
0266         case QEvent::FocusOut:
0267         {
0268             if (qobject_cast<QAbstractItemView*>(watched))
0269             {
0270                 Q_FOREACH (const QModelIndex& index, selectionModel->selectedIndexes())
0271                 {
0272                     if (index.isValid())
0273                     {
0274                         widgetPool->findWidgets(index, optionView(index));
0275                     }
0276                 }
0277             }
0278 
0279             break;
0280         }
0281 
0282         default:
0283         {
0284             break;
0285         }
0286     }
0287 
0288     return QObject::eventFilter(watched, event);
0289 }
0290 
0291 } // namespace Digikam
0292 
0293 #include "moc_dwitemdelegate_p.cpp"