vcl/inc/qt5/QtInstanceAssistant.hxx |   19 +++++
 vcl/qt5/QtInstanceAssistant.cxx     |  118 ++++++++++++++++++++++++++++--------
 2 files changed, 114 insertions(+), 23 deletions(-)

New commits:
commit 7bec65cca52f297b39b909182cff544285e0969d
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Sun Feb 23 01:58:50 2025 +0100
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Sun Feb 23 10:15:52 2025 +0100

    tdf#130857 qt weld: Implement QtInstanceAssistant::set_page_index
    
    As already mentioned in
    
        Change-Id: I91b44da40736f6e61c64167d00305a1d7ba06b45
        Author: Michael Weghorn <m.wegh...@posteo.de>
        Date:   Sat Feb 22 18:30:30 2025 +0100
    
            tdf#130857 qt weld: Introduce QtInstanceAssistant
    
    , the page id that QWizard uses does not conceptually match
    the page index that weld::Assistant uses:
    
    weld::Assistant uses two ways to refer to specific pages:
    1) an int page index
    2) an OUString identifier
    
    QWizard uses an int id to refer to pages. This concept of an id does
    not match the index concept that weld::Assistang uses. (The id generally
    does not match an index in the range between 0 and the number of pages - 1.)
    
    Introduce a new property PROPERTY_PAGE_INDEX that
    gets set on the QWizardPage objects and contains
    the page index as used in the weld::Assistant API
    and 2 helper methods QtInstanceAssistant::pageIndex
    and QtInstanceAssistant::setPageIndex to get/set
    the page index property for a page as well as a helper
    method QtInstanceAssistant::page that returns the
    page for a given page index.
    
    Update existing code to no longer assume that
    the QWizard page ID and the weld::Assistant page index
    are the same.
    
    Implement QtInstanceAssistant::set_page_index that
    moves an existing page to a new position/index.
    Given that the IDs used in QWizard don't match the
    page indices, use a vector to sort by page index
    instead and reassign the new index property to
    all pages at the end.
    
    In a previous attempt trying to keep the QWizard page ID
    and the weld::Assistant page index in sync, I ran
    into the problem that the ID for a page cannot simply
    be changed, and removing and reinserting a page with
    a new ID had the side-effect that it triggered events.
    (And the current page can change when pages are removed
    from QWizard.)
    
    While the default QWizard logic that decides what
    page to switch to when pressing e.g. the "Next"
    button would switch to the page with the lowest
    ID greater than the current page (see [1], [2])
    in which case the page IDs would be relevant.
    However, the approach taken in LO is that the
    logic of switching pages is handled "manually"
    inside LO instead, using callbacks that get triggered
    on button click, etc.
    
    [1] https://doc.qt.io/qt-6/qwizard.html#nextId
    [2] https://doc.qt.io/qt-6/qwizardpage.html#nextId
    
    Change-Id: Idd94676e850cabca75763645cb1e102999b80b64
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182047
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/vcl/inc/qt5/QtInstanceAssistant.hxx 
b/vcl/inc/qt5/QtInstanceAssistant.hxx
index 199d6415c5c0..4478c9ef198f 100644
--- a/vcl/inc/qt5/QtInstanceAssistant.hxx
+++ b/vcl/inc/qt5/QtInstanceAssistant.hxx
@@ -15,6 +15,20 @@
 
 #include <QtWidgets/QWizard>
 
+/*
+ * weld::Assistant implementation using a QWizard widget.
+ *
+ * The weld::Assistant API uses two ways to refer to specific pages:
+ * 1) an int page index
+ * 2) an OUString identifier
+ *
+ * Qt's QWizard widget used by this class uses an int id to refer to pages.
+ * This concept of an id does not match the index concept that weld::Assistang 
uses.
+ * (The id generally does not match an index in the range between 0 and the 
number of pages - 1.)
+ *
+ * Instead, 1) is mapped to a custom QObject property and for 2), the 
QObject::objectName
+ * of the QWizardPage objects is used.
+ */
 class QtInstanceAssistant : public QtInstanceDialog, public virtual 
