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

source code of kwidgetsaddons/src/kpagewidgetmodel.cpp