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