weld::Assistant
 {
     Q_OBJECT
@@ -44,6 +58,11 @@ public:
 
 private:
     QWizardPage* page(const OUString& rIdent) const;
+    QWizardPage* page(int nPageIndex) const;
+
+    // get/set the page index as used in the weld::Assistant API
+    static int pageIndex(QWizardPage& rPage);
+    static void setPageIndex(QWizardPage& rPage, int nIndex);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt5/QtInstanceAssistant.cxx b/vcl/qt5/QtInstanceAssistant.cxx
index 12d1a51816c2..2f04d0887f89 100644
--- a/vcl/qt5/QtInstanceAssistant.cxx
+++ b/vcl/qt5/QtInstanceAssistant.cxx
@@ -12,6 +12,11 @@
 
 #include <vcl/qt/QtUtils.hxx>
 
+// Name of QObject property set on QWizardPage objects for the page
+// index as used in the weld::Assistant API.
+// This is different from the page id as used in the QWizard API
+const char* const PROPERTY_PAGE_INDEX = "page-index";
+
 QtInstanceAssistant::QtInstanceAssistant(QWizard* pWizard)
     : QtInstanceDialog(pWizard)
     , m_pWizard(pWizard)
@@ -23,10 +28,13 @@ int QtInstanceAssistant::get_current_page() const
 {
     SolarMutexGuard g;
 
-    int nPage = 0;
-    GetQtInstance().RunInMainThread([&] { nPage = m_pWizard->currentId(); });
+    int nPageIndex = -1;
+    GetQtInstance().RunInMainThread([&] {
+        if (QWizardPage* pPage = m_pWizard->page(m_pWizard->currentId()))
+            nPageIndex = pageIndex(*pPage);
+    });
 
-    return nPage;
+    return nPageIndex;
 }
 
 int QtInstanceAssistant::get_n_pages() const
@@ -45,7 +53,7 @@ OUString QtInstanceAssistant::get_page_ident(int nPage) const
 
     OUString sId;
     GetQtInstance().RunInMainThread([&] {
-        if (QWizardPage* pPage = m_pWizard->page(nPage))
+        if (QWizardPage* pPage = page(nPage))
             sId = toOUString(pPage->objectName());
     });
 
@@ -71,19 +79,24 @@ void QtInstanceAssistant::set_current_page(int nPage)
 
     GetQtInstance().RunInMainThread([&] {
 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
-        m_pWizard->setCurrentId(nPage);
-#else
-        int nCurrentPage = m_pWizard->currentId();
-        if (nPage > nCurrentPage)
-        {
-            for (int i = 0; i < nPage - nCurrentPage; ++i)
-                m_pWizard->next();
-        }
-        else if (nPage < nCurrentPage)
+        const QList<int> aPageIds = m_pWizard->pageIds();
+        for (int nId : aPageIds)
         {
-            for (int i = 0; i < nPage - nCurrentPage; ++i)
-                m_pWizard->back();
+            QWizardPage* pPage = m_pWizard->page(nId);
+            assert(pPage);
+            if (pageIndex(*pPage) == nPage)
+            {
+                m_pWizard->setCurrentId(nId);
+                return;
+            }
         }
+#else
+        // QWizard::setCurrentId only available from 6.4 on
+        // start with first page and advance until the expected one is the 
current one
+        m_pWizard->restart();
+        int nCurrentId = m_pWizard->currentId();
+        while (nCurrentId != -1 && pageIndex(*m_pWizard->page(nCurrentId)) != 
nPage)
+            m_pWizard->next();
 #endif
     });
 }
