vcl/CustomTarget_qt5_moc.mk             |    1 
 vcl/CustomTarget_qt6_moc.mk             |    1 
 vcl/inc/qt5/QtInstanceMessageDialog.hxx |   19 +++++++++
 vcl/qt5/QtInstanceMessageDialog.cxx     |   63 ++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 1 deletion(-)

New commits:
commit a54abf77c40c59e5a4d8a70e1b129b1e420265a3
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Sat Feb 3 11:35:33 2024 +0100
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Sun Feb 4 07:01:14 2024 +0100

    tdf#130857 qt weld: Support asnyc running of msg dialogs
    
    Implement methods required to run a welded Qt message dialog
    asynchronously: `QtInstanceMessageDialog::runAsync` and
    `QtInstanceMessageDialog::response`.
    
    Run the dialog asynchronously using `QDialog::open` and
    connect to the `QDialog::finished` signal to be notified
    when the dialog gets closed.
    
    Similar to how the gtk-based implementation, use local
    variables for the `std::shared_ptr`s and reset the members
    right away, not only at the end of the slot, since resetting
    the relevant one set in the corresponding `runAsync` overload
    will result in the object getting deallocated, thus the members
    can no longer be accessed safely.
    
    Take the solar mutex before calling the callback function
    as that seems to be expected (e.g. otherwise triggers an assert
    for the below example where the callback functions
    modifies VCL widgets).
    
    With this in place, running welded Qt message dialogs
    asynchronously works instead of not showing up at all, e.g.
    
    1) start Writer with qt6 VCL plugin and without
       `SAL_VCL_QT_NO_WELDED_WIDGETS` set
    2) open "File" -> "Properties" -> "Security"
    3) click the "Protect..." button
    4) enter 2 different passwords and press "OK" button
    
    Change-Id: Ic1b1bfc7d89c1be8a9f9dee59bc86cf3da37a280
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162948
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk
index 5fb4f482e778..136741320e9d 100644
--- a/vcl/CustomTarget_qt5_moc.mk
+++ b/vcl/CustomTarget_qt5_moc.mk
@@ -14,6 +14,7 @@ $(call gb_CustomTarget_get_target,vcl/qt5) : \
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtFilePicker.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtFrame.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtInstance.moc \
+       $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtInstanceMessageDialog.moc 
\
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtMainWindow.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtMenu.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtObject.moc \
diff --git a/vcl/CustomTarget_qt6_moc.mk b/vcl/CustomTarget_qt6_moc.mk
index 77aab947164d..c544490d4398 100644
--- a/vcl/CustomTarget_qt6_moc.mk
+++ b/vcl/CustomTarget_qt6_moc.mk
@@ -14,6 +14,7 @@ $(call gb_CustomTarget_get_target,vcl/qt6) : \
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtFilePicker.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtFrame.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtInstance.moc \
+       $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtInstanceMessageDialog.moc 
\
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtMainWindow.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtMenu.moc \
        $(call gb_CustomTarget_get_workdir,vcl/qt6)/QtObject.moc \
diff --git a/vcl/inc/qt5/QtInstanceMessageDialog.hxx 
b/vcl/inc/qt5/QtInstanceMessageDialog.hxx
index ae353268833c..c12243b5945c 100644
--- a/vcl/inc/qt5/QtInstanceMessageDialog.hxx
+++ b/vcl/inc/qt5/QtInstanceMessageDialog.hxx
@@ -12,11 +12,20 @@
 #include "QtInstanceDialog.hxx"
 #include <QtWidgets/QMessageBox>
 
-class QtInstanceMessageDialog : public QtInstanceDialog, public virtual 
weld::MessageDialog
+class QtInstanceMessageDialog : public QObject,
+                                public QtInstanceDialog,
+                                public virtual weld::MessageDialog
 {
+    Q_OBJECT;
+
 private:
     QMessageBox* m_pMessageDialog;
 
+    // the DialogController/Dialog/function passed to the runAsync variants
+    std::shared_ptr<weld::DialogController> m_xRunAsyncDialogController;
+    std::shared_ptr<weld::Dialog> m_xRunAsyncDialog;
+    std::function<void(sal_Int32)> m_aRunAsyncFunc;
+
 public:
     QtInstanceMessageDialog(QMessageBox* pMessageDialog);
 
@@ -35,6 +44,14 @@ public:
                             const OUString& rHelpId = {}) override;
     virtual void set_default_response(int nResponse) override;
     virtual int run() override;
