1/*
2 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "toolbarlayoutdelegate.h"
8
9#include "loggingcategory.h"
10#include "toolbarlayout.h"
11
12ToolBarDelegateIncubator::ToolBarDelegateIncubator(QQmlComponent *component, QQmlContext *context)
13 : QQmlIncubator(QQmlIncubator::Asynchronous)
14 , m_component(component)
15 , m_context(context)
16{
17}
18
19void ToolBarDelegateIncubator::setStateCallback(std::function<void(QQuickItem *)> callback)
20{
21 m_stateCallback = callback;
22}
23
24void ToolBarDelegateIncubator::setCompletedCallback(std::function<void(ToolBarDelegateIncubator *)> callback)
25{
26 m_completedCallback = callback;
27}
28
29void ToolBarDelegateIncubator::create()
30{
31 m_component->create(*this, context: m_context);
32}
33
34bool ToolBarDelegateIncubator::isFinished()
35{
36 return m_finished;
37}
38
39void ToolBarDelegateIncubator::setInitialState(QObject *object)
40{
41 auto item = qobject_cast<QQuickItem *>(o: object);
42 if (item) {
43 m_stateCallback(item);
44 }
45}
46
47void ToolBarDelegateIncubator::statusChanged(QQmlIncubator::Status status)
48{
49 if (status == QQmlIncubator::Error) {
50 qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
51 const auto e = errors();
52 for (const auto &error : e) {
53 qCWarning(KirigamiLog) << error;
54 }
55 m_finished = true;
56 }
57
58 if (status == QQmlIncubator::Ready) {
59 m_completedCallback(this);
60 m_finished = true;
61 }
62}
63
64ToolBarLayoutDelegate::ToolBarLayoutDelegate(ToolBarLayout *parent)
65 : QObject() // Note: delegates are managed by unique_ptr, so don't parent
66 , m_parent(parent)
67{
68}
69
70ToolBarLayoutDelegate::~ToolBarLayoutDelegate()
71{
72 if (m_fullIncubator) {
73 m_fullIncubator->clear();
74 delete m_fullIncubator;
75 }
76 if (m_iconIncubator) {
77 m_iconIncubator->clear();
78 delete m_iconIncubator;
79 }
80 if (m_full) {
81 m_full->disconnect(receiver: this);
82 delete m_full;
83 }
84 if (m_icon) {
85 m_icon->disconnect(receiver: this);
86 delete m_icon;
87 }
88}
89
90QObject *ToolBarLayoutDelegate::action() const
91{
92 return m_action;
93}
94
95void ToolBarLayoutDelegate::setAction(QObject *action)
96{
97 if (action == m_action) {
98 return;
99 }
100
101 if (m_action) {
102 QObject::disconnect(sender: m_action, SIGNAL(visibleChanged()), receiver: this, SLOT(actionVisibleChanged()));
103 QObject::disconnect(sender: m_action, SIGNAL(displayHintChanged()), receiver: this, SLOT(displayHintChanged()));
104 }
105
106 m_action = action;
107 if (m_action) {
108 if (m_action->property(name: "visible").isValid()) {
109 QObject::connect(sender: m_action, SIGNAL(visibleChanged()), receiver: this, SLOT(actionVisibleChanged()));
110 m_actionVisible = m_action->property(name: "visible").toBool();
111 }
112
113 if (m_action->property(name: "displayHint").isValid()) {
114 QObject::connect(sender: m_action, SIGNAL(displayHintChanged()), receiver: this, SLOT(displayHintChanged()));
115 m_displayHint = DisplayHint::DisplayHints{m_action->property(name: "displayHint").toInt()};
116 }
117 }
118}
119
120void ToolBarLayoutDelegate::createItems(QQmlComponent *fullComponent, QQmlComponent *iconComponent, std::function<void(QQuickItem *)> callback)
121{
122 m_fullIncubator = new ToolBarDelegateIncubator(fullComponent, qmlContext(fullComponent));
123 m_fullIncubator->setStateCallback(callback);
124 m_fullIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
125 if (incubator->isError()) {
126 qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
127 const auto errors = incubator->errors();
128 for (const auto &error : errors) {
129 qCWarning(KirigamiLog) << error;
130 }
131 return;
132 }
133
134 m_full = qobject_cast<QQuickItem *>(o: incubator->object());
135 m_full->setVisible(false);
136 connect(sender: m_full, signal: &QQuickItem::implicitWidthChanged, context: this, slot: &ToolBarLayoutDelegate::triggerRelayout);
137 connect(sender: m_full, signal: &QQuickItem::implicitHeightChanged, context: this, slot: &ToolBarLayoutDelegate::triggerRelayout);
138 connect(sender: m_full, signal: &QQuickItem::visibleChanged, context: this, slot: &ToolBarLayoutDelegate::ensureItemVisibility);
139
140 if (m_icon) {
141 m_ready = true;
142 }
143
144 m_parent->relayout();
145
146 QMetaObject::invokeMethod(object: this, function: &ToolBarLayoutDelegate::cleanupIncubators, type: Qt::QueuedConnection);
147 });
148 m_iconIncubator = new ToolBarDelegateIncubator(iconComponent, qmlContext(iconComponent));
149 m_iconIncubator->setStateCallback(callback);
150 m_iconIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
151 if (incubator->isError()) {
152 qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
153 const auto errors = incubator->errors();
154 for (const auto &error : errors) {
155 qCWarning(KirigamiLog) << error;
156 }
157 return;
158 }
159
160 m_icon = qobject_cast<QQuickItem *>(o: incubator->object());
161 m_icon->setVisible(false);
162 connect(sender: m_icon, signal: &QQuickItem::implicitWidthChanged, context: this, slot: &ToolBarLayoutDelegate::triggerRelayout);
163 connect(sender: m_icon, signal: &QQuickItem::implicitHeightChanged, context: this, slot: &ToolBarLayoutDelegate::triggerRelayout);
164 connect(sender: m_icon, signal: &QQuickItem::visibleChanged, context: this, slot: &ToolBarLayoutDelegate::ensureItemVisibility);
165
166 if (m_full) {
167 m_ready = true;
168 }
169
170 m_parent->relayout();
171
172 QMetaObject::invokeMethod(object: this, function: &ToolBarLayoutDelegate::cleanupIncubators, type: Qt::QueuedConnection);
173 });
174
175 m_fullIncubator->create();
176 m_iconIncubator->create();
177}
178
179bool ToolBarLayoutDelegate::isReady() const
180{
181 return m_ready;
182}
183
184bool ToolBarLayoutDelegate::isActionVisible() const
185{
186 return m_actionVisible;
187}
188
189bool ToolBarLayoutDelegate::isHidden() const
190{
191 return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::AlwaysHide);
192}
193
194bool ToolBarLayoutDelegate::isIconOnly() const
195{
196 return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::IconOnly);
197}
198
199bool ToolBarLayoutDelegate::isKeepVisible() const
200{
201 return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::KeepVisible);
202}
203
204bool ToolBarLayoutDelegate::isVisible() const
205{
206 return m_iconVisible || m_fullVisible;
207}
208
209void ToolBarLayoutDelegate::hide()
210{
211 m_iconVisible = false;
212 m_fullVisible = false;
213 ensureItemVisibility();
214}
215
216void ToolBarLayoutDelegate::showFull()
217{
218 m_iconVisible = false;
219 m_fullVisible = true;
220}
221
222void ToolBarLayoutDelegate::showIcon()
223{
224 m_iconVisible = true;
225 m_fullVisible = false;
226}
227
228void ToolBarLayoutDelegate::show()
229{
230 ensureItemVisibility();
231}
232
233void ToolBarLayoutDelegate::setPosition(qreal x, qreal y)
234{
235 m_full->setX(x);
236 m_icon->setX(x);
237 m_full->setY(y);
238 m_icon->setY(y);
239}
240
241void ToolBarLayoutDelegate::setHeight(qreal height)
242{
243 m_full->setHeight(height);
244 m_icon->setHeight(height);
245}
246
247void ToolBarLayoutDelegate::resetHeight()
248{
249 m_full->resetHeight();
250 m_icon->resetHeight();
251}
252
253qreal ToolBarLayoutDelegate::width() const
254{
255 if (m_iconVisible) {
256 return m_icon->width();
257 }
258 return m_full->width();
259}
260
261qreal ToolBarLayoutDelegate::height() const
262{
263 if (m_iconVisible) {
264 return m_icon->height();
265 }
266 return m_full->height();
267}
268
269qreal ToolBarLayoutDelegate::implicitWidth() const
270{
271 if (m_iconVisible) {
272 return m_icon->implicitWidth();
273 }
274 return m_full->implicitWidth();
275}
276
277qreal ToolBarLayoutDelegate::implicitHeight() const
278{
279 if (m_iconVisible) {
280 return m_icon->implicitHeight();
281 }
282 return m_full->implicitHeight();
283}
284
285qreal ToolBarLayoutDelegate::maxHeight() const
286{
287 return std::max(a: m_full->implicitHeight(), b: m_icon->implicitHeight());
288}
289
290qreal ToolBarLayoutDelegate::iconWidth() const
291{
292 return m_icon->width();
293}
294
295qreal ToolBarLayoutDelegate::fullWidth() const
296{
297 return m_full->width();
298}
299
300void ToolBarLayoutDelegate::actionVisibleChanged()
301{
302 m_actionVisible = m_action->property(name: "visible").toBool();
303 m_parent->relayout();
304}
305
306void ToolBarLayoutDelegate::displayHintChanged()
307{
308 m_displayHint = DisplayHint::DisplayHints{m_action->property(name: "displayHint").toInt()};
309 m_parent->relayout();
310}
311
312void ToolBarLayoutDelegate::cleanupIncubators()
313{
314 if (m_fullIncubator && m_fullIncubator->isFinished()) {
315 delete m_fullIncubator;
316 m_fullIncubator = nullptr;
317 }
318
319 if (m_iconIncubator && m_iconIncubator->isFinished()) {
320 delete m_iconIncubator;
321 m_iconIncubator = nullptr;
322 }
323}
324
325void ToolBarLayoutDelegate::triggerRelayout()
326{
327 m_parent->relayout();
328}
329
330#include "moc_toolbarlayoutdelegate.cpp"
331

source code of kirigami/src/toolbarlayoutdelegate.cpp