1/*
2 This file is part of the KDE Libraries
3 SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kpagewidgetmodel.h"
9#include "kpagewidgetmodel_p.h"
10
11#include "loggingcategory.h"
12
13#include <QPointer>
14#include <QWidget>
15
16#include <QIcon>
17
18class KPageWidgetItemPrivate
19{
20public:
21 KPageWidgetItemPrivate()
22 : checkable(false)
23 , checked(false)
24 , enabled(true)
25 , headerVisible(true)
26 {
27 }
28
29 ~KPageWidgetItemPrivate()
30 {
31 delete widget;
32 widget = nullptr;
33 }
34
35 QString name;
36 QString header;
37 QIcon icon;
38 QPointer<QWidget> widget;
39 bool checkable : 1;
40 bool checked : 1;
41 bool enabled : 1;
42 bool headerVisible : 1;
43};
44
45KPageWidgetItem::KPageWidgetItem(QWidget *widget)
46 : QObject(nullptr)
47 , d(new KPageWidgetItemPrivate)
48{
49 d->widget = widget;
50
51 // Hide the widget, otherwise when the widget has this KPageView as
52 // parent the widget is shown outside the QStackedWidget if the page
53 // was not selected ( and reparented ) yet.
54 if (d->widget) {
55 d->widget->hide();
56 }
57}
58
59KPageWidgetItem::KPageWidgetItem(QWidget *widget, const QString &name)
60 : QObject(nullptr)
61 , d(new KPageWidgetItemPrivate)
62{
63 d->widget = widget;
64 d->name = name;
65
66 // Hide the widget, otherwise when the widget has this KPageView as
67 // parent the widget is shown outside the QStackedWidget if the page
68 // was not selected ( and reparented ) yet.
69 if (d->widget) {
70 d->widget->hide();
71 }
72}
73
74KPageWidgetItem::~KPageWidgetItem() = default;
75
76void KPageWidgetItem::setEnabled(bool enabled)
77{
78 d->enabled = enabled;
79 if (d->widget) {
80 d->widget->setEnabled(enabled);
81 }
82 Q_EMIT changed();
83}
84
85bool KPageWidgetItem::isEnabled() const
86{
87 return d->enabled;
88}
89
90bool KPageWidgetItem::isHeaderVisible() const
91{
92 return d->headerVisible;
93}
94
95void KPageWidgetItem::setHeaderVisible(bool visible)
96{
97 d->headerVisible = visible;
98
99 Q_EMIT changed();
100}
101
102QWidget *KPageWidgetItem::widget() const
103{
104 return d->widget;
105}
106
107void KPageWidgetItem::setName(const QString &name)
108{
109 d->name = name;
110
111 Q_EMIT changed();
112}
113
114QString KPageWidgetItem::name() const
115{
116 return d->name;
117}
118
119void KPageWidgetItem::setHeader(const QString &header)
120{
121 d->header = header;
122
123 Q_EMIT changed();
124}
125
126QString KPageWidgetItem::header() const
127{
128 return d->header;
129}
130
131void KPageWidgetItem::setIcon(const QIcon &icon)
132{
133 d->icon = icon;
134
135 Q_EMIT changed();
136}
137
138QIcon KPageWidgetItem::icon() const
139{
140 return d->icon;
141}
142
143void KPageWidgetItem::setCheckable(bool checkable)
144{
145 d->checkable = checkable;
146
147 Q_EMIT changed();
148}
149
150bool KPageWidgetItem::isCheckable() const
151{
152 return d->checkable;
153}
154
155void KPageWidgetItem::setChecked(bool checked)
156{
157 d->checked = checked;
158
159 Q_EMIT toggled(checked);
160 Q_EMIT changed();
161}
162
163bool KPageWidgetItem::isChecked() const
164{
165 return d->checked;
166}
167
168PageItem::PageItem(KPageWidgetItem *pageWidgetItem, PageItem *parent)
169 : mPageWidgetItem(pageWidgetItem)
170 , mParentItem(parent)
171{
172}
173
174PageItem::~PageItem()
175{
176 delete mPageWidgetItem;
177 mPageWidgetItem = nullptr;
178
179 qDeleteAll(c: mChildItems);
180}
181
182void PageItem::appendChild(PageItem *item)
183{
184 mChildItems.append(t: item);
185}
186
187void PageItem::insertChild(int row, PageItem *item)
188{
189 mChildItems.insert(i: row, t: item);
190}
191
192void PageItem::removeChild(int row)
193{
194 mChildItems.removeAt(i: row);
195}
196
197PageItem *PageItem::child(int row)
198{
199 return mChildItems.value(i: row);
200}
201
202int PageItem::childCount() const
203{
204 return mChildItems.count();
205}
206
207int PageItem::columnCount() const
208{
209 return 1;
210}
211
212PageItem *PageItem::parent()
213{
214 return mParentItem;
215}
216
217int PageItem::row() const
218{
219 if (mParentItem) {
220 return mParentItem->mChildItems.indexOf(t: const_cast<PageItem *>(this));
221 }
222
223 return 0;
224}
225
226KPageWidgetItem *PageItem::pageWidgetItem() const
227{
228 return mPageWidgetItem;
229}
230
231PageItem *PageItem::findChild(const KPageWidgetItem *item)
232{
233 if (mPageWidgetItem == item) {
234 return this;
235 }
236
237 for (int i = 0; i < mChildItems.count(); ++i) {
238 PageItem *pageItem = mChildItems[i]->findChild(item);
239 if (pageItem) {
240 return pageItem;
241 }
242 }
243
244 return nullptr;
245}
246
247void PageItem::dump(int indent)
248{
249 const QString indentation(indent, QLatin1Char(' '));
250
251 const QString name = (mPageWidgetItem ? mPageWidgetItem->name() : QStringLiteral("root"));
252 qCDebug(KWidgetsAddonsLog, "%s (%p)", qPrintable(QString(indentation + name)), (void *)this);
253 for (int i = 0; i < mChildItems.count(); ++i) {
254 mChildItems[i]->dump(indent: indent + 2);
255 }
256}
257
258KPageWidgetModel::KPageWidgetModel(QObject *parent)
259 : KPageModel(*new KPageWidgetModelPrivate, parent)
260{
261}
262
263KPageWidgetModel::~KPageWidgetModel()
264{
265}
266
267int KPageWidgetModel::columnCount(const QModelIndex &) const
268{
269 return 1;
270}
271
272QVariant KPageWidgetModel::data(const QModelIndex &index, int role) const
273{
274 if (!index.isValid()) {
275 return QVariant();
276 }
277
278 PageItem *item = static_cast<PageItem *>(index.internalPointer());
279
280 if (role == Qt::DisplayRole) {
281 return QVariant(item->pageWidgetItem()->name());
282 } else if (role == Qt::DecorationRole) {
283 return QVariant(item->pageWidgetItem()->icon());
284 } else if (role == HeaderRole) {
285 return QVariant(item->pageWidgetItem()->header());
286 } else if (role == HeaderVisibleRole) {
287 return item->pageWidgetItem()->isHeaderVisible();
288 } else if (role == WidgetRole) {
289 return QVariant::fromValue(value: item->pageWidgetItem()->widget());
290 } else if (role == Qt::CheckStateRole) {
291 if (item->pageWidgetItem()->isCheckable()) {
292 return (item->pageWidgetItem()->isChecked() ? Qt::Checked : Qt::Unchecked);
293 } else {
294 return QVariant();
295 }
296 } else {
297 return QVariant();
298 }
299}
300
301bool KPageWidgetModel::setData(const QModelIndex &index, const QVariant &value, int role)
302{
303 if (!index.isValid()) {
304 return false;
305 }
306
307 if (role != Qt::CheckStateRole) {
308 return false;
309 }
310
311 PageItem *item = static_cast<PageItem *>(index.internalPointer());
312 if (!item) {
313 return false;
314 }
315
316 if (!item->pageWidgetItem()->isCheckable()) {
317 return false;
318 }
319
320 if (value.toInt() == Qt::Checked) {
321 item->pageWidgetItem()->setChecked(true);
322 } else {
323 item->pageWidgetItem()->setChecked(false);
324 }
325
326 return true;
327}
328
329Qt::ItemFlags KPageWidgetModel::flags(const QModelIndex &index) const
330{
331 if (!index.isValid()) {
332 return Qt::NoItemFlags;
333 }
334
335 Qt::ItemFlags flags = Qt::ItemIsSelectable;
336
337 PageItem *item = static_cast<PageItem *>(index.internalPointer());
338 if (item->pageWidgetItem()->isCheckable()) {
339 flags |= Qt::ItemIsUserCheckable;
340 }
341 if (item->pageWidgetItem()->isEnabled()) {
342 flags |= Qt::ItemIsEnabled;
343 }
344
345 return flags;
346}
347
348QModelIndex KPageWidgetModel::index(int row, int column, const QModelIndex &parent) const
349{
350 Q_D(const KPageWidgetModel);
351
352 PageItem *parentItem;
353
354 if (parent.isValid()) {
355 parentItem = static_cast<PageItem *>(parent.internalPointer());
356 } else {
357 parentItem = d->rootItem;
358 }
359
360 PageItem *childItem = parentItem->child(row);
361 if (childItem) {
362 return createIndex(arow: row, acolumn: column, adata: childItem);
363 } else {
364 return QModelIndex();
365 }
366}
367
368QModelIndex KPageWidgetModel::parent(const QModelIndex &index) const
369{
370 Q_D(const KPageWidgetModel);
371
372 if (!index.isValid()) {
373 return QModelIndex();
374 }
375
376 PageItem *item = static_cast<PageItem *>(index.internalPointer());
377 PageItem *parentItem = item->parent();
378
379 if (parentItem == d->rootItem) {
380 return QModelIndex();
381 } else {
382 return createIndex(arow: parentItem->row(), acolumn: 0, adata: parentItem);
383 }
384}
385
386int KPageWidgetModel::rowCount(const QModelIndex &parent) const
387{
388 Q_D(const KPageWidgetModel);
389
390 PageItem *parentItem;
391
392 if (!parent.isValid()) {
393 parentItem = d->rootItem;
394 } else {
395 parentItem = static_cast<PageItem *>(parent.internalPointer());
396 }
397
398 return parentItem->childCount();
399}
400
401KPageWidgetItem *KPageWidgetModel::addPage(QWidget *widget, const QString &name)
402{
403 KPageWidgetItem *item = new KPageWidgetItem(widget, name);
404
405 addPage(item);
406
407 return item;
408}
409
410void KPageWidgetModel::addPage(KPageWidgetItem *item)
411{
412 Q_EMIT layoutAboutToBeChanged();
413
414 Q_D(KPageWidgetModel);
415 connect(sender: item, SIGNAL(changed()), receiver: this, SLOT(_k_itemChanged()));
416 connect(sender: item, SIGNAL(toggled(bool)), receiver: this, SLOT(_k_itemToggled(bool)));
417
418 // The row to be inserted
419 int row = d->rootItem->childCount();
420
421 beginInsertRows(parent: QModelIndex(), first: row, last: row);
422
423 PageItem *pageItem = new PageItem(item, d->rootItem);
424 d->rootItem->appendChild(item: pageItem);
425
426 endInsertRows();
427
428 Q_EMIT layoutChanged();
429}
430
431KPageWidgetItem *KPageWidgetModel::insertPage(KPageWidgetItem *before, QWidget *widget, const QString &name)
432{
433 KPageWidgetItem *item = new KPageWidgetItem(widget, name);
434
435 insertPage(before, item);
436
437 return item;
438}
439
440void KPageWidgetModel::insertPage(KPageWidgetItem *before, KPageWidgetItem *item)
441{
442 Q_D(KPageWidgetModel);
443
444 PageItem *beforePageItem = d->rootItem->findChild(item: before);
445 if (!beforePageItem) {
446 qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
447 return;
448 }
449
450 Q_EMIT layoutAboutToBeChanged();
451
452 connect(sender: item, SIGNAL(changed()), receiver: this, SLOT(_k_itemChanged()));
453 connect(sender: item, SIGNAL(toggled(bool)), receiver: this, SLOT(_k_itemToggled(bool)));
454
455 PageItem *parent = beforePageItem->parent();
456 // The row to be inserted
457 int row = beforePageItem->row();
458
459 QModelIndex index;
460 if (parent != d->rootItem) {
461 index = createIndex(arow: parent->row(), acolumn: 0, adata: parent);
462 }
463
464 beginInsertRows(parent: index, first: row, last: row);
465
466 PageItem *newPageItem = new PageItem(item, parent);
467 parent->insertChild(row, item: newPageItem);
468
469 endInsertRows();
470
471 Q_EMIT layoutChanged();
472}
473
474KPageWidgetItem *KPageWidgetModel::addSubPage(KPageWidgetItem *parent, QWidget *widget, const QString &name)
475{
476 KPageWidgetItem *item = new KPageWidgetItem(widget, name);
477
478 addSubPage(parent, item);
479
480 return item;
481}
482
483void KPageWidgetModel::addSubPage(KPageWidgetItem *parent, KPageWidgetItem *item)
484{
485 Q_D(KPageWidgetModel);
486
487 PageItem *parentPageItem = d->rootItem->findChild(item: parent);
488 if (!parentPageItem) {
489 qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
490 return;
491 }
492
493 Q_EMIT layoutAboutToBeChanged();
494
495 connect(sender: item, SIGNAL(changed()), receiver: this, SLOT(_k_itemChanged()));
496 connect(sender: item, SIGNAL(toggled(bool)), receiver: this, SLOT(_k_itemToggled(bool)));
497
498 // The row to be inserted
499 int row = parentPageItem->childCount();
500
501 QModelIndex index;
502 if (parentPageItem != d->rootItem) {
503 index = createIndex(arow: parentPageItem->row(), acolumn: 0, adata: parentPageItem);
504 }
505
506 beginInsertRows(parent: index, first: row, last: row);
507
508 PageItem *newPageItem = new PageItem(item, parentPageItem);
509 parentPageItem->appendChild(item: newPageItem);
510
511 endInsertRows();
512
513 Q_EMIT layoutChanged();
514}
515
516void KPageWidgetModel::removePage(KPageWidgetItem *item)
517{
518 if (!item) {
519 return;
520 }
521
522 Q_D(KPageWidgetModel);
523
524 PageItem *pageItem = d->rootItem->findChild(item);
525 if (!pageItem) {
526 qCDebug(KWidgetsAddonsLog, "Invalid KPageWidgetItem passed!");
527 return;
528 }
529
530 Q_EMIT layoutAboutToBeChanged();
531
532 disconnect(sender: item, SIGNAL(changed()), receiver: this, SLOT(_k_itemChanged()));
533 disconnect(sender: item, SIGNAL(toggled(bool)), receiver: this, SLOT(_k_itemToggled(bool)));
534
535 PageItem *parentPageItem = pageItem->parent();
536 int row = parentPageItem->row();
537
538 QModelIndex index;
539 if (parentPageItem != d->rootItem) {
540 index = createIndex(arow: row, acolumn: 0, adata: parentPageItem);
541 }
542
543 beginRemoveRows(parent: index, first: pageItem->row(), last: pageItem->row());
544
545 parentPageItem->removeChild(row: pageItem->row());
546 delete pageItem;
547
548 endRemoveRows();
549
550 Q_EMIT layoutChanged();
551}
552
553KPageWidgetItem *KPageWidgetModel::item(const QModelIndex &index) const
554{
555 if (!index.isValid()) {
556 return nullptr;
557 }
558
559 PageItem *item = static_cast<PageItem *>(index.internalPointer());
560 if (!item) {
561 return nullptr;
562 }
563
564 return item->pageWidgetItem();
565}
566
567QModelIndex KPageWidgetModel::index(const KPageWidgetItem *item) const
568{
569 Q_D(const KPageWidgetModel);
570
571 if (!item) {
572 return QModelIndex();
573 }
574
575 const PageItem *pageItem = d->rootItem->findChild(item);
576 if (!pageItem) {
577 return QModelIndex();
578 }
579
580 return createIndex(arow: pageItem->row(), acolumn: 0, adata: (void *)pageItem);
581}
582
583#include "moc_kpagewidgetmodel.cpp"
584

source code of kwidgetsaddons/src/kpagewidgetmodel.cpp