@@ -94,21 +107,53 @@ void QtInstanceAssistant::set_current_page(const OUString& 
rIdent)
 
     GetQtInstance().RunInMainThread([&] {
         const QList<int> aPageIds = m_pWizard->pageIds();
-        for (int nPage : aPageIds)
+        for (int nPageId : aPageIds)
         {
-            QWizardPage* pPage = m_pWizard->page(nPage);
+            QWizardPage* pPage = m_pWizard->page(nPageId);
             if (pPage && pPage->objectName() == toQString(rIdent))
             {
-                set_current_page(nPage);
+                set_current_page(nPageId);
                 break;
             }
         }
     });
 }
 
-void QtInstanceAssistant::set_page_index(const OUString&, int)
+void QtInstanceAssistant::set_page_index(const OUString& rIdent, int nIndex)
 {
-    assert(false && "not implemented yet");
+    SolarMutexGuard g;
+
+    GetQtInstance().RunInMainThread([&] {
+        const QString sIdent = toQString(rIdent);
+
+        // QWizard page IDs are different from weld::Assistant page indices
+        // use a vector where items will be sorted by page index for help
+        QList<QWizardPage*> aPages;
+        int nOldIndex = -1;
+        const QList<int> aPageIds = m_pWizard->pageIds();
+        for (int nPageId : aPageIds)
+        {
+            QWizardPage* pPage = m_pWizard->page(nPageId);
+            assert(pPage);
+            aPages.push_back(pPage);
+            if (pPage->objectName() == sIdent)
+                nOldIndex = pageIndex(*pPage);
+        }
+
+        assert(nOldIndex >= 0 && "no page with the given identifier");
+
+        // sort vector by page index
+        std::sort(aPages.begin(), aPages.end(), [](QWizardPage* pFirst, 
QWizardPage* pSecond) {
+            return pageIndex(*pFirst) < pageIndex(*pSecond);
+        });
+        // remove and reinsert the page at new position
+        QWizardPage* pPage = aPages.takeAt(nOldIndex);
+        aPages.insert(nIndex, pPage);
+
+        // update index property for all pages
+        for (qsizetype i = 0; i < aPages.size(); ++i)
+            setPageIndex(*aPages.at(i), i);
+    });
 }
 
 void QtInstanceAssistant::set_page_title(const OUString& rIdent, const 
OUString& rTitle)
@@ -153,9 +198,11 @@ weld::Container* QtInstanceAssistant::append_page(const 
OUString& rIdent)
     GetQtInstance().RunInMainThread([&] {
         QWizardPage* pNewPage = new QWizardPage;
         pNewPage->setObjectName(toQString(rIdent));
-        // ensure that QWizard page ID matches page index
-        const int nPageId = m_pWizard->pageIds().size();
-        m_pWizard->setPage(nPageId, pNewPage);
+
+        const int nPageIndex = m_pWizard->pageIds().size();
+        setPageIndex(*pNewPage, nPageIndex);
+
+        m_pWizard->addPage(pNewPage);
 
         m_aPages.emplace_back(new QtInstanceContainer(pNewPage));
         pContainer = m_aPages.back().get();
@@ -187,4 +234,29 @@ QWizardPage* QtInstanceAssistant::page(const OUString& 
rIdent) const
     return nullptr;
 }
 
+QWizardPage* QtInstanceAssistant::page(int nPageIndex) const
+{
+    const QList<int> aPageIds = m_pWizard->pageIds();
+    for (int nId : aPageIds)
+    {
+        QWizardPage* pPage = m_pWizard->page(nId);
+        if (pPage && pageIndex(*pPage) == nPageIndex)
+            return pPage;
+    }
+
+    return nullptr;
+}
+
+int QtInstanceAssistant::pageIndex(QWizardPage& rPage)
+{
+    const QVariant aPageProperty = rPage.property(PROPERTY_PAGE_INDEX);
+    assert(aPageProperty.isValid() && aPageProperty.canConvert<int>());
+    return aPageProperty.toInt();
+}
+
+void QtInstanceAssistant::setPageIndex(QWizardPage& rPage, int nIndex)
+{
+    rPage.setProperty(PROPERTY_PAGE_INDEX, nIndex);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to