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: |
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 ; |
37 | QIcon icon; |
38 | QPointer<QWidget> widget; |
39 | bool checkable : 1; |
40 | bool checked : 1; |
41 | bool enabled : 1; |
42 | bool : 1; |
43 | }; |
44 | |
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 | |
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 | |
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 | |
85 | bool KPageWidgetItem::isEnabled() const |
86 | { |
87 | return d->enabled; |
88 | } |
89 | |
90 | bool KPageWidgetItem::() const |
91 | { |
92 | return d->headerVisible; |
93 | } |
94 | |
95 | void KPageWidgetItem::(bool visible) |
96 | { |
97 | d->headerVisible = visible; |
98 | |
99 | Q_EMIT changed(); |
100 | } |
101 | |
102 | QWidget *KPageWidgetItem::widget() const |
103 | { |
104 | return d->widget; |
105 | } |
106 | |
107 | void KPageWidgetItem::setName(const QString &name) |
108 | { |
109 | d->name = name; |
110 | |
111 | Q_EMIT changed(); |
112 | } |
113 | |
114 | QString KPageWidgetItem::name() const |
115 | { |
116 | return d->name; |
117 | } |
118 | |
119 | void KPageWidgetItem::(const QString &) |
120 | { |
121 | d->header = header; |
122 | |
123 | Q_EMIT changed(); |
124 | } |
125 | |
126 | QString KPageWidgetItem::() const |
127 | { |
128 | return d->header; |
129 | } |
130 | |
131 | void KPageWidgetItem::setIcon(const QIcon &icon) |
132 | { |
133 | d->icon = icon; |
134 | |
135 | Q_EMIT changed(); |
136 | } |
137 | |
138 | QIcon KPageWidgetItem::icon() const |
139 | { |
140 | return d->icon; |
141 | } |
142 | |
143 | void KPageWidgetItem::setCheckable(bool checkable) |
144 | { |
145 | d->checkable = checkable; |
146 | |
147 | Q_EMIT changed(); |
148 | } |
149 | |
150 | bool KPageWidgetItem::isCheckable() const |
151 | { |
152 | return d->checkable; |
153 | } |
154 | |
155 | void KPageWidgetItem::setChecked(bool checked) |
156 | { |
157 | d->checked = checked; |
158 | |
159 | Q_EMIT toggled(checked); |
160 | Q_EMIT changed(); |
161 | } |
162 | |
163 | bool KPageWidgetItem::isChecked() const |
164 | { |
165 | return d->checked; |
166 | } |
167 | |
168 | PageItem::PageItem(KPageWidgetItem *pageWidgetItem, PageItem *parent) |
169 | : mPageWidgetItem(pageWidgetItem) |
170 | , mParentItem(parent) |
171 | { |
172 | } |
173 | |
174 | PageItem::~PageItem() |
175 | { |
176 | delete mPageWidgetItem; |
177 | mPageWidgetItem = nullptr; |
178 | |
179 | qDeleteAll(c: mChildItems); |
180 | } |
181 | |
182 | void PageItem::appendChild(PageItem *item) |
183 | { |
184 | mChildItems.append(t: item); |
185 | } |
186 | |
187 | void PageItem::insertChild(int row, PageItem *item) |
188 | { |
189 | mChildItems.insert(i: row, t: item); |
190 | } |
191 | |
192 | void PageItem::removeChild(int row) |
193 | { |
194 | mChildItems.removeAt(i: row); |
195 | } |
196 | |
197 | PageItem *PageItem::child(int row) |
198 | { |
199 | return mChildItems.value(i: row); |
200 | } |
201 | |
202 | int PageItem::childCount() const |
203 | { |
204 | return mChildItems.count(); |
205 | } |
206 | |
207 | int PageItem::columnCount() const |
208 | { |
209 | return 1; |
210 | } |
211 | |
212 | PageItem *PageItem::parent() |
213 | { |
214 | return mParentItem; |
215 | } |
216 | |
217 | int PageItem::row() const |
218 | { |
219 | if (mParentItem) { |
220 | return mParentItem->mChildItems.indexOf(t: const_cast<PageItem *>(this)); |
221 | } |
222 | |
223 | return 0; |
224 | } |
225 | |
226 | KPageWidgetItem *PageItem::pageWidgetItem() const |
227 | { |
228 | return mPageWidgetItem; |
229 | } |
230 | |
231 | PageItem *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 | |
247 | void 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 | |
258 | KPageWidgetModel::KPageWidgetModel(QObject *parent) |
259 | : KPageModel(*new KPageWidgetModelPrivate, parent) |
260 | { |
261 | } |
262 | |
263 | KPageWidgetModel::~KPageWidgetModel() |
264 | { |
265 | } |
266 | |
267 | int KPageWidgetModel::columnCount(const QModelIndex &) const |
268 | { |
269 | return 1; |
270 | } |
271 | |
272 | QVariant 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 | |
301 | bool 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 | |
329 | Qt::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 | |
348 | QModelIndex 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 | |
368 | QModelIndex 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 | |
386 | int 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 | |
401 | KPageWidgetItem *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 | |
410 | void 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 | |
431 | KPageWidgetItem *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 | |
440 | void 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 | |
474 | KPageWidgetItem *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 | |
483 | void 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 | |
516 | void 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 | |
553 | KPageWidgetItem *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 | |
567 | QModelIndex 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 | |