vcl/inc/qt5/QtInstanceContainer.hxx | 7 +++ vcl/inc/qt5/QtInstanceMessageDialog.hxx | 3 + vcl/qt5/QtInstanceContainer.cxx | 26 ++++++++++++- vcl/qt5/QtInstanceMessageDialog.cxx | 62 +++++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 4 deletions(-)
New commits: commit c392f12d3379d51d3f24d3f58a15518aef84f951 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Tue Nov 5 17:40:28 2024 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Wed Nov 6 18:59:34 2024 +0100 tdf#130857 qt weld: Add layout/widget for extra msg dialog controls weld::MessageDialog::weld_message_area needs to return a weld::Container that can be used to insert additional controls into a message dialog. In order to implement this for QtInstanceMessageDialog, insert an additional widget with a QVBoxLayout layout into the QMessageBox layout, and return that one. In order to ensure that the extra controls are inserted in between the labels holding the text in the message dialog and the button box, make use of the known implementation detail that Qt's QMessageBox uses QGridLayout for its layout (see QMessageBoxPrivate::setupLayout in qtbase [1]), find where the last label is positioned, shift everything after the last label down by one row in the grid layout, then insert the extra widget in the now empty row. If QMessageBox internals ever change to use a different layout,..., then this will have to be adjusted in the future, but it works fine in my tests with both, Qt 5.15 and current qtbase dev (as of commit 4c0b45553862d3eff35906d02ea5e2afd9252bbd). This will be needed e.g. by the "LibreOfficDev Help Not Installed" dialog that shows up when pressing F1 in a build not including the local help. [1] https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/dialogs/qmessagebox.cpp?id=4c0b45553862d3eff35906d02ea5e2afd9252bbd#n290 Change-Id: I2153add5145a4655800ca89f8e943610014b1021 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176091 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/inc/qt5/QtInstanceMessageDialog.hxx b/vcl/inc/qt5/QtInstanceMessageDialog.hxx index 42489aa5a7cf..6f2cfac5606d 100644 --- a/vcl/inc/qt5/QtInstanceMessageDialog.hxx +++ b/vcl/inc/qt5/QtInstanceMessageDialog.hxx @@ -19,6 +19,8 @@ class QtInstanceMessageDialog : public QtInstanceDialog, public virtual weld::Me private: QMessageBox* m_pMessageDialog; + // widget containing a layout to add additional items + QWidget* m_pExtraControlsContainer; public: QtInstanceMessageDialog(QMessageBox* pMessageDialog); @@ -41,6 +43,7 @@ public: virtual int run() override; private: + QWidget* addWidgetForExtraItems(); virtual QPushButton* buttonForResponseCode(int nResponse); protected slots: diff --git a/vcl/qt5/QtInstanceMessageDialog.cxx b/vcl/qt5/QtInstanceMessageDialog.cxx index ed2c377258bb..9be7dd9c4f27 100644 --- a/vcl/qt5/QtInstanceMessageDialog.cxx +++ b/vcl/qt5/QtInstanceMessageDialog.cxx @@ -12,13 +12,18 @@ #include <vcl/qt/QtUtils.hxx> +#include <QtWidgets/QLabel> #include <QtWidgets/QPushButton> +#include <QtWidgets/QVBoxLayout> QtInstanceMessageDialog::QtInstanceMessageDialog(QMessageBox* pMessageDialog) : QtInstanceDialog(pMessageDialog) , m_pMessageDialog(pMessageDialog) { assert(m_pMessageDialog); + + m_pExtraControlsContainer = addWidgetForExtraItems(); + assert(m_pExtraControlsContainer); } void QtInstanceMessageDialog::set_primary_text(const rtl::OUString& rText) @@ -47,7 +52,10 @@ void QtInstanceMessageDialog::set_secondary_text(const rtl::OUString& rText) m_pMessageDialog->setInformativeText(toQString(rText)); } -weld::Container* QtInstanceMessageDialog::weld_message_area() { return nullptr; } +weld::Container* QtInstanceMessageDialog::weld_message_area() +{ + return new QtInstanceContainer(m_pExtraControlsContainer); +} OUString QtInstanceMessageDialog::get_primary_text() const { @@ -165,6 +173,58 @@ void QtInstanceMessageDialog::dialogFinished(int nResult) QtInstanceDialog::dialogFinished(nResponseCode); } +QWidget* QtInstanceMessageDialog::addWidgetForExtraItems() +{ + // make use of implementation detail that QMessageBox uses QGridLayout for its layout + // (logic here will need to be adjusted if that ever changes) + QGridLayout* pDialogLayout = qobject_cast<QGridLayout*>(m_pMessageDialog->layout()); + assert(pDialogLayout && "QMessageBox has unexpected layout"); + + // find last label + const int nItemCount = pDialogLayout->count(); + int nLastLabelIndex = -1; + for (int i = nItemCount - 1; i >= 0; --i) + { + if (QLayoutItem* pItem = pDialogLayout->itemAt(i)) + { + if (qobject_cast<QLabel*>(pItem->widget())) + { + nLastLabelIndex = i; + break; + } + } + } + assert(nLastLabelIndex >= 0 && "didn't find label in message box"); + + // shift everything after the last label down by one row + for (int i = nLastLabelIndex + 1; i < nItemCount; ++i) + { + if (QLayoutItem* pItem = pDialogLayout->itemAt(i)) + { + int nRow = 0; + int nCol = 0; + int nRowSpan = 0; + int nColSpan = 0; + pDialogLayout->getItemPosition(i, &nRow, &nCol, &nRowSpan, &nColSpan); + pDialogLayout->removeItem(pItem); + pDialogLayout->addItem(pItem, nRow + 1, nCol, nRowSpan, nColSpan); + } + } + + // insert an additional layout in the now empty row, underneath the last label + int nLabelRow = 0; + int nLabelCol = 0; + int nLabelRowSpan = 0; + int nLabelColSpan = 0; + pDialogLayout->getItemPosition(nLastLabelIndex, &nLabelRow, &nLabelCol, &nLabelRowSpan, + &nLabelColSpan); + QWidget* pWidget = new QWidget; + pWidget->setLayout(new QVBoxLayout); + pDialogLayout->addWidget(pWidget, nLabelRow + 1, nLabelCol); + + return pWidget; +} + QPushButton* QtInstanceMessageDialog::buttonForResponseCode(int nResponse) { SolarMutexGuard g; commit a1db771b40092a4e289d0bac52d1237afe7a1ec4 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Tue Nov 5 15:45:18 2024 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Wed Nov 6 18:59:27 2024 +0100 tdf#130857 qt weld: Implement QtInstanceContainer::move As documented in include/vcl/weld.hxx, the new parent can be null, in which case the widget is only removed from the current container. In that case, mark the widget for deletion, as there's no more parent that owns the widget and would take care of deleting it when getting deleted itself. Change-Id: I1b3374683629a841f5101098b967cc5cf75d4f69 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176090 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/inc/qt5/QtInstanceContainer.hxx b/vcl/inc/qt5/QtInstanceContainer.hxx index a0cd31869dc6..371cc4d46aae 100644 --- a/vcl/inc/qt5/QtInstanceContainer.hxx +++ b/vcl/inc/qt5/QtInstanceContainer.hxx @@ -11,18 +11,23 @@ #include "QtInstanceWidget.hxx" +#include <QtWidgets/QLayout> + class QtInstanceContainer : public QtInstanceWidget, public virtual weld::Container { public: QtInstanceContainer(QWidget* pWidget); - virtual void move(weld::Widget*, weld::Container*) override; + virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override; virtual css::uno::Reference<css::awt::XWindow> CreateChildFrame() override; virtual void child_grab_focus() override; virtual void connect_container_focus_changed(const Link<Container&, void>&) override; + +private: + QLayout& getLayout(); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtInstanceContainer.cxx b/vcl/qt5/QtInstanceContainer.cxx index 53f79eca9999..8f8742387235 100644 --- a/vcl/qt5/QtInstanceContainer.cxx +++ b/vcl/qt5/QtInstanceContainer.cxx @@ -15,9 +15,24 @@ QtInstanceContainer::QtInstanceContainer(QWidget* pWidget) assert(pWidget->layout() && "no layout to use for container"); } -void QtInstanceContainer::move(weld::Widget*, weld::Container*) +void QtInstanceContainer::move(weld::Widget* pWidget, weld::Container* pNewParent) { - assert(false && "Not implemented yet"); + QtInstanceWidget* pQtInstanceWidget = dynamic_cast<QtInstanceWidget*>(pWidget); + assert(pQtInstanceWidget); + QWidget* pQWidget = pQtInstanceWidget->getQWidget(); + assert(pQWidget); + getLayout().removeWidget(pQWidget); + + if (!pNewParent) + { + pQWidget->deleteLater(); + return; + } + + QtInstanceContainer* pNewContainer = dynamic_cast<QtInstanceContainer*>(pNewParent); + assert(pNewContainer); + QLayout& rNewLayout = pNewContainer->getLayout(); + rNewLayout.addWidget(pQWidget); } css::uno::Reference<css::awt::XWindow> QtInstanceContainer::CreateChildFrame() @@ -33,4 +48,11 @@ void QtInstanceContainer::connect_container_focus_changed(const Link<Container&, assert(false && "Not implemented yet"); } +QLayout& QtInstanceContainer::getLayout() +{ + QLayout* pLayout = getQWidget()->layout(); + assert(pLayout); + return *pLayout; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */