File indexing completed on 2024-04-14 03:53:49

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "toolbarlayoutdelegate.h"
0008 
0009 #include "loggingcategory.h"
0010 #include "toolbarlayout.h"
0011 
0012 ToolBarDelegateIncubator::ToolBarDelegateIncubator(QQmlComponent *component, QQmlContext *context)
0013     : QQmlIncubator(QQmlIncubator::Asynchronous)
0014     , m_component(component)
0015     , m_context(context)
0016 {
0017 }
0018 
0019 void ToolBarDelegateIncubator::setStateCallback(std::function<void(QQuickItem *)> callback)
0020 {
0021     m_stateCallback = callback;
0022 }
0023 
0024 void ToolBarDelegateIncubator::setCompletedCallback(std::function<void(ToolBarDelegateIncubator *)> callback)
0025 {
0026     m_completedCallback = callback;
0027 }
0028 
0029 void ToolBarDelegateIncubator::create()
0030 {
0031     m_component->create(*this, m_context);
0032 }
0033 
0034 bool ToolBarDelegateIncubator::isFinished()
0035 {
0036     return m_finished;
0037 }
0038 
0039 void ToolBarDelegateIncubator::setInitialState(QObject *object)
0040 {
0041     auto item = qobject_cast<QQuickItem *>(object);
0042     if (item) {
0043         m_stateCallback(item);
0044     }
0045 }
0046 
0047 void ToolBarDelegateIncubator::statusChanged(QQmlIncubator::Status status)
0048 {
0049     if (status == QQmlIncubator::Error) {
0050         qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
0051         const auto e = errors();
0052         for (const auto &error : e) {
0053             qCWarning(KirigamiLog) << error;
0054         }
0055         m_finished = true;
0056     }
0057 
0058     if (status == QQmlIncubator::Ready) {
0059         m_completedCallback(this);
0060         m_finished = true;
0061     }
0062 }
0063 
0064 ToolBarLayoutDelegate::ToolBarLayoutDelegate(ToolBarLayout *parent)
0065     : QObject() // Note: delegates are managed by unique_ptr, so don't parent
0066     , m_parent(parent)
0067 {
0068 }
0069 
0070 ToolBarLayoutDelegate::~ToolBarLayoutDelegate()
0071 {
0072     if (m_fullIncubator) {
0073         m_fullIncubator->clear();
0074         delete m_fullIncubator;
0075     }
0076     if (m_iconIncubator) {
0077         m_iconIncubator->clear();
0078         delete m_iconIncubator;
0079     }
0080     if (m_full) {
0081         m_full->disconnect(this);
0082         delete m_full;
0083     }
0084     if (m_icon) {
0085         m_icon->disconnect(this);
0086         delete m_icon;
0087     }
0088 }
0089 
0090 QObject *ToolBarLayoutDelegate::action() const
0091 {
0092     return m_action;
0093 }
0094 
0095 void ToolBarLayoutDelegate::setAction(QObject *action)
0096 {
0097     if (action == m_action) {
0098         return;
0099     }
0100 
0101     if (m_action) {
0102         QObject::disconnect(m_action, SIGNAL(visibleChanged()), this, SLOT(actionVisibleChanged()));
0103         QObject::disconnect(m_action, SIGNAL(displayHintChanged()), this, SLOT(displayHintChanged()));
0104     }
0105 
0106     m_action = action;
0107     if (m_action) {
0108         if (m_action->property("visible").isValid()) {
0109             QObject::connect(m_action, SIGNAL(visibleChanged()), this, SLOT(actionVisibleChanged()));
0110             m_actionVisible = m_action->property("visible").toBool();
0111         }
0112 
0113         if (m_action->property("displayHint").isValid()) {
0114             QObject::connect(m_action, SIGNAL(displayHintChanged()), this, SLOT(displayHintChanged()));
0115             m_displayHint = DisplayHint::DisplayHints{m_action->property("displayHint").toInt()};
0116         }
0117     }
0118 }
0119 
0120 void ToolBarLayoutDelegate::createItems(QQmlComponent *fullComponent, QQmlComponent *iconComponent, std::function<void(QQuickItem *)> callback)
0121 {
0122     m_fullIncubator = new ToolBarDelegateIncubator(fullComponent, qmlContext(fullComponent));
0123     m_fullIncubator->setStateCallback(callback);
0124     m_fullIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
0125         if (incubator->isError()) {
0126             qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
0127             const auto errors = incubator->errors();
0128             for (const auto &error : errors) {
0129                 qCWarning(KirigamiLog) << error;
0130             }
0131             return;
0132         }
0133 
0134         m_full = qobject_cast<QQuickItem *>(incubator->object());
0135         m_full->setVisible(false);
0136         connect(m_full, &QQuickItem::implicitWidthChanged, this, &ToolBarLayoutDelegate::triggerRelayout);
0137         connect(m_full, &QQuickItem::implicitHeightChanged, this, &ToolBarLayoutDelegate::triggerRelayout);
0138         connect(m_full, &QQuickItem::visibleChanged, this, &ToolBarLayoutDelegate::ensureItemVisibility);
0139 
0140         if (m_icon) {
0141             m_ready = true;
0142         }
0143 
0144         m_parent->relayout();
0145 
0146         QMetaObject::invokeMethod(this, &ToolBarLayoutDelegate::cleanupIncubators, Qt::QueuedConnection);
0147     });
0148     m_iconIncubator = new ToolBarDelegateIncubator(iconComponent, qmlContext(iconComponent));
0149     m_iconIncubator->setStateCallback(callback);
0150     m_iconIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
0151         if (incubator->isError()) {
0152             qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
0153             const auto errors = incubator->errors();
0154             for (const auto &error : errors) {
0155                 qCWarning(KirigamiLog) << error;
0156             }
0157             return;
0158         }
0159 
0160         m_icon = qobject_cast<QQuickItem *>(incubator->object());
0161         m_icon->setVisible(false);
0162         connect(m_icon, &QQuickItem::implicitWidthChanged, this, &ToolBarLayoutDelegate::triggerRelayout);
0163         connect(m_icon, &QQuickItem::implicitHeightChanged, this, &ToolBarLayoutDelegate::triggerRelayout);
0164         connect(m_icon, &QQuickItem::visibleChanged, this, &ToolBarLayoutDelegate::ensureItemVisibility);
0165 
0166         if (m_full) {
0167             m_ready = true;
0168         }
0169 
0170         m_parent->relayout();
0171 
0172         QMetaObject::invokeMethod(this, &ToolBarLayoutDelegate::cleanupIncubators, Qt::QueuedConnection);
0173     });
0174 
0175     m_fullIncubator->create();
0176     m_iconIncubator->create();
0177 }
0178 
0179 bool ToolBarLayoutDelegate::isReady() const
0180 {
0181     return m_ready;
0182 }
0183 
0184 bool ToolBarLayoutDelegate::isActionVisible() const
0185 {
0186     return m_actionVisible;
0187 }
0188 
0189 bool ToolBarLayoutDelegate::isHidden() const
0190 {
0191     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::AlwaysHide);
0192 }
0193 
0194 bool ToolBarLayoutDelegate::isIconOnly() const
0195 {
0196     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::IconOnly);
0197 }
0198 
0199 bool ToolBarLayoutDelegate::isKeepVisible() const
0200 {
0201     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::KeepVisible);
0202 }
0203 
0204 bool ToolBarLayoutDelegate::isVisible() const
0205 {
0206     return m_iconVisible || m_fullVisible;
0207 }
0208 
0209 void ToolBarLayoutDelegate::hide()
0210 {
0211     m_iconVisible = false;
0212     m_fullVisible = false;
0213     ensureItemVisibility();
0214 }
0215 
0216 void ToolBarLayoutDelegate::showFull()
0217 {
0218     m_iconVisible = false;
0219     m_fullVisible = true;
0220 }
0221 
0222 void ToolBarLayoutDelegate::showIcon()
0223 {
0224     m_iconVisible = true;
0225     m_fullVisible = false;
0226 }
0227 
0228 void ToolBarLayoutDelegate::show()
0229 {
0230     ensureItemVisibility();
0231 }
0232 
0233 void ToolBarLayoutDelegate::setPosition(qreal x, qreal y)
0234 {
0235     m_full->setX(x);
0236     m_icon->setX(x);
0237     m_full->setY(y);
0238     m_icon->setY(y);
0239 }
0240 
0241 void ToolBarLayoutDelegate::setHeight(qreal height)
0242 {
0243     m_full->setHeight(height);
0244     m_icon->setHeight(height);
0245 }
0246 
0247 void ToolBarLayoutDelegate::resetHeight()
0248 {
0249     m_full->resetHeight();
0250     m_icon->resetHeight();
0251 }
0252 
0253 qreal ToolBarLayoutDelegate::width() const
0254 {
0255     if (m_iconVisible) {
0256         return m_icon->width();
0257     }
0258     return m_full->width();
0259 }
0260 
0261 qreal ToolBarLayoutDelegate::height() const
0262 {
0263     if (m_iconVisible) {
0264         return m_icon->height();
0265     }
0266     return m_full->height();
0267 }
0268 
0269 qreal ToolBarLayoutDelegate::implicitWidth() const
0270 {
0271     if (m_iconVisible) {
0272         return m_icon->implicitWidth();
0273     }
0274     return m_full->implicitWidth();
0275 }
0276 
0277 qreal ToolBarLayoutDelegate::implicitHeight() const
0278 {
0279     if (m_iconVisible) {
0280         return m_icon->implicitHeight();
0281     }
0282     return m_full->implicitHeight();
0283 }
0284 
0285 qreal ToolBarLayoutDelegate::maxHeight() const
0286 {
0287     return std::max(m_full->implicitHeight(), m_icon->implicitHeight());
0288 }
0289 
0290 qreal ToolBarLayoutDelegate::iconWidth() const
0291 {
0292     return m_icon->width();
0293 }
0294 
0295 qreal ToolBarLayoutDelegate::fullWidth() const
0296 {
0297     return m_full->width();
0298 }
0299 
0300 void ToolBarLayoutDelegate::actionVisibleChanged()
0301 {
0302     m_actionVisible = m_action->property("visible").toBool();
0303     m_parent->relayout();
0304 }
0305 
0306 void ToolBarLayoutDelegate::displayHintChanged()
0307 {
0308     m_displayHint = DisplayHint::DisplayHints{m_action->property("displayHint").toInt()};
0309     m_parent->relayout();
0310 }
0311 
0312 void ToolBarLayoutDelegate::cleanupIncubators()
0313 {
0314     if (m_fullIncubator && m_fullIncubator->isFinished()) {
0315         delete m_fullIncubator;
0316         m_fullIncubator = nullptr;
0317     }
0318 
0319     if (m_iconIncubator && m_iconIncubator->isFinished()) {
0320         delete m_iconIncubator;
0321         m_iconIncubator = nullptr;
0322     }
0323 }
0324 
0325 void ToolBarLayoutDelegate::triggerRelayout()
0326 {
0327     m_parent->relayout();
0328 }
0329 
0330 #include "moc_toolbarlayoutdelegate.cpp"