File indexing completed on 2024-04-28 15:27:45

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::widthChanged, this, [this]() {
0137             m_parent->relayout();
0138         });
0139         connect(m_full, &QQuickItem::heightChanged, this, [this]() {
0140             m_parent->relayout();
0141         });
0142         connect(m_full, &QQuickItem::visibleChanged, this, &ToolBarLayoutDelegate::ensureItemVisibility);
0143 
0144         if (m_icon) {
0145             m_ready = true;
0146         }
0147 
0148         m_parent->relayout();
0149 
0150         QMetaObject::invokeMethod(this, &ToolBarLayoutDelegate::cleanupIncubators, Qt::QueuedConnection);
0151     });
0152     m_iconIncubator = new ToolBarDelegateIncubator(iconComponent, qmlContext(iconComponent));
0153     m_iconIncubator->setStateCallback(callback);
0154     m_iconIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
0155         if (incubator->isError()) {
0156             qCWarning(KirigamiLog) << "Could not create delegate for ToolBarLayout";
0157             const auto errors = incubator->errors();
0158             for (const auto &error : errors) {
0159                 qCWarning(KirigamiLog) << error;
0160             }
0161             return;
0162         }
0163 
0164         m_icon = qobject_cast<QQuickItem *>(incubator->object());
0165         m_icon->setVisible(false);
0166         connect(m_icon, &QQuickItem::widthChanged, this, [this]() {
0167             m_parent->relayout();
0168         });
0169         connect(m_icon, &QQuickItem::heightChanged, this, [this]() {
0170             m_parent->relayout();
0171         });
0172         connect(m_icon, &QQuickItem::visibleChanged, this, &ToolBarLayoutDelegate::ensureItemVisibility);
0173 
0174         if (m_full) {
0175             m_ready = true;
0176         }
0177 
0178         m_parent->relayout();
0179 
0180         QMetaObject::invokeMethod(this, &ToolBarLayoutDelegate::cleanupIncubators, Qt::QueuedConnection);
0181     });
0182 
0183     m_fullIncubator->create();
0184     m_iconIncubator->create();
0185 }
0186 
0187 bool ToolBarLayoutDelegate::isReady() const
0188 {
0189     return m_ready;
0190 }
0191 
0192 bool ToolBarLayoutDelegate::isActionVisible() const
0193 {
0194     return m_actionVisible;
0195 }
0196 
0197 bool ToolBarLayoutDelegate::isHidden() const
0198 {
0199     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::AlwaysHide);
0200 }
0201 
0202 bool ToolBarLayoutDelegate::isIconOnly() const
0203 {
0204     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::IconOnly);
0205 }
0206 
0207 bool ToolBarLayoutDelegate::isKeepVisible() const
0208 {
0209     return DisplayHint::isDisplayHintSet(m_displayHint, DisplayHint::KeepVisible);
0210 }
0211 
0212 bool ToolBarLayoutDelegate::isVisible() const
0213 {
0214     return m_iconVisible || m_fullVisible;
0215 }
0216 
0217 void ToolBarLayoutDelegate::hide()
0218 {
0219     m_iconVisible = false;
0220     m_fullVisible = false;
0221     ensureItemVisibility();
0222 }
0223 
0224 void ToolBarLayoutDelegate::showFull()
0225 {
0226     m_iconVisible = false;
0227     m_fullVisible = true;
0228 }
0229 
0230 void ToolBarLayoutDelegate::showIcon()
0231 {
0232     m_iconVisible = true;
0233     m_fullVisible = false;
0234 }
0235 
0236 void ToolBarLayoutDelegate::show()
0237 {
0238     ensureItemVisibility();
0239 }
0240 
0241 void ToolBarLayoutDelegate::setPosition(qreal x, qreal y)
0242 {
0243     m_full->setX(x);
0244     m_icon->setX(x);
0245     m_full->setY(y);
0246     m_icon->setY(y);
0247 }
0248 
0249 void ToolBarLayoutDelegate::setHeight(qreal height)
0250 {
0251     m_full->setHeight(height);
0252     m_icon->setHeight(height);
0253 }
0254 
0255 qreal ToolBarLayoutDelegate::width() const
0256 {
0257     if (m_iconVisible) {
0258         return m_icon->width();
0259     }
0260     return m_full->width();
0261 }
0262 
0263 qreal ToolBarLayoutDelegate::height() const
0264 {
0265     if (m_iconVisible) {
0266         return m_icon->height();
0267     }
0268     return m_full->height();
0269 }
0270 
0271 qreal ToolBarLayoutDelegate::implicitWidth() const
0272 {
0273     if (m_iconVisible) {
0274         return m_icon->implicitWidth();
0275     }
0276     return m_full->implicitWidth();
0277 }
0278 
0279 qreal ToolBarLayoutDelegate::implicitHeight() const
0280 {
0281     if (m_iconVisible) {
0282         return m_icon->implicitHeight();
0283     }
0284     return m_full->implicitHeight();
0285 }
0286 
0287 qreal ToolBarLayoutDelegate::maxHeight() const
0288 {
0289     return std::max(m_full->height(), m_icon->height());
0290 }
0291 
0292 qreal ToolBarLayoutDelegate::iconWidth() const
0293 {
0294     return m_icon->width();
0295 }
0296 
0297 qreal ToolBarLayoutDelegate::fullWidth() const
0298 {
0299     return m_full->width();
0300 }
0301 
0302 void ToolBarLayoutDelegate::actionVisibleChanged()
0303 {
0304     m_actionVisible = m_action->property("visible").toBool();
0305     m_parent->relayout();
0306 }
0307 
0308 void ToolBarLayoutDelegate::displayHintChanged()
0309 {
0310     m_displayHint = DisplayHint::DisplayHints{m_action->property("displayHint").toInt()};
0311     m_parent->relayout();
0312 }
0313 
0314 void ToolBarLayoutDelegate::cleanupIncubators()
0315 {
0316     if (m_fullIncubator && m_fullIncubator->isFinished()) {
0317         delete m_fullIncubator;
0318         m_fullIncubator = nullptr;
0319     }
0320 
0321     if (m_iconIncubator && m_iconIncubator->isFinished()) {
0322         delete m_iconIncubator;
0323         m_iconIncubator = nullptr;
0324     }
0325 }
0326 
0327 #include "moc_toolbarlayoutdelegate.cpp"