1 // SPDX-FileCopyrightText: 2021 Nheko Contributors
2 //
3 // SPDX-License-Identifier: GPL-3.0-or-later
4 
5 #include "DelegateChooser.h"
6 
7 #include "Logging.h"
8 
9 // uses private API, which moved between versions
10 #include <QQmlEngine>
11 #include <QtGlobal>
12 
13 QQmlComponent *
delegate() const14 DelegateChoice::delegate() const
15 {
16     return delegate_;
17 }
18 
19 void
setDelegate(QQmlComponent * delegate)20 DelegateChoice::setDelegate(QQmlComponent *delegate)
21 {
22     if (delegate != delegate_) {
23         delegate_ = delegate;
24         emit delegateChanged();
25         emit changed();
26     }
27 }
28 
29 QVariant
roleValue() const30 DelegateChoice::roleValue() const
31 {
32     return roleValue_;
33 }
34 
35 void
setRoleValue(const QVariant & value)36 DelegateChoice::setRoleValue(const QVariant &value)
37 {
38     if (value != roleValue_) {
39         roleValue_ = value;
40         emit roleValueChanged();
41         emit changed();
42     }
43 }
44 
45 QVariant
roleValue() const46 DelegateChooser::roleValue() const
47 {
48     return roleValue_;
49 }
50 
51 void
setRoleValue(const QVariant & value)52 DelegateChooser::setRoleValue(const QVariant &value)
53 {
54     if (value != roleValue_) {
55         roleValue_ = value;
56         recalcChild();
57         emit roleValueChanged();
58     }
59 }
60 
61 QQmlListProperty<DelegateChoice>
choices()62 DelegateChooser::choices()
63 {
64     return QQmlListProperty<DelegateChoice>(this,
65                                             this,
66                                             &DelegateChooser::appendChoice,
67                                             &DelegateChooser::choiceCount,
68                                             &DelegateChooser::choice,
69                                             &DelegateChooser::clearChoices);
70 }
71 
72 void
appendChoice(QQmlListProperty<DelegateChoice> * p,DelegateChoice * c)73 DelegateChooser::appendChoice(QQmlListProperty<DelegateChoice> *p, DelegateChoice *c)
74 {
75     DelegateChooser *dc = static_cast<DelegateChooser *>(p->object);
76     dc->choices_.append(c);
77 }
78 
79 int
choiceCount(QQmlListProperty<DelegateChoice> * p)80 DelegateChooser::choiceCount(QQmlListProperty<DelegateChoice> *p)
81 {
82     return static_cast<DelegateChooser *>(p->object)->choices_.count();
83 }
84 DelegateChoice *
choice(QQmlListProperty<DelegateChoice> * p,int index)85 DelegateChooser::choice(QQmlListProperty<DelegateChoice> *p, int index)
86 {
87     return static_cast<DelegateChooser *>(p->object)->choices_.at(index);
88 }
89 void
clearChoices(QQmlListProperty<DelegateChoice> * p)90 DelegateChooser::clearChoices(QQmlListProperty<DelegateChoice> *p)
91 {
92     static_cast<DelegateChooser *>(p->object)->choices_.clear();
93 }
94 
95 void
recalcChild()96 DelegateChooser::recalcChild()
97 {
98     for (const auto choice : qAsConst(choices_)) {
99         auto choiceValue = choice->roleValue();
100         if (!roleValue_.isValid() || !choiceValue.isValid() || choiceValue == roleValue_) {
101             if (child_) {
102                 child_->setParentItem(nullptr);
103                 child_ = nullptr;
104             }
105 
106             choice->delegate()->create(incubator, QQmlEngine::contextForObject(this));
107             return;
108         }
109     }
110 }
111 
112 void
componentComplete()113 DelegateChooser::componentComplete()
114 {
115     QQuickItem::componentComplete();
116     recalcChild();
117 }
118 
119 void
statusChanged(QQmlIncubator::Status status)120 DelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status status)
121 {
122     if (status == QQmlIncubator::Ready) {
123         chooser.child_ = dynamic_cast<QQuickItem *>(object());
124         if (chooser.child_ == nullptr) {
125             nhlog::ui()->error("Delegate has to be derived of Item!");
126             return;
127         }
128 
129         chooser.child_->setParentItem(&chooser);
130         QQmlEngine::setObjectOwnership(chooser.child_,
131                                        QQmlEngine::ObjectOwnership::JavaScriptOwnership);
132         emit chooser.childChanged();
133 
134     } else if (status == QQmlIncubator::Error) {
135         for (const auto &e : errors())
136             nhlog::ui()->error("Error instantiating delegate: {}", e.toString().toStdString());
137     }
138 }
139