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 | 4 - vcl/inc/qt5/QtExpander.hxx | 37 +++++++++++ vcl/inc/qt6/QtExpander.hxx | 12 +++ vcl/qt5/QtBuilder.cxx | 32 ++++++++-- vcl/qt5/QtExpander.cxx | 60 ++++++++++++++++++ vcl/qt5/QtInstanceBuilder.cxx | 1 vcl/qt6/QtExpander.cxx | 12 +++ vcl/uiconfig/ui/openlockedquerybox.ui | 108 +++++++++++++++++----------------- 12 files changed, 210 insertions(+), 60 deletions(-)
New commits: commit 62595170ec26af556cd5d2ab3501d9e12ff28d49 Author: Michael Weghorn <[email protected]> AuthorDate: Sun Nov 24 00:35:30 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sun Nov 24 17:04:31 2024 +0100 tdf#130857 openlockedquerybox.ui: Define grid children in order Switch the order in which the children of the grid in the .ui file are defined so that the order matches the visual appearance, which makes sure that tab focus order with the Qt-based VCL plugins is correct as well in that dialog when using native Qt widgets after support for that dialog was added in Change-Id: If30736e70172c6b25feee0072c952274754aa81e Author: Michael Weghorn <[email protected]> Date: Sun Nov 24 00:22:26 2024 +0100 tdf#130857 qt weld: Support "Document in Use" dialog See commit 02692566ad9fc7c3484f8581ffa0004cd4e43987 Author: Michael Weghorn <[email protected]> Date: Thu Oct 24 17:43:35 2024 +0200 tdf#130857 optnewdictionarydialog.ui: Define focusable widgets in order for more background. Change-Id: Ie18c7b91911fea612167510e9bb098d63e1e9227 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177195 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/vcl/uiconfig/ui/openlockedquerybox.ui b/vcl/uiconfig/ui/openlockedquerybox.ui index 680698d2ecef..0b3942112b6d 100644 --- a/vcl/uiconfig/ui/openlockedquerybox.ui +++ b/vcl/uiconfig/ui/openlockedquerybox.ui @@ -133,6 +133,47 @@ receive a notification if ready.</property> <property name="top-attach">1</property> </packing> </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkButton" id="readonly"> + <property name="label" translatable="yes" context="openlockedquerybox|readonly">Open _R/O</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="notify"> + <property name="label" translatable="yes" context="openlockedquerybox|notify">_Notify</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">1</property> + </packing> + </child> <child> <object class="GtkLabel" id="OpenCopyMessage"> <property name="visible">True</property> @@ -151,6 +192,19 @@ local system.</property> <property name="top-attach">2</property> </packing> </child> + <child> + <object class="GtkButton" id="opencopy"> + <property name="label" translatable="yes" context="openlockedquerybox|opencopy">Open Co_py</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">2</property> + </packing> + </child> <child> <object class="GtkExpander" id="moredetailsexpander"> <property name="visible">True</property> @@ -187,60 +241,6 @@ local system.</property> <property name="width">2</property> </packing> </child> - <child> - <object class="GtkButton" id="opencopy"> - <property name="label" translatable="yes" context="openlockedquerybox|opencopy">Open Co_py</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="use-underline">True</property> - </object> - <packing> - <property name="left-attach">1</property> - <property name="top-attach">2</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">3</property> - <child> - <object class="GtkButton" id="readonly"> - <property name="label" translatable="yes" context="openlockedquerybox|readonly">Open _R/O</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="use-underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="notify"> - <property name="label" translatable="yes" context="openlockedquerybox|notify">_Notify</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">False</property> - <property name="use-underline">True</property> - <property name="draw-indicator">True</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="left-attach">1</property> - <property name="top-attach">1</property> - </packing> - </child> </object> <packing> <property name="expand">True</property> commit a0ca2e68177322539f554cd18eea5b7ca36ae155 Author: Michael Weghorn <[email protected]> AuthorDate: Sun Nov 24 00:22:26 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sun Nov 24 17:04:25 2024 +0100 tdf#130857 qt weld: Support "Document in Use" dialog Declare support for the dialog shown when trying to open a file that's already opened by another user (or more exactly, for which a lock file suggesting that it's opened by another user or LO instance exists). This means that native Qt widgets are used for that dialog now when using the qt5 or qt6 VCL plugin and starting LO with environment variable SAL_VCL_QT_USE_WELDED_WIDGETS=1 set. This is the first supported dialog making use of "GtkNotebook"/ QtInstanceNotebook, i.e. of what was implemented in previous commit Sample steps to see that dialog: * start Writer, save document as /tmp/test.odt * kill LibreOffice * open the lock file ( /tmp/.~lock.test.odt# ) in a text editor and change the user name to a dummy one, save. * start LO with qt6 VCL plugin and try to open the document Change-Id: If30736e70172c6b25feee0072c952274754aa81e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177194 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index 33838a2151f6..1cfb2349f431 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -71,6 +71,7 @@ bool QtInstanceBuilder::IsUIFileSupported(const OUString& rUIFile) u"sfx/ui/safemodequerydialog.ui"_ustr, u"svt/ui/printersetupdialog.ui"_ustr, u"svt/ui/restartdialog.ui"_ustr, + u"vcl/ui/openlockedquerybox.ui"_ustr, u"vcl/ui/printprogressdialog.ui"_ustr, u"writerperfect/ui/exportepub.ui"_ustr, }; commit 9ca43e71e294f778db1cd4febcfc232f2935a0b4 Author: Michael Weghorn <[email protected]> AuthorDate: Sun Nov 24 00:07:44 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Sun Nov 24 17:04:18 2024 +0100 tdf#130857 qt weld: Implement "GtkExpander" equivalent Implement support for "GtkExpander" objects in .ui files. As Qt doesn't seem to have any equivalent, add a new QtExpander class that subclasses QWidget and has a button that can be used to toggle visibility of the widget that is the GtkExpander's [1] content child. For a visual appearance similar to GtkExpander, set an icon for the button ("go-down" and "go-next" from the icon theme, which are arrows like the ones shown on a GtkExpander, at least with the Breeze icon theme). In QtBuilder, implement handling for "GtkExpander" objects: * Create an instance of the new QtExpander class. * Identify the content child, which can be distinguished from the label child by the fact that the latter has a "label" child type set, see also previous commit Change-Id: I3e308a6642d72b55d0ccc597dac716b236c22d61 Author: Michael Weghorn <[email protected]> Date: Sat Nov 23 20:54:47 2024 +0100 tdf#130857 Pass child type to WidgetBuilder::insertObject * Erase the "visible" property for the content child, as otherwise the content widget would be initially visible even if the expander is set to not be expanded. (QtExpander takes care of this, so ignore the property set in the .ui file.) * For the label child in GtkExpander, simply take over its text to QtExpander's button, then mark the label for deletion, as it's not needed otherwise. Support for the "Document in Use" dialog that has a GtkExpander and thuse makes use of this will be declared in a separate commit. [1] https://docs.gtk.org/gtk3/class.Expander.html Change-Id: Id2366834cb542eba613ea087e70f3a812d20fa89 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177193 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk index a819d4008307..184787590282 100644 --- a/vcl/CustomTarget_qt5_moc.mk +++ b/vcl/CustomTarget_qt5_moc.mk @@ -11,6 +11,7 @@ $(eval $(call gb_CustomTarget_CustomTarget,vcl/qt5)) $(call gb_CustomTarget_get_target,vcl/qt5) : \ $(gb_CustomTarget_workdir)/vcl/qt5/QtClipboard.moc \ + $(gb_CustomTarget_workdir)/vcl/qt5/QtExpander.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtFilePicker.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtFrame.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstance.moc \ diff --git a/vcl/CustomTarget_qt6_moc.mk b/vcl/CustomTarget_qt6_moc.mk index cb53e819835e..1ca3042eddc5 100644 --- a/vcl/CustomTarget_qt6_moc.mk +++ b/vcl/CustomTarget_qt6_moc.mk @@ -11,6 +11,7 @@ $(eval $(call gb_CustomTarget_CustomTarget,vcl/qt6)) $(call gb_CustomTarget_get_target,vcl/qt6) : \ $(gb_CustomTarget_workdir)/vcl/qt6/QtClipboard.moc \ + $(gb_CustomTarget_workdir)/vcl/qt6/QtExpander.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtFilePicker.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtFrame.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstance.moc \ diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk index 29dd1de6fba9..46d5eba4266a 100644 --- a/vcl/Library_vclplug_qt5.mk +++ b/vcl/Library_vclplug_qt5.mk @@ -85,6 +85,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ vcl/qt5/QtCustomStyle \ vcl/qt5/QtData \ vcl/qt5/QtDragAndDrop \ + vcl/qt5/QtExpander \ vcl/qt5/QtFilePicker \ vcl/qt5/QtFont \ vcl/qt5/QtFontFace \ diff --git a/vcl/Library_vclplug_qt6.mk b/vcl/Library_vclplug_qt6.mk index a1c28756220b..9a01ca63f7f6 100644 --- a/vcl/Library_vclplug_qt6.mk +++ b/vcl/Library_vclplug_qt6.mk @@ -84,6 +84,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt6,\ vcl/qt6/QtCustomStyle \ vcl/qt6/QtData \ vcl/qt6/QtDragAndDrop \ + vcl/qt6/QtExpander \ vcl/qt6/QtFilePicker \ vcl/qt6/QtFont \ vcl/qt6/QtFontFace \ diff --git a/vcl/inc/qt5/QtBuilder.hxx b/vcl/inc/qt5/QtBuilder.hxx index 7415b399eb57..a69158e10a8f 100644 --- a/vcl/inc/qt5/QtBuilder.hxx +++ b/vcl/inc/qt5/QtBuilder.hxx @@ -47,8 +47,8 @@ public: template <typename T = QObject> T* get(std::u16string_view sID); - QObject* makeObject(QObject* pParent, std::u16string_view sName, const OUString& sID, - stringmap& rMap); + QObject* makeObject(QObject* pParent, std::u16string_view sName, std::string_view sType, + const OUString& sID, stringmap& rMap); virtual void applyAtkProperties(QObject* pObject, const stringmap& rProperties, bool bToolbarItem) override; diff --git a/vcl/inc/qt5/QtExpander.hxx b/vcl/inc/qt5/QtExpander.hxx new file mode 100644 index 000000000000..135841c039f7 --- /dev/null +++ b/vcl/inc/qt5/QtExpander.hxx @@ -0,0 +1,37 @@ +/* -*- 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 <QtWidgets/QGridLayout> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QWidget> + +class QtExpander : public QWidget +{ + Q_OBJECT + + QPushButton* m_pButton; + QGridLayout* m_pLayout; + QWidget* m_pContentWidget; + bool m_bExpanded; + +public: + QtExpander(QWidget* pParent); + void setContentWidget(QWidget* pWidget); + void setText(const QString& rText); + +private: + void update(); + +private Q_SLOTS: + void handleButtonClick(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/qt6/QtExpander.hxx b/vcl/inc/qt6/QtExpander.hxx new file mode 100644 index 000000000000..25c0ac365af9 --- /dev/null +++ b/vcl/inc/qt6/QtExpander.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/QtExpander.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 36efe978551f..2c2d954b30c7 100644 --- a/vcl/qt5/QtBuilder.cxx +++ b/vcl/qt5/QtBuilder.cxx @@ -9,6 +9,7 @@ #include <QtBuilder.hxx> +#include <QtExpander.hxx> #include <QtInstanceLinkButton.hxx> #include <QtInstanceMessageDialog.hxx> #include <QtInstanceNotebook.hxx> @@ -83,12 +84,12 @@ void QtBuilder::insertComboBoxOrListBoxItems(QObject* pObject, stringmap& rMap, assert(false && "list boxes are not supported yet"); } -QObject* QtBuilder::insertObject(QObject* pParent, const OUString& rClass, std::string_view, +QObject* QtBuilder::insertObject(QObject* pParent, const OUString& rClass, std::string_view sType, const OUString& rID, stringmap& rProps, stringmap&, stringmap&) { QObject* pCurrentChild = nullptr; - pCurrentChild = makeObject(pParent, rClass, rID, rProps); + pCurrentChild = makeObject(pParent, rClass, sType, rID, rProps); setProperties(pCurrentChild, rProps); @@ -97,8 +98,8 @@ QObject* QtBuilder::insertObject(QObject* pParent, const OUString& rClass, std:: return pCurrentChild; } -QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, const OUString& sID, - stringmap& rMap) +QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std::string_view sType, + const OUString& sID, stringmap& rMap) { // ignore placeholders if (sName.empty()) @@ -202,6 +203,10 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, cons pObject = pLineEdit; } + else if (sName == u"GtkExpander") + { + pObject = new QtExpander(pParentWidget); + } else if (sName == u"GtkFrame") { pObject = new QGroupBox(pParentWidget); @@ -301,6 +306,16 @@ QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, cons // unset pParentWidget to not create a layout below pParentWidget = nullptr; } + else if (QtExpander* pExpander = qobject_cast<QtExpander*>(pParentWidget)) + { + // set the content (not the label) child as the expander's widget + if (sType != "label") + { + pExpander->setContentWidget(pWidget); + // erase "visible" property, QtExpander shows/hides the widget as needed + rMap.erase("visible"); + } + } if (pWidget) { @@ -364,6 +379,15 @@ void QtBuilder::tweakInsertedChild(QObject* pParent, QObject* pCurrentChild, std pGroupBox->setTitle(pLabel->text()); deleteObject(pLabel); } + else if (QtExpander* pExpander = qobject_cast<QtExpander*>(pParent)) + { + // GtkExpander has a `child-type="label"` child for the expander label + // in the GtkBuilder .ui file, s. https://docs.gtk.org/gtk3/class.Expander.html + // For QtExpander, the (button) text can be set directly. Therefore, take over + // text from the label and delete the separate label widget again + pExpander->setText(pLabel->text()); + deleteObject(pLabel); + } } } diff --git a/vcl/qt5/QtExpander.cxx b/vcl/qt5/QtExpander.cxx new file mode 100644 index 000000000000..b7e9b499f285 --- /dev/null +++ b/vcl/qt5/QtExpander.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <QtExpander.hxx> +#include <QtExpander.moc> + +QtExpander::QtExpander(QWidget* pParent) + : QWidget(pParent) + , m_pContentWidget(nullptr) + , m_bExpanded(false) +{ + m_pLayout = new QGridLayout; + setLayout(m_pLayout); + + m_pButton = new QPushButton; + m_pButton->setFlat(true); + m_pButton->setSizePolicy(QSizePolicy::Policy::Maximum, QSizePolicy::Policy::Maximum); + m_pLayout->addWidget(m_pButton, 0, 0); + m_pLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Policy::MinimumExpanding, + QSizePolicy::Policy::MinimumExpanding), + 0, 1); + + update(); + + connect(m_pButton, &QAbstractButton::clicked, this, &QtExpander::handleButtonClick); +} + +void QtExpander::setContentWidget(QWidget* pWidget) +{ + assert(pWidget); + m_pContentWidget = pWidget; + m_pLayout->addWidget(m_pContentWidget, 1, 0, 1, 2); + update(); +} + +void QtExpander::setText(const QString& rText) { m_pButton->setText(rText); } + +void QtExpander::update() +{ + const QString sIcon = m_bExpanded ? "go-down" : "go-next"; + m_pButton->setIcon(QIcon::fromTheme(sIcon)); + + if (m_pContentWidget) + m_pContentWidget->setVisible(m_bExpanded); +} + +void QtExpander::handleButtonClick() +{ + // toggle + m_bExpanded = !m_bExpanded; + update(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt6/QtExpander.cxx b/vcl/qt6/QtExpander.cxx new file mode 100644 index 000000000000..9978011ff290 --- /dev/null +++ b/vcl/qt6/QtExpander.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/QtExpander.cxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