+    virtual bool runAsync(std::shared_ptr<weld::DialogController> const& 
rxOwner,
+                          const std::function<void(sal_Int32)>& func) override;
+    virtual bool runAsync(std::shared_ptr<Dialog> const& rxSelf,
+                          const std::function<void(sal_Int32)>& func) override;
+    virtual void response(int nResponse) override;
+
+private slots:
+    void dialogFinished(int nResult);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt5/QtInstanceMessageDialog.cxx 
b/vcl/qt5/QtInstanceMessageDialog.cxx
index 7e505aff7cd0..cbda4c6ae0dd 100644
--- a/vcl/qt5/QtInstanceMessageDialog.cxx
+++ b/vcl/qt5/QtInstanceMessageDialog.cxx
@@ -8,6 +8,7 @@
  */
 
 #include <QtInstanceMessageDialog.hxx>
+#include <QtInstanceMessageDialog.moc>
 
 #include <QtWidgets/QPushButton>
 
@@ -20,7 +21,9 @@ const char* const PROPERTY_VCL_RESPONSE_CODE = 
"response-code";
 QtInstanceMessageDialog::QtInstanceMessageDialog(QMessageBox* pMessageDialog)
     : QtInstanceDialog(pMessageDialog)
     , m_pMessageDialog(pMessageDialog)
+    , m_aRunAsyncFunc(nullptr)
 {
+    assert(m_pMessageDialog);
 }
 
 void QtInstanceMessageDialog::set_primary_text(const rtl::OUString& rText)
@@ -81,4 +84,64 @@ int QtInstanceMessageDialog::run()
     return pClickedButton->property(PROPERTY_VCL_RESPONSE_CODE).toInt();
 }
 
+bool QtInstanceMessageDialog::runAsync(const 
std::shared_ptr<weld::DialogController>& rxOwner,
+                                       const std::function<void(sal_Int32)>& 
func)
+{
+    assert(m_pMessageDialog);
+
+    m_xRunAsyncDialogController = rxOwner;
+    m_aRunAsyncFunc = func;
+    connect(m_pMessageDialog, &QDialog::finished, this, 
&QtInstanceMessageDialog::dialogFinished);
+    m_pMessageDialog->open();
+
+    return true;
+}
+
+bool QtInstanceMessageDialog::runAsync(std::shared_ptr<Dialog> const& rxSelf,
+                                       const std::function<void(sal_Int32)>& 
func)
+{
+    assert(m_pMessageDialog);
+    assert(rxSelf.get() == this);
+
+    m_xRunAsyncDialog = rxSelf;
+    m_aRunAsyncFunc = func;
+    connect(m_pMessageDialog, &QDialog::finished, this, 
&QtInstanceMessageDialog::dialogFinished);
+    m_pMessageDialog->open();
+
+    return true;
+}
+
+void QtInstanceMessageDialog::response(int nResponse)
+{
+    assert(m_pMessageDialog);
+    m_pMessageDialog->done(nResponse);
+}
+
+void QtInstanceMessageDialog::dialogFinished(int nResult)
+{
+    assert(m_aRunAsyncFunc);
+
+    disconnect(m_pMessageDialog, &QDialog::finished, this,
+               &QtInstanceMessageDialog::dialogFinished);
+
+    // use local variables for these, as members might have got de-allocated 
by the time they're reset
+    std::shared_ptr<weld::Dialog> xRunAsyncDialog = m_xRunAsyncDialog;
+    std::shared_ptr<weld::DialogController> xRunAsyncDialogController = 
m_xRunAsyncDialogController;
+    std::function<void(sal_Int32)> aFunc = m_aRunAsyncFunc;
+    m_aRunAsyncFunc = nullptr;
+    m_xRunAsyncDialogController.reset();
+    m_xRunAsyncDialog.reset();
+
+    // if a button was clicked, use its response code, otherwise the passed one
+    int nRet = nResult;
+    if (QAbstractButton* pClickedButton = m_pMessageDialog->clickedButton())
+        nRet = pClickedButton->property(PROPERTY_VCL_RESPONSE_CODE).toInt();
+
+    SolarMutexGuard g;
+    aFunc(nRet);
+
+    xRunAsyncDialogController.reset();
+    xRunAsyncDialog.reset();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to