vcl/CustomTarget_qt5_moc.mk | 1 vcl/CustomTarget_qt6_moc.mk | 1 vcl/Library_vclplug_qt5.mk | 1 vcl/Library_vclplug_qt6.mk | 1 vcl/inc/qt5/QtBuilder.hxx | 1 vcl/inc/qt5/QtInstanceAssistant.hxx | 47 +++++++++ vcl/inc/qt5/QtInstanceBuilder.hxx | 2 vcl/inc/qt5/QtInstanceDialog.hxx | 2 vcl/inc/qt6/QtInstanceAssistant.hxx | 12 ++ vcl/qt5/QtBuilder.cxx | 28 +---- vcl/qt5/QtInstanceAssistant.cxx | 176 ++++++++++++++++++++++++++++++++++++ vcl/qt5/QtInstanceBuilder.cxx | 9 + vcl/qt5/QtInstanceDialog.cxx | 19 +++ vcl/qt6/QtInstanceAssistant.cxx | 12 ++ 14 files changed, 286 insertions(+), 26 deletions(-)
New commits: commit 1c3234ace9473aa7fe596e892177bde47362d101 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Feb 22 20:46:14 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Sun Feb 23 10:14:35 2025 +0100 tdf#130857 qt weld: Move findButtonBox helper to QtInstanceDialog It will be reused there in an upcoming commit. Change-Id: I419d2a4d82fb179501bafe04f00bde64d256a750 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182042 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/inc/qt5/QtBuilder.hxx b/vcl/inc/qt5/QtBuilder.hxx index 35ebff8616ec..c9434ddcff47 100644 --- a/vcl/inc/qt5/QtBuilder.hxx +++ b/vcl/inc/qt5/QtBuilder.hxx @@ -108,7 +108,6 @@ private: void setSpinButtonProperties(QDoubleSpinBox& rSpinBox, stringmap& rProps); static void setTextViewProperties(QPlainTextEdit& rTextEdit, stringmap& rProps); static QWidget* windowForObject(QObject* pObject); - static QDialogButtonBox* findButtonBox(QDialog* pDialog); static void applyGridPackingProperties(QWidget* pCurrentChild, QGridLayout& rGrid, const stringmap& rPackingProperties); diff --git a/vcl/inc/qt5/QtInstanceDialog.hxx b/vcl/inc/qt5/QtInstanceDialog.hxx index 76d3558369d9..b594606d89e7 100644 --- a/vcl/inc/qt5/QtInstanceDialog.hxx +++ b/vcl/inc/qt5/QtInstanceDialog.hxx @@ -12,6 +12,7 @@ #include "QtInstanceWindow.hxx" #include <QtWidgets/QAbstractButton> +#include <QtWidgets/QDialogButtonBox> class QtInstanceDialog : public QtInstanceWindow, public virtual weld::Dialog { @@ -60,6 +61,7 @@ public: virtual std::unique_ptr<weld::Container> weld_content_area() override; + static QDialogButtonBox* findButtonBox(QDialog* pDialog); static void handleButtonClick(QDialog& rDialog, QAbstractButton& rButton); /** diff --git a/vcl/qt5/QtBuilder.cxx b/vcl/qt5/QtBuilder.cxx index 716d45f94b58..079b7988e083 100644 --- a/vcl/qt5/QtBuilder.cxx +++ b/vcl/qt5/QtBuilder.cxx @@ -169,7 +169,7 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pTopLevel)) { // for a QMessageBox, return the existing button box instead of creating a new one - QDialogButtonBox* pButtonBox = findButtonBox(pMessageBox); + QDialogButtonBox* pButtonBox = QtInstanceDialog::findButtonBox(pMessageBox); assert(pButtonBox && "Could not find QMessageBox's button box"); pObject = pButtonBox; @@ -522,7 +522,7 @@ void QtBuilder::tweakInsertedChild(QObject* pParent, QObject* pCurrentChild, std // and button click is handled in QtInstanceMessageDialog if (!qobject_cast<QMessageBox*>(pDialog)) { - if (QDialogButtonBox* pButtonBox = findButtonBox(pDialog)) + if (QDialogButtonBox* pButtonBox = QtInstanceDialog::findButtonBox(pDialog)) { // ensure that button box is the last item in QDialog's layout // (that seems to be implicitly the case for GtkDialog in GTK) @@ -938,23 +938,4 @@ QWidget* QtBuilder::windowForObject(QObject* pObject) return nullptr; } -QDialogButtonBox* QtBuilder::findButtonBox(QDialog* pDialog) -{ - assert(pDialog); - QLayout* pLayout = pDialog->layout(); - if (!pLayout) - return nullptr; - - for (int i = 0; i < pLayout->count(); i++) - { - QLayoutItem* pItem = pLayout->itemAt(i); - if (QWidget* pItemWidget = pItem->widget()) - { - if (QDialogButtonBox* pButtonBox = qobject_cast<QDialogButtonBox*>(pItemWidget)) - return pButtonBox; - } - } - return nullptr; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt5/QtInstanceDialog.cxx b/vcl/qt5/QtInstanceDialog.cxx index 0a622728fb79..98f3fb1bf744 100644 --- a/vcl/qt5/QtInstanceDialog.cxx +++ b/vcl/qt5/QtInstanceDialog.cxx @@ -204,6 +204,25 @@ void QtInstanceDialog::dialogFinished(int nResult) xRunAsyncDialog.reset(); } +QDialogButtonBox* QtInstanceDialog::findButtonBox(QDialog* pDialog) +{ + assert(pDialog); + QLayout* pLayout = pDialog->layout(); + if (!pLayout) + return nullptr; + + for (int i = 0; i < pLayout->count(); i++) + { + QLayoutItem* pItem = pLayout->itemAt(i); + if (QWidget* pItemWidget = pItem->widget()) + { + if (QDialogButtonBox* pButtonBox = qobject_cast<QDialogButtonBox*>(pItemWidget)) + return pButtonBox; + } + } + return nullptr; +} + void QtInstanceDialog::handleButtonClick(QDialog& rDialog, QAbstractButton& rButton) { SolarMutexGuard g; commit ffd236bdf85682329ed18360007c7454eb2693aa Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Feb 22 18:30:30 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Sun Feb 23 10:14:26 2025 +0100 tdf#130857 qt weld: Introduce QtInstanceAssistant Add new class QtInstanceAssistant as the weld::Assistant implementation using native Qt widgets. A QWizard is used for the widget. This commit introduces QtInstanceAssistant and adds an initial implementation for most of its methods. (Others still need to be added in the future and calling them currently triggers an assert.) While GtkAssistant [2] and weld::Assistant use indices to identify pages, QWizard uses IDs. For now, assume that those are equivalent. Some extra logic may be needed to ensure this in the future (or an implementation that is not built on this assumption). The OUString identifier used in the weld::Assistant API is something different and set as the QObject::objectName property of the pages. In QtBuilder, create a QWizard widget when encountering a "GtkAssistant" object in a .ui file. [1] https://doc.qt.io/qt-6/qwizard.html [2] https://docs.gtk.org/gtk3/class.Assistant.html Change-Id: I91b44da40736f6e61c64167d00305a1d7ba06b45 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182036 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 45c83ba13364..9a91050a9d33 100644 --- a/vcl/CustomTarget_qt5_moc.mk +++ b/vcl/CustomTarget_qt5_moc.mk @@ -16,6 +16,7 @@ $(call gb_CustomTarget_get_target,vcl/qt5) : \ $(gb_CustomTarget_workdir)/vcl/qt5/QtFilePicker.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtFrame.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstance.moc \ + $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceAssistant.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceBox.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceCheckButton.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceComboBox.moc \ diff --git a/vcl/CustomTarget_qt6_moc.mk b/vcl/CustomTarget_qt6_moc.mk index 2fc5c72a5f7d..6e8a1489d0ed 100644 --- a/vcl/CustomTarget_qt6_moc.mk +++ b/vcl/CustomTarget_qt6_moc.mk @@ -16,6 +16,7 @@ $(call gb_CustomTarget_get_target,vcl/qt6) : \ $(gb_CustomTarget_workdir)/vcl/qt6/QtFilePicker.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtFrame.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstance.moc \ + $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceAssistant.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceBox.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceCheckButton.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceComboBox.moc \ diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk index c1c4ef31482b..10aa8d90842a 100644 --- a/vcl/Library_vclplug_qt5.mk +++ b/vcl/Library_vclplug_qt5.mk @@ -99,6 +99,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ vcl/qt5/QtHyperlinkLabel \ vcl/qt5/QtInstance \ vcl/qt5/QtInstance_Print \ + vcl/qt5/QtInstanceAssistant \ vcl/qt5/QtInstanceBox \ vcl/qt5/QtInstanceBuilder \ vcl/qt5/QtInstanceButton \ diff --git a/vcl/Library_vclplug_qt6.mk b/vcl/Library_vclplug_qt6.mk index 4e2060a616c0..98ff590e92b0 100644 --- a/vcl/Library_vclplug_qt6.mk +++ b/vcl/Library_vclplug_qt6.mk @@ -98,6 +98,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt6,\ vcl/qt6/QtHyperlinkLabel \ vcl/qt6/QtInstance \ vcl/qt6/QtInstance_Print \ + vcl/qt6/QtInstanceAssistant \ vcl/qt6/QtInstanceBox \ vcl/qt6/QtInstanceBuilder \ vcl/qt6/QtInstanceButton \ diff --git a/vcl/inc/qt5/QtInstanceAssistant.hxx b/vcl/inc/qt5/QtInstanceAssistant.hxx new file mode 100644 index 000000000000..d69108c5e5ef --- /dev/null +++ b/vcl/inc/qt5/QtInstanceAssistant.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "QtInstanceDialog.hxx" + +#include <vcl/weldutils.hxx> + +#include <QtWidgets/QWizard> + +class QtInstanceAssistant : public QtInstanceDialog, public virtual weld::Assistant +{ + Q_OBJECT + + QWizard* m_pWizard; + +public: + QtInstanceAssistant(QWizard* pWizard); + + virtual int get_current_page() const override; + virtual int get_n_pages() const override; + virtual OUString get_page_ident(int nPage) const override; + virtual OUString get_current_page_ident() const override; + virtual void set_current_page(int nPage) override; + virtual void set_current_page(const OUString& rIdent) override; + virtual void set_page_index(const OUString& rIdent, int nIndex) override; + virtual void set_page_title(const OUString& rIdent, const OUString& rTitle) override; + virtual OUString get_page_title(const OUString& rIdent) const override; + virtual void set_page_sensitive(const OUString& rIdent, bool bSensitive) override; + virtual weld::Container* append_page(const OUString& rIdent) override; + + virtual void set_page_side_help_id(const OUString& rHelpId) override; + + virtual void set_page_side_image(const OUString& rImage) override; + +private: + QWizardPage* page(const OUString& rIdent) const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/qt5/QtInstanceBuilder.hxx b/vcl/inc/qt5/QtInstanceBuilder.hxx index e07645e36b7c..4625af1079d7 100644 --- a/vcl/inc/qt5/QtInstanceBuilder.hxx +++ b/vcl/inc/qt5/QtInstanceBuilder.hxx @@ -31,7 +31,7 @@ public: virtual std::unique_ptr<weld::MessageDialog> weld_message_dialog(const OUString& id) override; virtual std::unique_ptr<weld::Dialog> weld_dialog(const OUString& rId) override; - virtual std::unique_ptr<weld::Assistant> weld_assistant(const OUString&) override; + virtual std::unique_ptr<weld::Assistant> weld_assistant(const OUString& rId) override; virtual std::unique_ptr<weld::Window> create_screenshot_window() override; virtual std::unique_ptr<weld::Widget> weld_widget(const OUString& rId) override; virtual std::unique_ptr<weld::Container> weld_container(const OUString& rId) override; diff --git a/vcl/inc/qt6/QtInstanceAssistant.hxx b/vcl/inc/qt6/QtInstanceAssistant.hxx new file mode 100644 index 000000000000..28c1318f6f66 --- /dev/null +++ b/vcl/inc/qt6/QtInstanceAssistant.hxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "../qt5/QtInstanceAssistant.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt5/QtBuilder.cxx b/vcl/qt5/QtBuilder.cxx index a3c0fe35aa77..716d45f94b58 100644 --- a/vcl/qt5/QtBuilder.cxx +++ b/vcl/qt5/QtBuilder.cxx @@ -41,6 +41,7 @@ #include <QtWidgets/QToolBar> #include <QtWidgets/QToolButton> #include <QtWidgets/QTreeView> +#include <QtWidgets/QWizard> namespace { @@ -132,6 +133,10 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std: setMessageDialogProperties(*pMessageBox, rMap); pObject = pMessageBox; } + else if (sName == u"GtkAssistant") + { + pObject = new QWizard(pParentWidget); + } else if (sName == u"GtkBox") { // for a QMessageBox, return the existing layout instead of creating a new one diff --git a/vcl/qt5/QtInstanceAssistant.cxx b/vcl/qt5/QtInstanceAssistant.cxx new file mode 100644 index 000000000000..8827ff07b39d --- /dev/null +++ b/vcl/qt5/QtInstanceAssistant.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <QtInstanceAssistant.hxx> +#include <QtInstanceAssistant.moc> + +#include <vcl/qt/QtUtils.hxx> + +QtInstanceAssistant::QtInstanceAssistant(QWizard* pWizard) + : QtInstanceDialog(pWizard) + , m_pWizard(pWizard) +{ + assert(pWizard); +} + +int QtInstanceAssistant::get_current_page() const +{ + SolarMutexGuard g; + + int nPage = 0; + GetQtInstance().RunInMainThread([&] { nPage = m_pWizard->currentId(); }); + + return nPage; +} + +int QtInstanceAssistant::get_n_pages() const +{ + SolarMutexGuard g; + + int nPageCount = 0; + GetQtInstance().RunInMainThread([&] { nPageCount = m_pWizard->pageIds().size(); }); + + return nPageCount; +} + +OUString QtInstanceAssistant::get_page_ident(int nPage) const +{ + SolarMutexGuard g; + + OUString sId; + GetQtInstance().RunInMainThread([&] { + if (QWizardPage* pPage = m_pWizard->page(nPage)) + sId = toOUString(pPage->objectName()); + }); + + return sId; +} + +OUString QtInstanceAssistant::get_current_page_ident() const +{ + SolarMutexGuard g; + + OUString sId; + GetQtInstance().RunInMainThread([&] { + if (QWizardPage* pPage = m_pWizard->currentPage()) + sId = toOUString(pPage->objectName()); + }); + + return sId; +} + +void QtInstanceAssistant::set_current_page(int nPage) +{ + SolarMutexGuard g; + + 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) + { + for (int i = 0; i < nPage - nCurrentPage; ++i) + m_pWizard->back(); + } +#endif + }); +} + +void QtInstanceAssistant::set_current_page(const OUString& rIdent) +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + const QList<int> aPageIds = m_pWizard->pageIds(); + for (int nPage : aPageIds) + { + QWizardPage* pPage = m_pWizard->page(nPage); + if (pPage && pPage->objectName() == toQString(rIdent)) + { + set_current_page(nPage); + break; + } + } + }); +} + +void QtInstanceAssistant::set_page_index(const OUString&, int) +{ + assert(false && "not implemented yet"); +} + +void QtInstanceAssistant::set_page_title(const OUString& rIdent, const OUString& rTitle) +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (QWizardPage* pPage = page(rIdent)) + pPage->setTitle(toQString(rTitle)); + }); +} + +OUString QtInstanceAssistant::get_page_title(const OUString& rIdent) const +{ + SolarMutexGuard g; + + OUString sTitle; + GetQtInstance().RunInMainThread([&] { + if (QWizardPage* pPage = page(rIdent)) + sTitle = toOUString(pPage->title()); + }); + + return sTitle; +} + +void QtInstanceAssistant::set_page_sensitive(const OUString& rIdent, bool bSensitive) +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (QWizardPage* pPage = page(rIdent)) + pPage->setEnabled(bSensitive); + }); +} + +weld::Container* QtInstanceAssistant::append_page(const OUString&) +{ + assert(false && "not implemented yet"); + return nullptr; +} + +void QtInstanceAssistant::set_page_side_help_id(const OUString&) +{ + assert(false && "not implemented yet"); +} + +void QtInstanceAssistant::set_page_side_image(const OUString&) +{ + assert(false && "not implemented yet"); +} + +QWizardPage* QtInstanceAssistant::page(const OUString& rIdent) const +{ + const QList<int> aPageIds = m_pWizard->pageIds(); + for (int nPage : aPageIds) + { + QWizardPage* pPage = m_pWizard->page(nPage); + if (pPage && pPage->objectName() == toQString(rIdent)) + return pPage; + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index 5772b5d5cb63..400eb9d38e3c 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -12,6 +12,7 @@ #include <unordered_set> #include <QtBuilder.hxx> +#include <QtInstanceAssistant.hxx> #include <QtInstanceBox.hxx> #include <QtInstanceCheckButton.hxx> #include <QtInstanceComboBox.hxx> @@ -158,10 +159,12 @@ std::unique_ptr<weld::Dialog> QtInstanceBuilder::weld_dialog(const OUString& rId return xRet; } -std::unique_ptr<weld::Assistant> QtInstanceBuilder::weld_assistant(const OUString&) +std::unique_ptr<weld::Assistant> QtInstanceBuilder::weld_assistant(const OUString& rId) { - assert(false && "Not implemented yet"); - return nullptr; + QWizard* pWizard = m_xBuilder->get<QWizard>(rId); + std::unique_ptr<weld::Assistant> xRet(pWizard ? std::make_unique<QtInstanceAssistant>(pWizard) + : nullptr); + return xRet; } std::unique_ptr<weld::Window> QtInstanceBuilder::create_screenshot_window() diff --git a/vcl/qt6/QtInstanceAssistant.cxx b/vcl/qt6/QtInstanceAssistant.cxx new file mode 100644 index 000000000000..ff994f344d52 --- /dev/null +++ b/vcl/qt6/QtInstanceAssistant.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "../qt5/QtInstanceAssistant.cxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */