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"