/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include const char* const QtInstanceDialog::PROPERTY_VCL_RESPONSE_CODE = "response-code"; QtInstanceDialog::QtInstanceDialog(QDialog* pDialog) : QtInstanceWindow(pDialog) , m_pDialog(pDialog) , m_pContentArea(nullptr) , m_aRunAsyncFunc(nullptr) { assert(m_pDialog); } QtInstanceDialog::~QtInstanceDialog() { SolarMutexGuard g; GetQtInstance().RunInMainThread([&] { m_pDialog->hide(); m_pDialog->deleteLater(); }); } bool QtInstanceDialog::runAsync(const std::shared_ptr& rxOwner, const std::function& func) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { bool bRet = false; rQtInstance.RunInMainThread([&] { bRet = runAsync(rxOwner, func); }); return bRet; } assert(m_pDialog); m_xRunAsyncDialogController = rxOwner; m_aRunAsyncFunc = func; connect(m_pDialog, &QDialog::finished, this, &QtInstanceDialog::dialogFinished); m_pDialog->show(); return true; } bool QtInstanceDialog::runAsync(std::shared_ptr const& rxSelf, const std::function& func) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { bool bRet; rQtInstance.RunInMainThread([&] { bRet = runAsync(rxSelf, func); }); return bRet; } assert(m_pDialog); assert(rxSelf.get() == this); m_xRunAsyncDialog = rxSelf; m_aRunAsyncFunc = func; connect(m_pDialog, &QDialog::finished, this, &QtInstanceDialog::dialogFinished); m_pDialog->open(); return true; } void QtInstanceDialog::collapse(weld::Widget& rEdit, weld::Widget* pButton) { SolarMutexGuard g; assert(m_aVisibleWidgetsBeforeCollapsing.empty() && "Dialog already collapsed?"); GetQtInstance().RunInMainThread([&] { #if QT_VERSION_CHECK(6, 3, 0) const QList m_pChildren = m_pDialog->findChildren(); #else const QList m_pChildren = m_pDialog->findChildren(QLatin1String("")); #endif // hide all widgets for (QWidget* pChild : m_pChildren) { if (!pChild->isHidden()) { m_aVisibleWidgetsBeforeCollapsing.push_back(pChild); pChild->hide(); } } // make the given widgets (and their ancestors) visible again QtInstanceWidget& rQtEdit = dynamic_cast(rEdit); QWidget* pEditWidget = rQtEdit.getQWidget(); assert(pEditWidget); QtInstanceWidget* pQtButton = dynamic_cast(pButton); QWidget* pButtonWidget = pQtButton ? pQtButton->getQWidget() : nullptr; for (QWidget* pVisibleWidget : { pEditWidget, pButtonWidget }) { QWidget* pWidget = pVisibleWidget; while (pWidget) { pWidget->setVisible(true); pWidget = pWidget->parentWidget(); } } resize_to_request(); }); } void QtInstanceDialog::undo_collapse() { SolarMutexGuard g; GetQtInstance().RunInMainThread([&] { for (QWidget* pWidget : m_aVisibleWidgetsBeforeCollapsing) pWidget->show(); m_aVisibleWidgetsBeforeCollapsing.clear(); resize_to_request(); }); } void QtInstanceDialog::SetInstallLOKNotifierHdl(const Link&) { } int QtInstanceDialog::run() { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { int nResult = 0; rQtInstance.RunInMainThread([&] { nResult = run(); }); return nResult; } return m_pDialog->exec(); } void QtInstanceDialog::response(int nResponse) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); rQtInstance.RunInMainThread([&] { m_pDialog->done(nResponse); }); } void QtInstanceDialog::add_button(const OUString& rText, int nResponse, const OUString& rHelpId) { SolarMutexGuard g; GetQtInstance().RunInMainThread([&] { QDialogButtonBox* pButtonBox = findButtonBox(m_pDialog); assert(pButtonBox && "Dialog has no button box"); QPushButton* pButton = pButtonBox->addButton(toQString(rText), QDialogButtonBox::NoRole); pButton->setProperty(QtInstanceDialog::PROPERTY_VCL_RESPONSE_CODE, nResponse); setHelpId(*pButton, rHelpId); }); } void QtInstanceDialog::set_modal(bool bModal) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { rQtInstance.RunInMainThread([&] { set_modal(bModal); }); return; } m_pDialog->setModal(bModal); } bool QtInstanceDialog::get_modal() const { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { bool bModal = false; rQtInstance.RunInMainThread([&] { bModal = get_modal(); }); return bModal; } return m_pDialog->isModal(); } void QtInstanceDialog::set_centered_on_parent(bool) { // QDialog is centered on parent toplevel by default } std::unique_ptr QtInstanceDialog::weld_button_for_response(int nResponse) { SolarMutexGuard g; QPushButton* pButton = nullptr; GetQtInstance().RunInMainThread([&] { if (QDialogButtonBox* pButtonBox = findButtonBox(m_pDialog)) { const QList aButtons = pButtonBox->buttons(); pButton = buttonForResponseCode(aButtons, nResponse); } }); if (pButton) return std::make_unique(pButton); return nullptr; } std::unique_ptr QtInstanceDialog::weld_content_area() { if (!m_pContentArea) { if (QBoxLayout* pBoxLayout = qobject_cast(m_pDialog->layout())) { // insert an extra widget and layout at beginning of the dialog's layout m_pContentArea = new QWidget; m_pContentArea->setLayout(new QVBoxLayout); pBoxLayout->insertWidget(0, m_pContentArea); } else { assert(false && "Dialog has layout that's not supported (yet)"); } } return std::make_unique(m_pContentArea); } void QtInstanceDialog::change_default_button(weld::Button* pOld, weld::Button* pNew) { SolarMutexGuard g; GetQtInstance().RunInMainThread([&] { if (QtInstanceButton* pOldButton = dynamic_cast(pOld)) { if (QPushButton* pPushButton = qobject_cast(&pOldButton->getButton())) pPushButton->setDefault(false); } if (QtInstanceButton* pNewButton = dynamic_cast(pNew)) { if (QPushButton* pPushButton = qobject_cast(&pNewButton->getButton())) pPushButton->setDefault(true); } }); } bool QtInstanceDialog::is_default_button(const weld::Button* pCandidate) const { SolarMutexGuard g; bool bDefault = false; GetQtInstance().RunInMainThread([&] { if (const QtInstanceButton* pButton = dynamic_cast(pCandidate)) { if (QPushButton* pPushButton = qobject_cast(&pButton->getButton())) bDefault = pPushButton->isDefault(); } }); return bDefault; } void QtInstanceDialog::dialogFinished(int nResult) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { rQtInstance.RunInMainThread([&] { dialogFinished(nResult); }); return; } disconnect(m_pDialog, &QDialog::finished, this, &QtInstanceDialog::dialogFinished); // use local variables for these, as members might have got de-allocated by the time they're reset std::shared_ptr xRunAsyncDialog = m_xRunAsyncDialog; std::shared_ptr xRunAsyncDialogController = m_xRunAsyncDialogController; std::function aFunc = m_aRunAsyncFunc; m_aRunAsyncFunc = nullptr; m_xRunAsyncDialogController.reset(); m_xRunAsyncDialog.reset(); if (aFunc) aFunc(nResult); xRunAsyncDialogController.reset(); xRunAsyncDialog.reset(); } QDialogButtonBox* QtInstanceDialog::findButtonBox(const QDialog* pDialog) { assert(pDialog); QLayout* pLayout = pDialog->layout(); if (!pLayout) return nullptr; for (int i = 0; i < pLayout->count(); i++) { QLayoutItem* pItem = pLayout->itemAt(i); if (QWidget* pItemWidget = pItem->widget()) { if (QDialogButtonBox* pButtonBox = qobject_cast(pItemWidget)) return pButtonBox; } } return nullptr; } QPushButton* QtInstanceDialog::buttonForResponseCode(const QList& rButtons, int nResponse) { for (QAbstractButton* pAbstractButton : rButtons) { if (pAbstractButton->property(PROPERTY_VCL_RESPONSE_CODE).toInt() == nResponse) { QPushButton* pButton = qobject_cast(pAbstractButton); assert(pButton); return pButton; } } return nullptr; } void QtInstanceDialog::handleButtonClick(QDialog& rDialog, QAbstractButton& rButton) { SolarMutexGuard g; QtInstance& rQtInstance = GetQtInstance(); if (!rQtInstance.IsMainThread()) { rQtInstance.RunInMainThread([&] { handleButtonClick(rDialog, rButton); }); return; } // skip default handling if a custom click handler is set if (QtInstanceButton::hasCustomClickHandler(rButton)) return; QVariant aResponseProperty = rButton.property(QtInstanceDialog::PROPERTY_VCL_RESPONSE_CODE); if (!aResponseProperty.isValid()) return; assert(aResponseProperty.canConvert()); const int nResponseCode = aResponseProperty.toInt(); // close dialog with button's response code unless it's the "Help" button if (nResponseCode != RET_HELP) { rDialog.done(nResponseCode); return; } // handle "Help" button Help* pHelp = Application::GetHelp(); if (!pHelp) return; QtInstanceWidget aButtonWidget(&rButton); pHelp->Start(aButtonWidget.get_help_id(), &aButtonWidget); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */