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 | |
12 | ToolBarDelegateIncubator::ToolBarDelegateIncubator(QQmlComponent *component, QQmlContext *context) |
13 | : QQmlIncubator(QQmlIncubator::Asynchronous) |
14 | , m_component(component) |
15 | , m_context(context) |
16 | { |
17 | } |
18 | |
19 | void ToolBarDelegateIncubator::setStateCallback(std::function<void(QQuickItem *)> callback) |
20 | { |
21 | m_stateCallback = callback; |
22 | } |
23 | |
24 | void ToolBarDelegateIncubator::setCompletedCallback(std::function<void(ToolBarDelegateIncubator *)> callback) |
25 | { |
26 | m_completedCallback = callback; |
27 | } |
28 | |
29 | void ToolBarDelegateIncubator::create() |
30 | { |
31 | m_component->create(*this, context: m_context); |
32 | } |
33 | |
34 | bool ToolBarDelegateIncubator::isFinished() |
35 | { |
36 | return m_finished; |
37 | } |
38 | |
39 | void ToolBarDelegateIncubator::setInitialState(QObject *object) |
40 | { |
41 | auto item = qobject_cast<QQuickItem *>(o: object); |
42 | if (item) { |
43 | m_stateCallback(item); |
44 | } |
45 | } |
46 | |
47 | void 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 | |
64 | ToolBarLayoutDelegate::ToolBarLayoutDelegate(ToolBarLayout *parent) |
65 | : QObject() // Note: delegates are managed by unique_ptr, so don't parent |
66 | , m_parent(parent) |
67 | { |
68 | } |
69 | |
70 | ToolBarLayoutDelegate::~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 | |
90 | QObject *ToolBarLayoutDelegate::action() const |
91 | { |
92 | return m_action; |
93 | } |
94 | |
95 | void 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 | |
120 | void 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 | |
179 | bool ToolBarLayoutDelegate::isReady() const |
180 | { |
181 | return m_ready; |
182 | } |
183 | |
184 | bool ToolBarLayoutDelegate::isActionVisible() const |
185 | { |
186 | return m_actionVisible; |
187 | } |
188 | |
189 | bool ToolBarLayoutDelegate::isHidden() const |
190 | { |
191 | return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::AlwaysHide); |
192 | } |
193 | |
194 | bool ToolBarLayoutDelegate::isIconOnly() const |
195 | { |
196 | return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::IconOnly); |
197 | } |
198 | |
199 | bool ToolBarLayoutDelegate::isKeepVisible() const |
200 | { |
201 | return DisplayHint::isDisplayHintSet(values: m_displayHint, hint: DisplayHint::KeepVisible); |
202 | } |
203 | |
204 | bool ToolBarLayoutDelegate::isVisible() const |
205 | { |
206 | return m_iconVisible || m_fullVisible; |
207 | } |
208 | |
209 | void ToolBarLayoutDelegate::hide() |
210 | { |
211 | m_iconVisible = false; |
212 | m_fullVisible = false; |
213 | ensureItemVisibility(); |
214 | } |
215 | |
216 | void ToolBarLayoutDelegate::showFull() |
217 | { |
218 | m_iconVisible = false; |
219 | m_fullVisible = true; |
220 | } |
221 | |
222 | void ToolBarLayoutDelegate::showIcon() |
223 | { |
224 | m_iconVisible = true; |
225 | m_fullVisible = false; |
226 | } |
227 | |
228 | void ToolBarLayoutDelegate::show() |
229 | { |
230 | ensureItemVisibility(); |
231 | } |
232 | |
233 | void 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 | |
241 | void ToolBarLayoutDelegate::setHeight(qreal height) |
242 | { |
243 | m_full->setHeight(height); |
244 | m_icon->setHeight(height); |
245 | } |
246 | |
247 | void ToolBarLayoutDelegate::resetHeight() |
248 | { |
249 | m_full->resetHeight(); |
250 | m_icon->resetHeight(); |
251 | } |
252 | |
253 | qreal ToolBarLayoutDelegate::width() const |
254 | { |
255 | if (m_iconVisible) { |
256 | return m_icon->width(); |
257 | } |
258 | return m_full->width(); |
259 | } |
260 | |
261 | qreal ToolBarLayoutDelegate::height() const |
262 | { |
263 | if (m_iconVisible) { |
264 | return m_icon->height(); |
265 | } |
266 | return m_full->height(); |
267 | } |
268 | |
269 | qreal ToolBarLayoutDelegate::implicitWidth() const |
270 | { |
271 | if (m_iconVisible) { |
272 | return m_icon->implicitWidth(); |
273 | } |
274 | return m_full->implicitWidth(); |
275 | } |
276 | |
277 | qreal ToolBarLayoutDelegate::implicitHeight() const |
278 | { |
279 | if (m_iconVisible) { |
280 | return m_icon->implicitHeight(); |
281 | } |
282 | return m_full->implicitHeight(); |
283 | } |
284 | |
285 | qreal ToolBarLayoutDelegate::maxHeight() const |
286 | { |
287 | return std::max(a: m_full->implicitHeight(), b: m_icon->implicitHeight()); |
288 | } |
289 | |
290 | qreal ToolBarLayoutDelegate::iconWidth() const |
291 | { |
292 | return m_icon->width(); |
293 | } |
294 | |
295 | qreal ToolBarLayoutDelegate::fullWidth() const |
296 | { |
297 | return m_full->width(); |
298 | } |
299 | |
300 | void ToolBarLayoutDelegate::actionVisibleChanged() |
301 | { |
302 | m_actionVisible = m_action->property(name: "visible" ).toBool(); |
303 | m_parent->relayout(); |
304 | } |
305 | |
306 | void ToolBarLayoutDelegate::displayHintChanged() |
307 | { |
308 | m_displayHint = DisplayHint::DisplayHints{m_action->property(name: "displayHint" ).toInt()}; |
309 | m_parent->relayout(); |
310 | } |
311 | |
312 | void 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 | |
325 | void ToolBarLayoutDelegate::triggerRelayout() |
326 | { |
327 | m_parent->relayout(); |
328 | } |
329 | |
330 | #include "moc_toolbarlayoutdelegate.cpp" |
331 | |