File indexing completed on 2024-04-28 15:32:09

0001 /*
0002     This file is part of the KDE Libraries
0003     SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "kpagewidgetmodel.h"
0009 #include "kpagewidgetmodel_p.h"
0010 
0011 #include "loggingcategory.h"
0012 
0013 #include <QPointer>
0014 #include <QWidget>
0015 
0016 #include <QIcon>
0017 
0018 class KPageWidgetItemPrivate
0019 {
0020 public:
0021     KPageWidgetItemPrivate()
0022         : checkable(false)
0023         , checked(false)
0024         , enabled(true)
0025         , headerVisible(true)
0026     {
0027     }
0028 
0029     ~KPageWidgetItemPrivate()
0030     {
0031         delete widget;
0032         widget = nullptr;
0033     }
0034 
0035     QString name;
0036     QString header;
0037     QIcon icon;
0038     QPointer<QWidget> widget;
0039     bool checkable : 1;
0040     bool checked : 1;
0041     bool enabled : 1;
0042     bool headerVisible : 1;
0043 };
0044 
0045 KPageWidgetItem::KPageWidgetItem(QWidget *widget)
0046     : QObject(nullptr)
0047     , d(new KPageWidgetItemPrivate)
0048 {
0049     d->widget = widget;
0050 
0051     // Hide the widget, otherwise when the widget has this KPageView as
0052     // parent the widget is shown outside the QStackedWidget if the page
0053     // was not selected ( and reparented ) yet.
0054     if (d->widget) {
0055         d->widget->hide();
0056     }
0057 }
0058 
0059 KPageWidgetItem::KPageWidgetItem(QWidget *widget, const QString &name)
0060     : QObject(nullptr)
0061     , d(new KPageWidgetItemPrivate)
0062 {
0063     d->widget = widget;
0064     d->name = name;
0065 
0066     // Hide the widget, otherwise when the widget has this KPageView as
0067     // parent the widget is shown outside the QStackedWidget if the page
0068     // was not selected ( and reparented ) yet.
0069     if (d->widget) {
0070         d->widget->hide();
0071     }
0072 }
0073 
0074 KPageWidgetItem::~KPageWidgetItem() = default;
0075 
0076 void KPageWidgetItem::setEnabled(bool enabled)
0077 {
0078     d->enabled = enabled;
0079     if (d->widget) {
0080         d->widget->setEnabled(enabled);
0081     }
0082     Q_EMIT changed();
0083 }
0084 
0085 bool KPageWidgetItem::isEnabled() const
0086 {
0087     return d->enabled;
0088 }
0089 
0090 bool KPageWidgetItem::isHeaderVisible() const
0091 {
0092     return d->headerVisible;
0093 }
0094 
0095 void KPageWidgetItem::setHeaderVisible(bool visible)
0096 {
0097     d->headerVisible = visible;
0098 
0099     Q_EMIT changed();
0100 }
0101 
0102 QWidget *KPageWidgetItem::widget() const
0103 {
0104     return d->widget;
0105 }
0106 
0107 void KPageWidgetItem::setName(const QString &name)
0108 {
0109     d->name = name;
0110 
0111     Q_EMIT changed();
0112 }
0113 
0114 QString KPageWidgetItem::name() const
0115 {
0116     return d->name;
0117 }
0118 
0119 void KPageWidgetItem::setHeader(const QString &header)
0120 {
0121     const bool autoHeaderInvisibilityTriggered = header.isEmpty() & !header.isNull();
0122     if (autoHeaderInvisibilityTriggered) {
0123         qCWarning(KWidgetsAddonsLog)
0124             << "KPageWidgetItem::setHeader() called with empty non-null string, which is deprecated. Use KPageWidgetItem::setHeaderVisible(false) instead.";
0125     }
0126 
0127     d->header = header;
0128 
0129     Q_EMIT changed();
0130 }
0131 
0132 QString KPageWidgetItem::header() const
0133 {
0134     return d->header;
0135 }
0136 
0137 void KPageWidgetItem::setIcon(const QIcon &icon)
0138 {
0139     d->icon = icon;
0140 
0141     Q_EMIT changed();
0142 }
0143 
0144 QIcon KPageWidgetItem::icon() const
0145 {
0146     return d->icon;
0147 }
0148 
0149 void KPageWidgetItem::setCheckable(bool checkable)
0150 {
0151     d->checkable = checkable;
0152 
0153     Q_EMIT changed();
0154 }
0155 
0156 bool KPageWidgetItem::isCheckable() const
0157 {
0158     return d->checkable;
0159 }
0160 
0161 void KPageWidgetItem::setChecked(bool checked)
0162 {
0163     d->checked = checked;
0164 
0165     Q_EMIT toggled(checked);
0166     Q_EMIT changed();
0167 }
0168 
0169 bool KPageWidgetItem::isChecked() const
0170 {
0171     return d->checked;
0172 }
0173 
0174 PageItem::PageItem(KPageWidgetItem *pageWidgetItem, PageItem *parent)
0175     : mPageWidgetItem(pageWidgetItem)
0176     , mParentItem(parent)
0177 {
0178 }
0179 
0180 PageItem::~PageItem()
0181 {
0182     delete mPageWidgetItem;
0183     mPageWidgetItem = nullptr;
0184 
0185     qDeleteAll(mChildItems);
0186 }
0187 
0188 void PageItem::appendChild(PageItem *item)
0189 {
0190     mChildItems.append(item);
0191 }
0192 
0193 void PageItem::insertChild(int row, PageItem *item)
0194 {
0195     mChildItems.insert(row, item);
0196 }
0197 
0198 void PageItem::removeChild(int row)
0199 {
0200     mChildItems.removeAt(row);
0201 }
0202 
0203 PageItem *PageItem::child(int row)
0204 {
0205     return mChildItems.value(row);
0206 }
0207 
0208 int PageItem::childCount() const
0209 {
0210     return mChildItems.count();
0211 }
0212 
0213 int PageItem::columnCount() const
0214 {
0215     return 1;
0216 }
0217 
0218 PageItem *PageItem::parent()
0219 {
0220     return mParentItem;
0221 }
0222 
0223 int PageItem::row() const
0224 {
0225     if (mParentItem) {
0226         return mParentItem->mChildItems.indexOf(const_cast<PageItem *>(this));
0227     }
0228 
0229     return 0;
0230 }
0231 
0232 KPageWidgetItem *PageItem::pageWidgetItem() const
0233 {
0234     return mPageWidgetItem;
0235 }
0236 
0237 PageItem *PageItem::findChild(const KPageWidgetItem *item)
0238 {
0239     if (mPageWidgetItem == item) {
0240         return this;
0241     }
0242 
0243     for (int i = 0; i < mChildItems.count(); ++i) {
0244         PageItem *pageItem = mChildItems[i]->findChild(item);
0245         if (pageItem) {
0246             return pageItem;
0247         }
0248     }
0249 
0250     return nullptr;
0251 }
0252 
0253 void PageItem::dump(int indent)
0254 {
0255     const QString indentation(indent, QLatin1Char(' '));
0256 
0257     const QString name = (mPageWidgetItem ? mPageWidgetItem->name() : QStringLiteral("root"));
0258     qCDebug(KWidgetsAddonsLog, "%s (%p)", qPrintable(QString(indentation + name)), (void *)this);
0259     for (int i = 0; i < mChildItems.count(); ++i) {
0260         mChildItems[i]->dump(indent + 2);
0261     }
0262 }
0263 
0264 KPageWidgetModel::KPageWidgetModel(QObject *parent)
0265     : KPageModel(*new KPageWidgetModelPrivate, parent)
0266 {
0267 }
0268 
0269 KPageWidgetModel::~KPageWidgetModel()
0270 {
0271 }
0272 
0273 int KPageWidgetModel::columnCount(const QModelIndex &) const
0274 {
0275     return 1;
0276 }
0277 
0278 QVariant KPageWidgetModel::data(const QModelIndex &index, int role) const
0279 {
0280     if (!index.isValid()) {
0281         return QVariant();
0282     }
0283 
0284     PageItem *item = static_cast<PageItem *>(index.internalPointer());
0285 
0286     if (role == Qt::DisplayRole) {
0287         return QVariant(item->pageWidgetItem()->name());
0288     } else if (role == Qt::DecorationRole) {
0289         return QVariant(item->pageWidgetItem()->icon());
0290     } else if (role == HeaderRole) {
0291         return QVariant(item->pageWidgetItem()->header());
0292     } else if (role == HeaderVisibleRole) {
0293         return item->pageWidgetItem()->isHeaderVisible();
0294     } else if (role == WidgetRole) {
0295         return QVariant::fromValue(item->pageWidgetItem()->widget());
0296     } else if (role == Qt::CheckStateRole) {
0297         if (item->pageWidgetItem()->isCheckable()) {
0298             return (item->pageWidgetItem()->isChecked() ? Qt::Checked : Qt::Unchecked);
0299         } else {
0300             return QVariant();
0301         }
0302     } else {
0303         return QVariant();
0304     }
0305 }
0306 
0307 bool KPageWidgetModel::setData(const QModelIndex &index, const QVariant &value, int role)
0308 {
0309     if (!index.isValid()) {
0310         return false;
0311     }
0312 
0313     if (role != Qt::CheckStateRole) {
0314         return false;
0315     }
0316 
0317     PageItem *item = static_cast<PageItem *>(index.internalPointer());
0318     if (!item) {
0319         return false;
0320     }
0321 
0322     if (!item->pageWidgetItem()->isCheckable()) {
0323         return false;
0324     }
0325 
0326     if (value.toInt() == Qt::Checked) {
0327         item->pageWidgetItem()->setChecked(true);
0328     } else {
0329         item->pageWidgetItem()->setChecked(false);
0330     }
0331 
0332     return true;
0333 }
0334 
0335 Qt::ItemFlags KPageWidgetModel::flags(const QModelIndex &index) const
0336 {
0337     if (!index.isValid()) {
0338         return Qt::NoItemFlags;
0339     }
0340 
0341     Qt::ItemFlags flags = Qt::ItemIsSelectable;
0342 
0343     PageItem *item = static_cast<PageItem *>(index.internalPointer());
0344     if (item->pageWidgetItem()->isCheckable()) {
0345         flags |= Qt::ItemIsUserCheckable;
0346     }
0347     if (item->pageWidgetItem()->isEnabled()) {
0348         flags |= Qt::ItemIsEnabled;
0349     }
0350 
0351     return flags;
0352 }
0353 
0354 QModelIndex KPageWidgetModel::index(int row, int column, const QModelIndex &parent) const
0355 {
0356     Q_D(const KPageWidgetModel);
0357 
0358     PageItem *parentItem;
0359 
0360     if (parent.isValid()) {
0361         parentItem = static_cast<PageItem *>(parent.internalPointer());
0362     } else {
0363         parentItem = d->rootItem;
0364     }
0365 
0366     PageItem *childItem = parentItem->child(row);
0367     if (childItem) {
0368         return createIndex(row, column, childItem);
0369     } else {
0370         return QModelIndex();
0371     }
0372 }
0373 
0374 QModelIndex KPageWidgetModel::parent(const QModelIndex &index) const
0375 {
0376     Q_D(const KPageWidgetModel);
0377 
0378     if (!index.isValid()) {
0379         return QModelIndex();
0380     }
0381 
0382     PageItem *item = static_cast<PageItem *>(index.internalPointer());
0383     PageItem *parentItem = item->parent();
0384 
0385     if (parentItem == d->rootItem) {
0386         return QModelIndex();
0387     } else {
0388         return createIndex(parentItem->row(), 0, parentItem);
0389     }
0390 }
0391 
0392 int KPageWidgetModel::rowCount(const QModelIndex &parent) const
0393 {
0394     Q_D(const KPageWidgetModel);
0395 
0396     PageItem *parentItem;
0397 
0398     if (!parent.isValid()) {
0399         parentItem = d->rootItem;
0400     } else {
0401         parentItem = static_cast<PageItem *>(parent.internalPointer());
0402     }
0403 
0404     return parentItem->childCount();
0405 }
0406 
0407 KPageWidgetItem *KPageWidgetModel::addPage(QWidget *widget, const QString &name)
0408 {
0409     KPageWidgetItem *item = new KPageWidgetItem(widget, name);
0410 
0411     addPage(item);
0412 
0413     return item;
0414 }
0415 
0416 void KPageWidgetModel::addPage(KPageWidgetItem *item)
0417 {
0418     Q_EMIT layoutAboutToBeChanged();
0419 
0420     Q_D(KPageWidgetModel);
0421     connect(item, SIGNAL(changed()), this, SLOT(_k_itemChanged()));
0422     connect(item, SIGNAL(toggled(bool)), this, SLOT(_k_itemToggled(bool)));
0423 
0424     // The row to be inserted
0425     int row = d->rootItem->childCount();
0426 
0427     beginInsertRows(QModelIndex(), row, row);
0428 
0429     PageItem *pageItem = new PageItem(item, d->rootItem);
0430     d->rootItem->appendChild(pageItem);
0431 
0432     endInsertRows();
0433 
0434     Q_EMIT layoutChanged();
0435 }
0436 
0437 KPageWidgetItem *KPageWidgetModel::insertPage(KPageWidgetItem *before, QWidget *widget, const QString &name)
0438 {
0439     KPageWidgetItem *item = new KPageWidgetItem(widget, name);
0440 
0441     insertPage(before, item);
0442 
0443     return item;
0444 }
0445 
0446 void KPageWidgetModel::insertPage(KPageWidgetItem *before, KPageWidgetItem *item)
0447 {
0448     Q_D(KPageWidgetModel);
0449 
0450     PageItem *beforePageItem = d->rootItem->findChild(before);
0451     if (!beforePageItem) {
0452         qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
0453         return;
0454     }
0455 
0456     Q_EMIT layoutAboutToBeChanged();
0457 
0458     connect(item, SIGNAL(changed()), this, SLOT(_k_itemChanged()));
0459     connect(item, SIGNAL(toggled(bool)), this, SLOT(_k_itemToggled(bool)));
0460 
0461     PageItem *parent = beforePageItem->parent();
0462     // The row to be inserted
0463     int row = beforePageItem->row();
0464 
0465     QModelIndex index;
0466     if (parent != d->rootItem) {
0467         index = createIndex(parent->row(), 0, parent);
0468     }
0469 
0470     beginInsertRows(index, row, row);
0471 
0472     PageItem *newPageItem = new PageItem(item, parent);
0473     parent->insertChild(row, newPageItem);
0474 
0475     endInsertRows();
0476 
0477     Q_EMIT layoutChanged();
0478 }
0479 
0480 KPageWidgetItem *KPageWidgetModel::addSubPage(KPageWidgetItem *parent, QWidget *widget, const QString &name)
0481 {
0482     KPageWidgetItem *item = new KPageWidgetItem(widget, name);
0483 
0484     addSubPage(parent, item);
0485 
0486     return item;
0487 }
0488 
0489 void KPageWidgetModel::addSubPage(KPageWidgetItem *parent, KPageWidgetItem *item)
0490 {
0491     Q_D(KPageWidgetModel);
0492 
0493     PageItem *parentPageItem = d->rootItem->findChild(parent);
0494     if (!parentPageItem) {
0495         qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
0496         return;
0497     }
0498 
0499     Q_EMIT layoutAboutToBeChanged();
0500 
0501     connect(item, SIGNAL(changed()), this, SLOT(_k_itemChanged()));
0502     connect(item, SIGNAL(toggled(bool)), this, SLOT(_k_itemToggled(bool)));
0503 
0504     // The row to be inserted
0505     int row = parentPageItem->childCount();
0506 
0507     QModelIndex index;
0508     if (parentPageItem != d->rootItem) {
0509         index = createIndex(parentPageItem->row(), 0, parentPageItem);
0510     }
0511 
0512     beginInsertRows(index, row, row);
0513 
0514     PageItem *newPageItem = new PageItem(item, parentPageItem);
0515     parentPageItem->appendChild(newPageItem);
0516 
0517     endInsertRows();
0518 
0519     Q_EMIT layoutChanged();
0520 }
0521 
0522 void KPageWidgetModel::removePage(KPageWidgetItem *item)
0523 {
0524     if (!item) {
0525         return;
0526     }
0527 
0528     Q_D(KPageWidgetModel);
0529 
0530     PageItem *pageItem = d->rootItem->findChild(item);
0531     if (!pageItem) {
0532         qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
0533         return;
0534     }
0535 
0536     Q_EMIT layoutAboutToBeChanged();
0537 
0538     disconnect(item, SIGNAL(changed()), this, SLOT(_k_itemChanged()));
0539     disconnect(item, SIGNAL(toggled(bool)), this, SLOT(_k_itemToggled(bool)));
0540 
0541     PageItem *parentPageItem = pageItem->parent();
0542     int row = parentPageItem->row();
0543 
0544     QModelIndex index;
0545     if (parentPageItem != d->rootItem) {
0546         index = createIndex(row, 0, parentPageItem);
0547     }
0548 
0549     beginRemoveRows(index, pageItem->row(), pageItem->row());
0550 
0551     parentPageItem->removeChild(pageItem->row());
0552     delete pageItem;
0553 
0554     endRemoveRows();
0555 
0556     Q_EMIT layoutChanged();
0557 }
0558 
0559 KPageWidgetItem *KPageWidgetModel::item(const QModelIndex &index) const
0560 {
0561     if (!index.isValid()) {
0562         return nullptr;
0563     }
0564 
0565     PageItem *item = static_cast<PageItem *>(index.internalPointer());
0566     if (!item) {
0567         return nullptr;
0568     }
0569 
0570     return item->pageWidgetItem();
0571 }
0572 
0573 QModelIndex KPageWidgetModel::index(const KPageWidgetItem *item) const
0574 {
0575     Q_D(const KPageWidgetModel);
0576 
0577     if (!item) {
0578         return QModelIndex();
0579     }
0580 
0581     const PageItem *pageItem = d->rootItem->findChild(item);
0582     if (!pageItem) {
0583         return QModelIndex();
0584     }
0585 
0586     return createIndex(pageItem->row(), 0, (void *)pageItem);
0587 }
0588 
0589 #include "moc_kpagewidgetmodel.cpp"