File indexing completed on 2025-01-19 03:53:50

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-11-03
0007  * Description : A dialog base class which can handle multiple pages.
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2007      by Matthias Kretz <kretz at kde dot org>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dconfigdlgmodels_p.h"
0017 
0018 // Qt includes
0019 
0020 #include <QPointer>
0021 #include <QIcon>
0022 
0023 // Local includes
0024 
0025 #include "digikam_debug.h"
0026 
0027 namespace Digikam
0028 {
0029 
0030 DConfigDlgModel::DConfigDlgModel(QObject* const parent)
0031     : QAbstractItemModel(parent),
0032       d_ptr             (nullptr)
0033 {
0034 }
0035 
0036 DConfigDlgModel::DConfigDlgModel(DConfigDlgModelPrivate& dd, QObject* const parent)
0037     : QAbstractItemModel(parent),
0038       d_ptr             (&dd)
0039 {
0040     d_ptr->q_ptr = this;
0041 }
0042 
0043 DConfigDlgModel::~DConfigDlgModel()
0044 {
0045     delete d_ptr;
0046 }
0047 
0048 // ----------------------------------------------------------------------------------
0049 
0050 class Q_DECL_HIDDEN DConfigDlgWdgItem::Private
0051 {
0052 public:
0053 
0054     explicit Private()
0055         : checkable(false),
0056           checked  (false),
0057           enabled  (true)
0058     {
0059     }
0060 
0061     ~Private()
0062     {
0063         delete widget;
0064         widget = nullptr;
0065     }
0066 
0067     QString           name;
0068     QString           header;
0069     QIcon             icon;
0070     QPointer<QWidget> widget;
0071     bool              checkable : 1;
0072     bool              checked   : 1;
0073     bool              enabled   : 1;
0074 };
0075 
0076 DConfigDlgWdgItem::DConfigDlgWdgItem(QWidget* const widget)
0077     : QObject(nullptr),
0078       d      (new Private)
0079 {
0080     d->widget = widget;
0081 
0082     /**
0083      * Hide the widget, otherwise when the widget has this DConfigDlgView as
0084      * parent the widget is shown outside the QStackedWidget if the page
0085      * was not selected ( and reparented ) yet.
0086      */
0087     if (d->widget)
0088     {
0089         d->widget->hide();
0090     }
0091 }
0092 
0093 DConfigDlgWdgItem::DConfigDlgWdgItem(QWidget* const widget, const QString& name)
0094     : QObject(nullptr),
0095       d      (new Private)
0096 {
0097     d->widget = widget;
0098     d->name   = name;
0099 
0100     /**
0101      * Hide the widget, otherwise when the widget has this DConfigDlgView as
0102      * parent the widget is shown outside the QStackedWidget if the page
0103      * was not selected ( and reparented ) yet.
0104      */
0105     if (d->widget)
0106     {
0107         d->widget->hide();
0108     }
0109 }
0110 
0111 DConfigDlgWdgItem::~DConfigDlgWdgItem()
0112 {
0113     delete d;
0114 }
0115 
0116 void DConfigDlgWdgItem::setEnabled(bool enabled)
0117 {
0118     d->enabled = enabled;
0119 
0120     if (d->widget)
0121     {
0122         d->widget->setEnabled(enabled);
0123     }
0124 
0125     Q_EMIT changed();
0126 }
0127 
0128 bool DConfigDlgWdgItem::isEnabled() const
0129 {
0130     return d->enabled;
0131 }
0132 
0133 QWidget* DConfigDlgWdgItem::widget() const
0134 {
0135     return d->widget;
0136 }
0137 
0138 void DConfigDlgWdgItem::setName(const QString& name)
0139 {
0140     d->name = name;
0141 
0142     Q_EMIT changed();
0143 }
0144 
0145 QString DConfigDlgWdgItem::name() const
0146 {
0147     return d->name;
0148 }
0149 
0150 void DConfigDlgWdgItem::setHeader(const QString& header)
0151 {
0152     d->header = header;
0153 
0154     Q_EMIT changed();
0155 }
0156 
0157 QString DConfigDlgWdgItem::header() const
0158 {
0159     return d->header;
0160 }
0161 
0162 void DConfigDlgWdgItem::setIcon(const QIcon& icon)
0163 {
0164     d->icon = icon;
0165 
0166     Q_EMIT changed();
0167 }
0168 
0169 QIcon DConfigDlgWdgItem::icon() const
0170 {
0171     return d->icon;
0172 }
0173 
0174 void DConfigDlgWdgItem::setCheckable(bool checkable)
0175 {
0176     d->checkable = checkable;
0177 
0178     Q_EMIT changed();
0179 }
0180 
0181 bool DConfigDlgWdgItem::isCheckable() const
0182 {
0183     return d->checkable;
0184 }
0185 
0186 void DConfigDlgWdgItem::setChecked(bool checked)
0187 {
0188     d->checked = checked;
0189 
0190     Q_EMIT toggled(checked);
0191     Q_EMIT changed();
0192 }
0193 
0194 bool DConfigDlgWdgItem::isChecked() const
0195 {
0196     return d->checked;
0197 }
0198 
0199 // ---------------------------------------------------------------------------------
0200 
0201 PageItem::PageItem(DConfigDlgWdgItem* const pageWidgetItem, PageItem* const parent)
0202     : mPageWidgetItem(pageWidgetItem),
0203       mParentItem    (parent)
0204 {
0205 }
0206 
0207 PageItem::~PageItem()
0208 {
0209     delete mPageWidgetItem;
0210     mPageWidgetItem = nullptr;
0211 
0212     qDeleteAll(mChildItems);
0213 }
0214 
0215 void PageItem::appendChild(PageItem* item)
0216 {
0217     mChildItems.append(item);
0218 }
0219 
0220 void PageItem::insertChild(int row, PageItem* item)
0221 {
0222     mChildItems.insert(row, item);
0223 }
0224 
0225 void PageItem::removeChild(int row)
0226 {
0227     mChildItems.removeAt(row);
0228 }
0229 
0230 PageItem* PageItem::child(int row)
0231 {
0232     return mChildItems.value(row);
0233 }
0234 
0235 int PageItem::childCount() const
0236 {
0237     return mChildItems.count();
0238 }
0239 
0240 int PageItem::columnCount() const
0241 {
0242     return 1;
0243 }
0244 
0245 PageItem* PageItem::parent()
0246 {
0247     return mParentItem;
0248 }
0249 
0250 int PageItem::row() const
0251 {
0252     if (mParentItem)
0253     {
0254         return mParentItem->mChildItems.indexOf(const_cast<PageItem*>(this));
0255     }
0256 
0257     return 0;
0258 }
0259 
0260 DConfigDlgWdgItem* PageItem::pageWidgetItem() const
0261 {
0262     return mPageWidgetItem;
0263 }
0264 
0265 PageItem* PageItem::findChild(const DConfigDlgWdgItem* item)
0266 {
0267     if (mPageWidgetItem == item)
0268     {
0269         return this;
0270     }
0271 
0272     for (int i = 0 ; i < mChildItems.count() ; ++i)
0273     {
0274         PageItem* const pageItem = mChildItems[ i ]->findChild(item);
0275 
0276         if (pageItem)
0277         {
0278             return pageItem;
0279         }
0280     }
0281 
0282     return nullptr;
0283 }
0284 
0285 void PageItem::dump(int indent)
0286 {
0287     QString prefix;
0288 
0289     for (int i = 0 ; i < indent ; ++i)
0290     {
0291         prefix.append(QLatin1Char(' '));
0292     }
0293 
0294     const QString name = (mPageWidgetItem ? mPageWidgetItem->name() : QLatin1String("root"));
0295     qCDebug(DIGIKAM_GENERAL_LOG) << QString::asprintf("%s (%p)", qPrintable(QString(QString::fromLatin1("%1%2")).arg(prefix, name)),
0296                                                                  (void*)this);
0297 
0298     for (int i = 0 ; i < mChildItems.count() ; ++i)
0299     {
0300         mChildItems[ i ]->dump(indent + 2);
0301     }
0302 }
0303 
0304 // ---------------------------------------------------------------------------------
0305 
0306 DConfigDlgWdgModel::DConfigDlgWdgModel(QObject* const parent)
0307     : DConfigDlgModel(*new DConfigDlgWdgModelPrivate, parent)
0308 {
0309 }
0310 
0311 DConfigDlgWdgModel::~DConfigDlgWdgModel()
0312 {
0313 }
0314 
0315 int DConfigDlgWdgModel::columnCount(const QModelIndex&) const
0316 {
0317     return 1;
0318 }
0319 
0320 QVariant DConfigDlgWdgModel::data(const QModelIndex& index, int role) const
0321 {
0322     if (!index.isValid())
0323     {
0324         return QVariant();
0325     }
0326 
0327     PageItem* const item = static_cast<PageItem *>(index.internalPointer());
0328 
0329     if      (role == Qt::DisplayRole)
0330     {
0331         return QVariant(item->pageWidgetItem()->name());
0332     }
0333     else if (role == Qt::DecorationRole)
0334     {
0335         return QVariant(item->pageWidgetItem()->icon());
0336     }
0337     else if (role == HeaderRole)
0338     {
0339         return QVariant(item->pageWidgetItem()->header());
0340     }
0341     else if (role == WidgetRole)
0342     {
0343         return QVariant::fromValue(item->pageWidgetItem()->widget());
0344     }
0345     else if (role == Qt::CheckStateRole)
0346     {
0347         if (item->pageWidgetItem()->isCheckable())
0348         {
0349             return (item->pageWidgetItem()->isChecked() ? Qt::Checked : Qt::Unchecked);
0350         }
0351         else
0352         {
0353             return QVariant();
0354         }
0355     }
0356     else
0357     {
0358         return QVariant();
0359     }
0360 }
0361 
0362 bool DConfigDlgWdgModel::setData(const QModelIndex& index, const QVariant& value, int role)
0363 {
0364     if (!index.isValid())
0365     {
0366         return false;
0367     }
0368 
0369     if (role != Qt::CheckStateRole)
0370     {
0371         return false;
0372     }
0373 
0374     PageItem* const item = static_cast<PageItem*>(index.internalPointer());
0375 
0376     if (!item)
0377     {
0378         return false;
0379     }
0380 
0381     if (!item->pageWidgetItem()->isCheckable())
0382     {
0383         return false;
0384     }
0385 
0386     if (value.toInt() == Qt::Checked)
0387     {
0388         item->pageWidgetItem()->setChecked(true);
0389     }
0390     else
0391     {
0392         item->pageWidgetItem()->setChecked(false);
0393     }
0394 
0395     return true;
0396 }
0397 
0398 Qt::ItemFlags DConfigDlgWdgModel::flags(const QModelIndex& index) const
0399 {
0400     if (!index.isValid())
0401     {
0402         return Qt::NoItemFlags;
0403     }
0404 
0405     Qt::ItemFlags flags = Qt::ItemIsSelectable;
0406 
0407     PageItem* const item = static_cast<PageItem *>(index.internalPointer());
0408 
0409     if (item->pageWidgetItem()->isCheckable())
0410     {
0411         flags |= Qt::ItemIsUserCheckable;
0412     }
0413 
0414     if (item->pageWidgetItem()->isEnabled())
0415     {
0416         flags |= Qt::ItemIsEnabled;
0417     }
0418 
0419     return flags;
0420 }
0421 
0422 QModelIndex DConfigDlgWdgModel::index(int row, int column, const QModelIndex& parent) const
0423 {
0424     PageItem* parentItem = nullptr;
0425 
0426     if (parent.isValid())
0427     {
0428         parentItem = static_cast<PageItem*>(parent.internalPointer());
0429     }
0430     else
0431     {
0432         parentItem = d_func()->rootItem;
0433     }
0434 
0435     PageItem* const childItem = parentItem->child(row);
0436 
0437     if (childItem)
0438     {
0439         return createIndex(row, column, childItem);
0440     }
0441     else
0442     {
0443         return QModelIndex();
0444     }
0445 }
0446 
0447 QModelIndex DConfigDlgWdgModel::parent(const QModelIndex& index) const
0448 {
0449     if (!index.isValid())
0450     {
0451         return QModelIndex();
0452     }
0453 
0454     PageItem* const item       = static_cast<PageItem *>(index.internalPointer());
0455     PageItem* const parentItem = item->parent();
0456 
0457     if (parentItem == d_func()->rootItem)
0458     {
0459         return QModelIndex();
0460     }
0461     else
0462     {
0463         return createIndex(parentItem->row(), 0, parentItem);
0464     }
0465 }
0466 
0467 int DConfigDlgWdgModel::rowCount(const QModelIndex& parent) const
0468 {
0469     PageItem* parentItem = nullptr;
0470 
0471     if (!parent.isValid())
0472     {
0473         parentItem = d_func()->rootItem;
0474     }
0475     else
0476     {
0477         parentItem = static_cast<PageItem *>(parent.internalPointer());
0478     }
0479 
0480     return parentItem->childCount();
0481 }
0482 
0483 DConfigDlgWdgItem* DConfigDlgWdgModel::addPage(QWidget* widget, const QString& name)
0484 {
0485     DConfigDlgWdgItem* const item = new DConfigDlgWdgItem(widget, name);
0486     addPage(item);
0487 
0488     return item;
0489 }
0490 
0491 void DConfigDlgWdgModel::addPage(DConfigDlgWdgItem* item)
0492 {
0493     Q_EMIT layoutAboutToBeChanged();
0494 
0495     Q_D(DConfigDlgWdgModel);
0496 
0497     connect(item, SIGNAL(changed()),
0498             this, SLOT(_k_itemChanged()));
0499 
0500     connect(item, SIGNAL(toggled(bool)),
0501             this, SLOT(_k_itemToggled(bool)));
0502 
0503     // The row to be inserted
0504 
0505     int row = d->rootItem->childCount();
0506 
0507     beginInsertRows(QModelIndex(), row, row);
0508 
0509     PageItem* const pageItem = new PageItem(item, d->rootItem);
0510     d->rootItem->appendChild(pageItem);
0511 
0512     endInsertRows();
0513 
0514     Q_EMIT layoutChanged();
0515 }
0516 
0517 DConfigDlgWdgItem* DConfigDlgWdgModel::insertPage(DConfigDlgWdgItem* before, QWidget* widget, const QString& name)
0518 {
0519     DConfigDlgWdgItem* const item = new DConfigDlgWdgItem(widget, name);
0520 
0521     insertPage(before, item);
0522 
0523     return item;
0524 }
0525 
0526 void DConfigDlgWdgModel::insertPage(DConfigDlgWdgItem* before, DConfigDlgWdgItem* item)
0527 {
0528     PageItem* const beforePageItem = d_func()->rootItem->findChild(before);
0529 
0530     if (!beforePageItem)
0531     {
0532         qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid DConfigDlgWdgItem passed!";
0533         return;
0534     }
0535 
0536     Q_EMIT layoutAboutToBeChanged();
0537 
0538     connect(item, SIGNAL(changed()),
0539             this, SLOT(_k_itemChanged()));
0540 
0541     connect(item, SIGNAL(toggled(bool)),
0542             this, SLOT(_k_itemToggled(bool)));
0543 
0544     PageItem* const parent = beforePageItem->parent();
0545 
0546     // The row to be inserted
0547 
0548     int row                = beforePageItem->row();
0549 
0550     QModelIndex index;
0551 
0552     if (parent != d_func()->rootItem)
0553     {
0554         index = createIndex(parent->row(), 0, parent);
0555     }
0556 
0557     beginInsertRows(index, row, row);
0558 
0559     PageItem* const newPageItem = new PageItem(item, parent);
0560     parent->insertChild(row, newPageItem);
0561 
0562     endInsertRows();
0563 
0564     Q_EMIT layoutChanged();
0565 }
0566 
0567 DConfigDlgWdgItem* DConfigDlgWdgModel::addSubPage(DConfigDlgWdgItem* parent, QWidget* widget, const QString& name)
0568 {
0569     DConfigDlgWdgItem* const item = new DConfigDlgWdgItem(widget, name);
0570 
0571     addSubPage(parent, item);
0572 
0573     return item;
0574 }
0575 
0576 void DConfigDlgWdgModel::addSubPage(DConfigDlgWdgItem* parent, DConfigDlgWdgItem* item)
0577 {
0578     PageItem* const parentPageItem = d_func()->rootItem->findChild(parent);
0579 
0580     if (!parentPageItem)
0581     {
0582         qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid DConfigDlgWdgItem passed!";
0583         return;
0584     }
0585 
0586     Q_EMIT layoutAboutToBeChanged();
0587 
0588     connect(item, SIGNAL(changed()),
0589             this, SLOT(_k_itemChanged()));
0590 
0591     connect(item, SIGNAL(toggled(bool)),
0592             this, SLOT(_k_itemToggled(bool)));
0593 
0594     // The row to be inserted
0595 
0596     int row = parentPageItem->childCount();
0597 
0598     QModelIndex index;
0599 
0600     if (parentPageItem != d_func()->rootItem)
0601     {
0602         index = createIndex(parentPageItem->row(), 0, parentPageItem);
0603     }
0604 
0605     beginInsertRows(index, row, row);
0606 
0607     PageItem* const newPageItem = new PageItem(item, parentPageItem);
0608     parentPageItem->appendChild(newPageItem);
0609 
0610     endInsertRows();
0611 
0612     Q_EMIT layoutChanged();
0613 }
0614 
0615 void DConfigDlgWdgModel::removePage(DConfigDlgWdgItem* item)
0616 {
0617     if (!item)
0618     {
0619         return;
0620     }
0621 
0622     Q_D(DConfigDlgWdgModel);
0623 
0624     PageItem* const pageItem = d->rootItem->findChild(item);
0625 
0626     if (!pageItem)
0627     {
0628         qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid DConfigDlgWdgItem passed!";
0629         return;
0630     }
0631 
0632     Q_EMIT layoutAboutToBeChanged();
0633 
0634     disconnect(item, SIGNAL(changed()),
0635                this, SLOT(_k_itemChanged()));
0636 
0637     disconnect(item, SIGNAL(toggled(bool)),
0638                this, SLOT(_k_itemToggled(bool)));
0639 
0640     PageItem* const parentPageItem = pageItem->parent();
0641     int row                        = parentPageItem->row();
0642 
0643     QModelIndex index;
0644 
0645     if (parentPageItem != d->rootItem)
0646     {
0647         index = createIndex(row, 0, parentPageItem);
0648     }
0649 
0650     beginRemoveRows(index, pageItem->row(), pageItem->row());
0651 
0652     parentPageItem->removeChild(pageItem->row());
0653     delete pageItem;
0654 
0655     endRemoveRows();
0656 
0657     Q_EMIT layoutChanged();
0658 }
0659 
0660 DConfigDlgWdgItem* DConfigDlgWdgModel::item(const QModelIndex& index) const
0661 {
0662     if (!index.isValid())
0663     {
0664         return nullptr;
0665     }
0666 
0667     PageItem* const item = static_cast<PageItem*>(index.internalPointer());
0668 
0669     if (!item)
0670     {
0671         return nullptr;
0672     }
0673 
0674     return item->pageWidgetItem();
0675 }
0676 
0677 QModelIndex DConfigDlgWdgModel::index(const DConfigDlgWdgItem* item) const
0678 {
0679     if (!item)
0680     {
0681         return QModelIndex();
0682     }
0683 
0684     const PageItem* pageItem = d_func()->rootItem->findChild(item);
0685 
0686     if (!pageItem)
0687     {
0688         return QModelIndex();
0689     }
0690 
0691     return createIndex(pageItem->row(), 0, (void*)pageItem);
0692 }
0693 
0694 } // namespace Digikam
0695 
0696 #include "moc_dconfigdlgmodels.cpp"