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"