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