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: */

Reply via email to