Files
libreoffice/vcl/qt5/QtBuilder.cxx

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

743 lines
26 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
/*
* 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 <QtBuilder.hxx>
#include <QtDoubleSpinBox.hxx>
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
#include <QtExpander.hxx>
#include <QtInstanceLinkButton.hxx>
#include <QtInstanceMessageDialog.hxx>
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
#include <QtInstanceNotebook.hxx>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
#include <QtTools.hxx>
#include <rtl/ustrbuf.hxx>
#include <vcl/qt/QtUtils.hxx>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
#include <QtWidgets/QDialog>
#include <QtWidgets/QDialogButtonBox>
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
#include <QtWidgets/QLayout>
#include <QtWidgets/QPlainTextEdit>
#include <QtWidgets/QProgressBar>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
#include <QtWidgets/QPushButton>
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
#include <QtWidgets/QRadioButton>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QTreeView>
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
namespace
{
QString convertAccelerator(const OUString& rText)
{
// preserve literal '&'s and use '&' instead of '_' for the accelerator
return toQString(rText.replaceAll("&", "&&").replace('_', '&'));
}
}
QtBuilder::QtBuilder(QObject* pParent, std::u16string_view sUIRoot, const OUString& rUIFile)
: WidgetBuilder(sUIRoot, rUIFile, false)
{
processUIFile(pParent);
}
QtBuilder::~QtBuilder() {}
QObject* QtBuilder::get_by_name(std::u16string_view sID)
{
for (auto const& child : m_aChildren)
{
if (child.m_sID == sID)
return child.m_pWindow;
}
return nullptr;
}
void QtBuilder::insertComboBoxOrListBoxItems(QObject* pObject, stringmap& rMap,
const std::vector<ComboBoxTextItem>& rItems)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
if (QComboBox* pComboBox = qobject_cast<QComboBox*>(pObject))
{
for (const ComboBoxTextItem& rItem : rItems)
{
QVariant aUserData;
if (!rItem.m_sId.isEmpty())
aUserData = QVariant::fromValue(toQString(rItem.m_sId));
pComboBox->addItem(toQString(rItem.m_sItem), aUserData);
}
const int nActiveId = BuilderBase::extractActive(rMap);
pComboBox->setCurrentIndex(nActiveId);
return;
}
assert(false && "list boxes are not supported yet");
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
QObject* QtBuilder::insertObject(QObject* pParent, const OUString& rClass, std::string_view sType,
const OUString& rID, stringmap& rProps, stringmap&, stringmap&)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
QObject* pCurrentChild = nullptr;
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
pCurrentChild = makeObject(pParent, rClass, sType, rID, rProps);
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
setProperties(pCurrentChild, rProps);
rProps.clear();
return pCurrentChild;
}
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
QObject* QtBuilder::makeObject(QObject* pParent, std::u16string_view sName, std::string_view sType,
const OUString& sID, stringmap& rMap)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
// ignore placeholders
if (sName.empty())
return nullptr;
// nothing to do for these
if (sName == u"GtkCellRendererText" || sName == u"GtkTreeSelection")
return nullptr;
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
QWidget* pParentWidget = qobject_cast<QWidget*>(pParent);
QLayout* pParentLayout = qobject_cast<QLayout*>(pParent);
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
QObject* pObject = nullptr;
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
// in case a QLayout is created, an additional QWidget parent
// will also be created because that is needed for QtInstanceContainer
QWidget* pLayoutParentWidget = nullptr;
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
if (sName == u"GtkMessageDialog")
{
pObject = new QMessageBox(pParentWidget);
}
else if (sName == u"GtkBox")
{
// for a QMessageBox, return the existing layout instead of creating a new one
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pParent))
{
pObject = pMessageBox->layout();
assert(pObject && "QMessageBox has no layout");
}
else
{
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
QWidget* pBoxParentWidget = pParentWidget;
// Unless this is the direct GtkBox child of a GtkDialog, create a parent widget
// that can be used to create a QtInstanceContainer for this box
if (!qobject_cast<QDialog*>(pParentWidget))
{
pLayoutParentWidget = new QWidget(pParentWidget);
pBoxParentWidget = pLayoutParentWidget;
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
const bool bVertical = hasOrientationVertical(rMap);
if (bVertical)
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
pObject = new QVBoxLayout(pBoxParentWidget);
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
else
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
pObject = new QHBoxLayout(pBoxParentWidget);
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
}
else if (sName == u"GtkButtonBox")
{
QWidget* pTopLevel = windowForObject(pParent);
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);
assert(pButtonBox && "Could not find QMessageBox's button box");
pObject = pButtonBox;
// skip adding to layout below, button box is already contained in dialog
pParentLayout = nullptr;
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
else
{
QDialogButtonBox* pButtonBox = new QDialogButtonBox(pParentWidget);
if (hasOrientationVertical(rMap))
pButtonBox->setOrientation(Qt::Vertical);
pObject = pButtonBox;
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
}
else if (sName == u"GtkButton")
{
if (QDialogButtonBox* pButtonBox = qobject_cast<QDialogButtonBox*>(pParentWidget))
{
pObject = pButtonBox->addButton("", QDialogButtonBox::NoRole);
// for message boxes, avoid implicit standard buttons in addition to those explicitly added
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pParentWidget->window()))
pMessageBox->setStandardButtons(QMessageBox::NoButton);
}
else
{
pObject = new QPushButton(pParentWidget);
}
}
else if (sName == u"GtkCheckButton")
{
pObject = new QCheckBox(pParentWidget);
}
else if (sName == u"GtkComboBoxText")
{
QComboBox* pComboBox = new QComboBox(pParentWidget);
pComboBox->setEditable(extractEntry(rMap));
pObject = pComboBox;
}
else if (sName == u"GtkDialog")
{
pObject = new QDialog(pParentWidget);
}
else if (sName == u"GtkDrawingArea")
{
pObject = new QLabel(pParentWidget);
}
else if (sName == u"GtkEntry")
{
QLineEdit* pLineEdit = new QLineEdit(pParentWidget);
auto aIt = rMap.find(u"visibility"_ustr);
if (aIt != rMap.end() && !toBool(aIt->second))
pLineEdit->setEchoMode(QLineEdit::Password);
pObject = pLineEdit;
}
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
else if (sName == u"GtkExpander")
{
pObject = new QtExpander(pParentWidget);
}
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
else if (sName == u"GtkFrame")
{
pObject = new QGroupBox(pParentWidget);
}
else if (sName == u"GtkGrid")
{
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
pLayoutParentWidget = new QWidget(pParentWidget);
pObject = new QGridLayout(pLayoutParentWidget);
}
else if (sName == u"GtkImage")
{
QLabel* pLabel = new QLabel(pParentWidget);
const OUString sIconName = extractIconName(rMap);
if (!sIconName.isEmpty())
{
const Image aImage = loadThemeImage(sIconName);
pLabel->setPixmap(toQPixmap(aImage));
}
pObject = pLabel;
}
else if (sName == u"GtkLabel")
{
QLabel* pLabel = new QLabel(pParentWidget);
setLabelProperties(*pLabel, rMap);
tdf#130857 qt a11y weld: Set "buddy" (mnemonic widget) Based on previous commits Change-Id: I878eec7be5e82fac3e1b944d7fed7bf6711744ce Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:04:08 2024 +0200 tdf#130857 VclBuilder: Move mnemonic-widget bookkeeping to base class and Change-Id: I32c922f91e5e1d06c003e6d26a4342cbb98942e1 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:18:17 2024 +0200 tdf#130857 VclBuilder: Extract setMnemonicWidget helper + call from base , implement handling for mnemonic widgets for labels for native Qt widgets in QtBuilder: * call BuilderBase::extractMnemonicWidget when processing a "GtkLabel" object, in the same way that VclBuilder does that. * implement actually setting the mnemonic widget by calling QLabel::setBuddy [1] in QtBuilder::setMnemonicWidget to set the "buddy" (mnemonic widget) This makes Orca in a WIP branch to support a native qt6 "Alt Text" dialog announce the label text as well when the corresponding QLineEdit/QPlainTextEdit receives focus, as setting the buddy also ensures that the accessible labelledy-by/label-for relations get reported on the AT-SPI layer, see also commit 09789838bbbe57d207a66532b38cbba67ec59d70 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 21:39:44 2024 +0200 tdf#119931: cui a11y: Specify mnenomic-widget in "Alt Text" dialog which describes the scenario a bit more for the gtk3 variant. [1] https://doc.qt.io/qt-6/qlabel.html#setBuddy Change-Id: Iba1e766c0f2c5162beb5b938c134afab0dac68b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174510 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 22:56:05 +02:00
extractMnemonicWidget(sID, rMap);
pObject = pLabel;
}
else if (sName == u"GtkLevelBar" || sName == u"GtkProgressBar")
{
QProgressBar* pProgressBar = new QProgressBar(pParentWidget);
// don't show text (progress in percent) by default
pProgressBar->setTextVisible(false);
pObject = pProgressBar;
}
else if (sName == u"GtkLinkButton")
{
QtHyperlinkLabel* pLabel = new QtHyperlinkLabel(pParentWidget);
if (rMap.contains(u"label"_ustr))
pLabel->setDisplayText(toQString(rMap[u"label"_ustr]));
if (rMap.contains(u"uri"_ustr))
pLabel->setUri(toQString(rMap[u"uri"_ustr]));
pObject = pLabel;
}
else if (sName == u"GtkNotebook")
{
pObject = new QTabWidget(pParentWidget);
}
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
else if (sName == u"GtkRadioButton")
{
pObject = new QRadioButton(pParentWidget);
}
else if (sName == u"GtkScrolledWindow")
{
pObject = new QScrollArea(pParentWidget);
}
else if (sName == u"GtkSeparator")
{
const bool bVertical = hasOrientationVertical(rMap);
QFrame* pFrame = new QFrame(pParentWidget);
pFrame->setFrameShape(bVertical ? QFrame::VLine : QFrame::HLine);
pObject = pFrame;
}
else if (sName == u"GtkSpinButton")
{
QtDoubleSpinBox* pSpinBox = new QtDoubleSpinBox(pParentWidget);
setSpinButtonProperties(*pSpinBox, rMap);
pObject = pSpinBox;
}
else if (sName == u"GtkTextView")
{
pObject = new QPlainTextEdit(pParentWidget);
}
else if (sName == u"GtkTreeView")
{
QTreeView* pTreeView = new QTreeView(pParentWidget);
pTreeView->setModel(new QStandardItemModel(pTreeView));
pTreeView->setHeaderHidden(!extractHeadersVisible(rMap));
pTreeView->setRootIsDecorated(extractShowExpanders(rMap));
pObject = pTreeView;
}
else if (sName == u"GtkTreeViewColumn")
{
QTreeView* pTreeView = qobject_cast<QTreeView*>(pParentWidget);
assert(pTreeView && "Tree view column doesn't have a tree view parent");
QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(pTreeView->model());
assert(pModel && "Tree view doesn't have QStandardItemModel set");
const int nCol = pModel->columnCount();
pModel->insertColumn(nCol);
pModel->setHeaderData(nCol, Qt::Horizontal, toQString(extractTitle(rMap)));
// nothing else to do, return tree view parent for the widget
return pTreeView;
}
else
{
SAL_WARN("vcl.qt", "Widget type not supported yet: "
<< OUStringToOString(sName, RTL_TEXTENCODING_UTF8));
assert(false && "Widget type not supported yet");
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
QWidget* pWidget = qobject_cast<QWidget*>(pObject);
if (!pWidget)
pWidget = pLayoutParentWidget;
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
QTabWidget* pParentTabWidget = qobject_cast<QTabWidget*>(pParentWidget);
if (pParentTabWidget)
{
// remove QTabWidget child widget, set via QTabWidget::addTab instead
assert(pWidget);
pWidget->setParent(nullptr);
// initially, add tab with empty label, QtBuilder::applyTabChildProperties will evaluate actual one
pParentTabWidget->addTab(pWidget, QStringLiteral());
// unset pParentWidget to not create a layout below
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
pParentWidget = nullptr;
}
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
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");
}
}
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
if (pWidget)
{
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
if (!pParentLayout && pParentWidget)
{
// if the parent is a widget, use the widget's layout, and ensure it has one set
pParentLayout = pParentWidget->layout();
if (!pParentLayout)
pParentLayout = new QVBoxLayout(pParentWidget);
}
// add widget to parent layout
if (pParentLayout)
pParentLayout->addWidget(pWidget);
QtInstanceWidget::setHelpId(*pWidget, getHelpRoot() + sID);
pWidget->setToolTip(toQString(extractTooltipText(rMap)));
pWidget->setVisible(extractVisible(rMap));
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
// Set GtkBuilder ID as accessible ID
pWidget->setAccessibleIdentifier(toQString(sID));
#endif
}
else if (QLayout* pLayout = qobject_cast<QLayout*>(pObject))
{
// add layout to parent layout
if (QBoxLayout* pParentBoxLayout = qobject_cast<QBoxLayout*>(pParentLayout))
pParentBoxLayout->addLayout(pLayout);
else if (QGridLayout* pParentGridLayout = qobject_cast<QGridLayout*>(pParentLayout))
pParentGridLayout->addLayout(pLayout, pParentGridLayout->rowCount(), 0);
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
m_aChildren.emplace_back(sID, pObject);
return pObject;
}
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
void QtBuilder::tweakInsertedChild(QObject* pParent, QObject* pCurrentChild, std::string_view sType,
std::string_view sInternalChild)
tdf#130857 qt weld: Ensure dialog button box is last in layout For QDialog, make sure that if a button box is included in the dialog's layout, that this is the last item in the layout, by removing from the layout and adding it at the end again. I don't see any explicit child index explicitly being set in the .ui file for the "Help" -> "License Information" dialog ("sfx/ui/licensedialog.ui"). Potentially GTK implicitly visually makes the dialog's button box the last item in the dialog. Corresponding child is this one: <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> Potentially the `<child internal-child="action_area">` identifies this as the dialog's button box that should be last, at least dialog newly created in glade also has that set. For QMessageBox, which is a QDialog subclass, this special handling is not needed, as its default button box is used, which is already at the right place. This addresses the first aspect mentioned in previous commit: Change-Id: Ic9393755ec474f77ff22a1115e3cccba9d7b26cb Author: Michael Weghorn <m.weghorn@posteo.de> Date: Sat Sep 28 00:07:28 2024 +0200 tdf#130857 qt weld: Add initial support for dialog and label > However, currently buttons and the label with the text > are in the wrong order (i.e. buttons are above the text) Still missing: > and clicking the buttons doesn't yet have any effect. Change-Id: Id991551548c1e54fdf2e169886a6c67fc307931f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174077 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-09-28 00:26:52 +02:00
{
if (sInternalChild == "entry" && qobject_cast<QComboBox*>(pParent))
{
// an editable GtkComboBox has an internal GtkEntry child,
// but QComboBox doesn't need a separate widget for it, so
// delete it
deleteObject(pCurrentChild);
}
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
if (sType == "label")
{
if (QLabel* pLabel = qobject_cast<QLabel*>(pCurrentChild))
{
if (QGroupBox* pGroupBox = qobject_cast<QGroupBox*>(pParent))
{
// GtkFrame has a `child-type="label"` child for the GtkFrame label
// in the GtkBuilder .ui file, s. https://docs.gtk.org/gtk3/class.Frame.html
// For QGroupBox, the title can be set directly. Therefore, take over the
// title from the label and delete the separate label widget again
pGroupBox->setTitle(pLabel->text());
deleteObject(pLabel);
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
}
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 <m.weghorn@posteo.de> 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 <m.weghorn@posteo.de> Tested-by: Jenkins
2024-11-24 00:07:44 +01:00
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);
}
tdf#130857 qt weld: Create QGroupBox for "GtkFrame" Handle "GtkFrame" objects from .ui files and create a QGroupBox [1] for them. While there's also a QFrame class in Qt, QGroupBox seems more suitable, as it allows setting a title, while QFrame doesn't. Add special handling for the label child of the "GtkFrame". Quoting from the GtkFrame doc [2]: > The GtkFrame implementation of the GtkBuildable interface supports > placing a child in the label position by specifying “label” as the > “type” attribute of a <child> element. A normal content child can be > specified without specifying a <child> type attribute. Example for a frame label in chart2/uiconfig/ui/insertaxisdlg.ui: <child type="label"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="label" translatable="yes" context="insertaxisdlg|label1">Axes</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> In order to set the label's text as the text for the QGroupBox, identify that label child in QtBuilder::tweakInsertedChild, take over its text as the QGroupBox title, and mark the label for deletion, as it's no longer needed, since the QGroupBox handles its title itself from then on. [1] https://doc.qt.io/qt-6/qgroupbox.html [2] https://docs.gtk.org/gtk4/class.Frame.html Change-Id: Ie917a501466bad8821fc3e7f5049db7c1a56995f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174465 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 10:38:32 +02:00
}
}
tdf#130857 qt weld: Ensure dialog button box is last in layout For QDialog, make sure that if a button box is included in the dialog's layout, that this is the last item in the layout, by removing from the layout and adding it at the end again. I don't see any explicit child index explicitly being set in the .ui file for the "Help" -> "License Information" dialog ("sfx/ui/licensedialog.ui"). Potentially GTK implicitly visually makes the dialog's button box the last item in the dialog. Corresponding child is this one: <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> Potentially the `<child internal-child="action_area">` identifies this as the dialog's button box that should be last, at least dialog newly created in glade also has that set. For QMessageBox, which is a QDialog subclass, this special handling is not needed, as its default button box is used, which is already at the right place. This addresses the first aspect mentioned in previous commit: Change-Id: Ic9393755ec474f77ff22a1115e3cccba9d7b26cb Author: Michael Weghorn <m.weghorn@posteo.de> Date: Sat Sep 28 00:07:28 2024 +0200 tdf#130857 qt weld: Add initial support for dialog and label > However, currently buttons and the label with the text > are in the wrong order (i.e. buttons are above the text) Still missing: > and clicking the buttons doesn't yet have any effect. Change-Id: Id991551548c1e54fdf2e169886a6c67fc307931f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174077 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-09-28 00:26:52 +02:00
if (QDialog* pDialog = qobject_cast<QDialog*>(pCurrentChild))
{
// no action needed for QMessageBox, where the default button box is used
// and button click is handled in QtInstanceMessageDialog
tdf#130857 qt weld: Ensure dialog button box is last in layout For QDialog, make sure that if a button box is included in the dialog's layout, that this is the last item in the layout, by removing from the layout and adding it at the end again. I don't see any explicit child index explicitly being set in the .ui file for the "Help" -> "License Information" dialog ("sfx/ui/licensedialog.ui"). Potentially GTK implicitly visually makes the dialog's button box the last item in the dialog. Corresponding child is this one: <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> Potentially the `<child internal-child="action_area">` identifies this as the dialog's button box that should be last, at least dialog newly created in glade also has that set. For QMessageBox, which is a QDialog subclass, this special handling is not needed, as its default button box is used, which is already at the right place. This addresses the first aspect mentioned in previous commit: Change-Id: Ic9393755ec474f77ff22a1115e3cccba9d7b26cb Author: Michael Weghorn <m.weghorn@posteo.de> Date: Sat Sep 28 00:07:28 2024 +0200 tdf#130857 qt weld: Add initial support for dialog and label > However, currently buttons and the label with the text > are in the wrong order (i.e. buttons are above the text) Still missing: > and clicking the buttons doesn't yet have any effect. Change-Id: Id991551548c1e54fdf2e169886a6c67fc307931f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174077 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-09-28 00:26:52 +02:00
if (!qobject_cast<QMessageBox*>(pDialog))
{
if (QDialogButtonBox* pButtonBox = 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)
tdf#130857 qt weld: Ensure dialog button box is last in layout For QDialog, make sure that if a button box is included in the dialog's layout, that this is the last item in the layout, by removing from the layout and adding it at the end again. I don't see any explicit child index explicitly being set in the .ui file for the "Help" -> "License Information" dialog ("sfx/ui/licensedialog.ui"). Potentially GTK implicitly visually makes the dialog's button box the last item in the dialog. Corresponding child is this one: <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> Potentially the `<child internal-child="action_area">` identifies this as the dialog's button box that should be last, at least dialog newly created in glade also has that set. For QMessageBox, which is a QDialog subclass, this special handling is not needed, as its default button box is used, which is already at the right place. This addresses the first aspect mentioned in previous commit: Change-Id: Ic9393755ec474f77ff22a1115e3cccba9d7b26cb Author: Michael Weghorn <m.weghorn@posteo.de> Date: Sat Sep 28 00:07:28 2024 +0200 tdf#130857 qt weld: Add initial support for dialog and label > However, currently buttons and the label with the text > are in the wrong order (i.e. buttons are above the text) Still missing: > and clicking the buttons doesn't yet have any effect. Change-Id: Id991551548c1e54fdf2e169886a6c67fc307931f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174077 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-09-28 00:26:52 +02:00
QLayout* pLayout = pDialog->layout();
assert(pLayout && "dialog has no layout");
pLayout->removeWidget(pButtonBox);
pLayout->addWidget(pButtonBox);
// connect button click handler
const QList<QAbstractButton*> aButtons = pButtonBox->buttons();
for (QAbstractButton* pButton : aButtons)
{
assert(pButton);
QObject::connect(pButton, &QAbstractButton::clicked, pDialog,
[pDialog, pButton] {
QtInstanceDialog::handleButtonClick(*pDialog, *pButton);
});
}
tdf#130857 qt weld: Ensure dialog button box is last in layout For QDialog, make sure that if a button box is included in the dialog's layout, that this is the last item in the layout, by removing from the layout and adding it at the end again. I don't see any explicit child index explicitly being set in the .ui file for the "Help" -> "License Information" dialog ("sfx/ui/licensedialog.ui"). Potentially GTK implicitly visually makes the dialog's button box the last item in the dialog. Corresponding child is this one: <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> Potentially the `<child internal-child="action_area">` identifies this as the dialog's button box that should be last, at least dialog newly created in glade also has that set. For QMessageBox, which is a QDialog subclass, this special handling is not needed, as its default button box is used, which is already at the right place. This addresses the first aspect mentioned in previous commit: Change-Id: Ic9393755ec474f77ff22a1115e3cccba9d7b26cb Author: Michael Weghorn <m.weghorn@posteo.de> Date: Sat Sep 28 00:07:28 2024 +0200 tdf#130857 qt weld: Add initial support for dialog and label > However, currently buttons and the label with the text > are in the wrong order (i.e. buttons are above the text) Still missing: > and clicking the buttons doesn't yet have any effect. Change-Id: Id991551548c1e54fdf2e169886a6c67fc307931f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174077 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-09-28 00:26:52 +02:00
}
}
}
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
tdf#130857 qt a11y weld: Set "buddy" (mnemonic widget) Based on previous commits Change-Id: I878eec7be5e82fac3e1b944d7fed7bf6711744ce Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:04:08 2024 +0200 tdf#130857 VclBuilder: Move mnemonic-widget bookkeeping to base class and Change-Id: I32c922f91e5e1d06c003e6d26a4342cbb98942e1 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:18:17 2024 +0200 tdf#130857 VclBuilder: Extract setMnemonicWidget helper + call from base , implement handling for mnemonic widgets for labels for native Qt widgets in QtBuilder: * call BuilderBase::extractMnemonicWidget when processing a "GtkLabel" object, in the same way that VclBuilder does that. * implement actually setting the mnemonic widget by calling QLabel::setBuddy [1] in QtBuilder::setMnemonicWidget to set the "buddy" (mnemonic widget) This makes Orca in a WIP branch to support a native qt6 "Alt Text" dialog announce the label text as well when the corresponding QLineEdit/QPlainTextEdit receives focus, as setting the buddy also ensures that the accessible labelledy-by/label-for relations get reported on the AT-SPI layer, see also commit 09789838bbbe57d207a66532b38cbba67ec59d70 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 21:39:44 2024 +0200 tdf#119931: cui a11y: Specify mnenomic-widget in "Alt Text" dialog which describes the scenario a bit more for the gtk3 variant. [1] https://doc.qt.io/qt-6/qlabel.html#setBuddy Change-Id: Iba1e766c0f2c5162beb5b938c134afab0dac68b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174510 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 22:56:05 +02:00
void QtBuilder::setMnemonicWidget(const OUString& rLabelId, const OUString& rMnemonicWidgetId)
{
tdf#130857 qt a11y weld: Set "buddy" (mnemonic widget) Based on previous commits Change-Id: I878eec7be5e82fac3e1b944d7fed7bf6711744ce Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:04:08 2024 +0200 tdf#130857 VclBuilder: Move mnemonic-widget bookkeeping to base class and Change-Id: I32c922f91e5e1d06c003e6d26a4342cbb98942e1 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 22:18:17 2024 +0200 tdf#130857 VclBuilder: Extract setMnemonicWidget helper + call from base , implement handling for mnemonic widgets for labels for native Qt widgets in QtBuilder: * call BuilderBase::extractMnemonicWidget when processing a "GtkLabel" object, in the same way that VclBuilder does that. * implement actually setting the mnemonic widget by calling QLabel::setBuddy [1] in QtBuilder::setMnemonicWidget to set the "buddy" (mnemonic widget) This makes Orca in a WIP branch to support a native qt6 "Alt Text" dialog announce the label text as well when the corresponding QLineEdit/QPlainTextEdit receives focus, as setting the buddy also ensures that the accessible labelledy-by/label-for relations get reported on the AT-SPI layer, see also commit 09789838bbbe57d207a66532b38cbba67ec59d70 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Fri Oct 4 21:39:44 2024 +0200 tdf#119931: cui a11y: Specify mnenomic-widget in "Alt Text" dialog which describes the scenario a bit more for the gtk3 variant. [1] https://doc.qt.io/qt-6/qlabel.html#setBuddy Change-Id: Iba1e766c0f2c5162beb5b938c134afab0dac68b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174510 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-10-04 22:56:05 +02:00
QLabel* pLabel = get<QLabel>(rLabelId);
QObject* pBuddy = get_by_name(rMnemonicWidgetId);
if (!pLabel || !pBuddy || !pBuddy->isWidgetType())
return;
pLabel->setBuddy(static_cast<QWidget*>(pBuddy));
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
void QtBuilder::setPriority(QObject*, int) { SAL_WARN("vcl.qt", "Ignoring priority"); }
void QtBuilder::setContext(QObject*, std::vector<vcl::EnumContext::Context>&&)
{
SAL_WARN("vcl.qt", "Ignoring context");
}
bool QtBuilder::isHorizontalTabControl(QObject* pObject)
{
QTabWidget* pTabWidget = qobject_cast<QTabWidget*>(pObject);
if (!pTabWidget)
return false;
const QTabWidget::TabPosition ePosition = pTabWidget->tabPosition();
return ePosition == QTabWidget::TabPosition::North
|| ePosition == QTabWidget::TabPosition::South;
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
QMenu* QtBuilder::createMenu(const OUString&)
{
assert(false && "Not implemented yet");
return nullptr;
}
void QtBuilder::insertMenuObject(QMenu*, QMenu*, const OUString&, const OUString&, stringmap&,
stringmap&, accelmap&)
{
assert(false && "Not implemented yet");
}
void QtBuilder::applyAtkProperties(QObject* pObject, const stringmap& rProperties, bool)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
if (!pObject || !pObject->isWidgetType())
return;
QWidget* pWidget = static_cast<QWidget*>(pObject);
for (auto const & [ rKey, rValue ] : rProperties)
{
if (rKey == "AtkObject::accessible-description")
pWidget->setAccessibleDescription(toQString(rValue));
else if (rKey == "AtkObject::accessible-name")
pWidget->setAccessibleName(toQString(rValue));
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
void QtBuilder::applyGridPackingProperties(QWidget* pCurrentChild, QGridLayout& rGrid,
const stringmap& rPackingProperties)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
assert(pCurrentChild);
// properties not set when there's no explicit GtkGrid in the .ui file,
// like for the QGridLayout that's the (implicit) layout of a QMessageBox
if (!rPackingProperties.contains(u"left-attach"_ustr)
|| !rPackingProperties.contains(u"top-attach"_ustr))
return;
const sal_Int32 nColumn = rPackingProperties.at(u"left-attach"_ustr).toInt32();
const sal_Int32 nRow = rPackingProperties.at(u"top-attach"_ustr).toInt32();
auto aWidthIt = rPackingProperties.find(u"width"_ustr);
sal_Int32 nColumnSpan = (aWidthIt == rPackingProperties.end()) ? 1 : aWidthIt->second.toInt32();
auto aHeightIt = rPackingProperties.find(u"height"_ustr);
sal_Int32 nRowSpan = (aHeightIt == rPackingProperties.end()) ? 1 : aHeightIt->second.toInt32();
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
rGrid.removeWidget(pCurrentChild);
rGrid.addWidget(pCurrentChild, nRow, nColumn, nRowSpan, nColumnSpan);
}
void QtBuilder::applyPackingProperties(QObject* pCurrentChild, QObject* pParent,
const stringmap& rPackingProperties)
{
if (!pCurrentChild)
return;
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
QWidget* pWidget = nullptr;
if (pCurrentChild->isWidgetType())
pWidget = static_cast<QWidget*>(pCurrentChild);
else
{
QObject* pParentObject = pCurrentChild->parent();
assert(pParent && "Non-widget (i.e. layout) has no parent");
if (pParentObject->isWidgetType())
pWidget = static_cast<QWidget*>(pParentObject);
}
if (!pWidget)
return;
// check parent's parent, due to extra QWidget parents for layouts
if (QGridLayout* pGrid = qobject_cast<QGridLayout*>(pParent))
tdf#130857 qt weld: Add extra QWidget parents for layouts For "GtkBox" and "GtkGrid" objects in .ui files, don't just create the corresponding QLayout objects, but create an extra QWidget object and set the layout for that widget, i.e. use that QWidget as the parent. While this generally wouldn't be needed to properly layout/handle things in Qt, having an associated QWidget for the "GtkBox" and "GtkGrid" children is needed in order to be able to create a corresponding weld::Container (QtInstanceContainer) for these, which derives from weld::Widget. QLayout itself doesn't have the methods required to implement weld::Widget, e.g. can't be hidden or shown. Therefore, create a QWidget for these in addition, except for special cases like the top-level layout in a dialog or the dialog's button box. For QGroupBox (created for "GtkFrame" objects), this now means that the direct child is no more necessarily a layout. Just setting a QWidget as a child wouldn't suffice for proper layouting. Therefore, explicitly create a layout for parent widgets that don't have a layout set yet. Adjust QtBuilder::applyPackingProperties accordingly as well. Now, there's no more use case to call QtBuilder::applyGridPackingProperties with a QLayout for the current child. Get the corresponding QWidget parent (if there is one) before calling the method instead, and switch the param from QObject* to QWidget* to simplify the method. Having an extra widget might have the side-effect that extra spacing/margins might be used. If that turns out to be a problem, these can presumably explicitly be reduced (e.g. set to 0 for the relevant objects) as needed later. At least the 19 dialogs currently listed as supported in QtInstanceBuilder::IsUIFileSupported still look OK to me in a quick test with this commit in place. Actually making use of the newly added widgets to implement more of the QtInstanceContainer logic will be done in separate commits. Change-Id: I3d3600ddfc7883239177aafed57629c107cbdf5d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176033 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-04 19:06:15 +01:00
applyGridPackingProperties(pWidget, *pGrid, rPackingProperties);
else
SAL_WARN("vcl.qt", "QtBuilder::applyPackingProperties not yet implemented for this case");
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
void QtBuilder::applyTabChildProperties(QObject* pParent, const std::vector<OUString>& rIDs,
std::vector<vcl::EnumContext::Context>&,
stringmap& rProperties, stringmap&)
{
tdf#130857 tdf#142608 qt weld: Implement QtInstanceNotebook logic Implement all of the QtInstanceNotebook methods, see also GtkInstanceNotebook and SalInstanceNotebook for the gtk3 and VCL implementations for comparison. Unlike weld::Notebook, QTabWidget doesn't have the concept of IDs for tabs in addition to indices. Introduce a PROPERTY_TAB_PAGE_ID property that gets set on the widget of the corresponding tabs and holds the tab identifier in order to support that. Implement QtBuilder::applyTabChildProperties to set the tab label and ID property by using the newly introduced QtInstanceNotebook::setTabIdAndLabel, so only QtInstanceNotebook needs to handle that property. The weld::Container* returned by QtInstanceNotebook::get_page is owned by QtInstanceNotebook, so keep create one on demand and keep a mapping between tab pages and the corresponding weld::Container. In QtInstanceNotebook::insert_page, create a new widget and set a QVBoxLayout for now. That could be changed to use a different QLayout class in the future if that turns out to be more useful. In QtBuilder::makeObject, as the tab pages are children of the "GtkNotebook" in the .ui file, they are initially created as child widgets of the QTabWidget. However, they need to be set via QTabWidget::setTab instead, so add special handling for that case towards the end and unset the parent relationship and call that method. Change-Id: I52e11ecf053a48940b88b7e6d1e6f9ba8778d9bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176353 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-11-10 18:54:28 +01:00
QTabWidget* pTabWidget = qobject_cast<QTabWidget*>(pParent);
assert(pTabWidget && "parent must be a QTabWidget");
// set ID and label for the last inserted tab
assert(rProperties.contains(u"label"_ustr) && "Tab has no label");
QtInstanceNotebook::setTabIdAndLabel(*pTabWidget, pTabWidget->count() - 1, rIDs.front(),
rProperties.at(u"label"_ustr));
}
void QtBuilder::set_response(std::u16string_view sID, short nResponse)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
QPushButton* pPushButton = get<QPushButton>(sID);
assert(pPushButton);
pPushButton->setProperty(QtInstanceMessageDialog::PROPERTY_VCL_RESPONSE_CODE, int(nResponse));
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
void QtBuilder::deleteObject(QObject* pObject)
{
if (pObject->isWidgetType())
static_cast<QWidget*>(pObject)->hide();
pObject->deleteLater();
}
void QtBuilder::setProperties(QObject* pObject, stringmap& rProps)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
if (QMessageBox* pMessageBox = qobject_cast<QMessageBox*>(pObject))
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
for (auto const & [ rKey, rValue ] : rProps)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
if (rKey == u"text")
{
pMessageBox->setText(toQString(rValue));
}
else if (rKey == u"title")
{
pMessageBox->setWindowTitle(toQString(rValue));
}
else if (rKey == u"secondary-text")
{
pMessageBox->setInformativeText(toQString(rValue));
}
else if (rKey == u"message-type")
{
if (rValue == u"error")
pMessageBox->setIcon(QMessageBox::Critical);
else if (rValue == u"info")
pMessageBox->setIcon(QMessageBox::Information);
else if (rValue == u"question")
pMessageBox->setIcon(QMessageBox::Question);
else if (rValue == u"warning")
pMessageBox->setIcon(QMessageBox::Warning);
else
assert(false && "Unhandled message-type");
}
}
}
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
else if (qobject_cast<QCheckBox*>(pObject) || qobject_cast<QRadioButton*>(pObject))
{
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
QAbstractButton* pButton = static_cast<QAbstractButton*>(pObject);
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"active")
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
pButton->setChecked(toBool(rValue));
else if (rKey == u"label")
tdf#130857 qt weld: Add QtInstanceRadioButton Implement initial support for native radio buttons using QRadioButton: * Let QtBuilder create a QRadioButton widget when it encounters a "GtkRadioButton" object. * Let QtBuilder::setProperties also handle the QRadioButton case. Both, QRadioButton and QCheckBox derive from QAbstractButton, so reuse the existing logic for QCheckBox to set label and checked status. * Add new class QtInstanceRadioButton as a weld::RadioButton implementation that uses a QRadioButton widget. * Let QtInstanceBuilder::weld_radio_button return an instance of the new class. For now, ignore the GtkRadioButton "group" property [1] that is used to group radio buttons. QRadioButton's are automatically grouped when they have the same parent widget, which is sufficient for the case of the "Alignment" dialog in Math for which support will be declared in an upcoming commit. For more complex scenarios, the use of QButtonGroup [2] could be implemented in the future to explicitly group radio buttons, as mentioned in the QRadioButton doc [3]: > If you need multiple exclusive button groups for radio buttons that > belong to the same parent widget, put them into a QButtonGroup. [1] https://docs.gtk.org/gtk3/property.RadioButton.group.html [2] https://doc.qt.io/qt-6/qbuttongroup.html [3] https://doc.qt.io/qt-6/qradiobutton.html Change-Id: Iaf8b0fef00fc10268c09410080156e7913634ab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175639 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins
2024-10-25 13:21:55 +02:00
pButton->setText(convertAccelerator(rValue));
}
}
else if (QDialog* pDialog = qobject_cast<QDialog*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"modal")
pDialog->setModal(toBool(rValue));
else if (rKey == u"title")
pDialog->setWindowTitle(toQString(rValue));
}
}
else if (QPlainTextEdit* pTextEdit = qobject_cast<QPlainTextEdit*>(pObject))
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"accepts-tab")
pTextEdit->setTabChangesFocus(!toBool(rValue));
}
}
else if (QPushButton* pButton = qobject_cast<QPushButton*>(pObject))
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"image")
{
QLabel* pImageLabel = get<QLabel>(rValue);
assert(pImageLabel && "Button has non-existent image set");
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
pButton->setIcon(QIcon(pImageLabel->pixmap()));
#else
pButton->setIcon(QIcon(pImageLabel->pixmap(Qt::ReturnByValue)));
#endif
// parentless GtkImage in .ui file is only used for setting button
// image, so the object is no longer needed after doing so
if (!pImageLabel->parent())
deleteObject(pImageLabel);
}
else if (rKey == u"label")
{
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
pButton->setText(convertAccelerator(rValue));
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
}
}
}
void QtBuilder::setLabelProperties(QLabel& rLabel, stringmap& rProps)
{
for (auto const & [ rKey, rValue ] : rProps)
{
if (rKey == u"label")
rLabel.setText(convertAccelerator(rValue));
else if (rKey == u"wrap")
rLabel.setWordWrap(toBool(rValue));
}
}
void QtBuilder::setSpinButtonProperties(QDoubleSpinBox& rSpinBox, stringmap& rProps)
{
auto aDigitsIt = rProps.find(u"digits"_ustr);
sal_Int32 nDigits = (aDigitsIt != rProps.end()) ? aDigitsIt->second.toInt32() : 0;
rSpinBox.setDecimals(nDigits);
auto aAdjustmentIt = rProps.find("adjustment");
if (aAdjustmentIt != rProps.end())
{
const Adjustment* pAdjustment = get_adjustment_by_name(aAdjustmentIt->second);
assert(pAdjustment && "referenced adjustment doesn't exist");
for (auto const & [ rKey, rValue ] : *pAdjustment)
{
if (rKey == u"upper")
rSpinBox.setMaximum(rValue.toDouble());
else if (rKey == u"lower")
rSpinBox.setMinimum(rValue.toDouble());
else if (rKey == "value")
rSpinBox.setValue(rValue.toDouble());
else if (rKey == "step-increment")
rSpinBox.setSingleStep(rValue.toDouble());
}
}
}
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
QWidget* QtBuilder::windowForObject(QObject* pObject)
{
if (QWidget* pWidget = qobject_cast<QWidget*>(pObject))
return pWidget->window();
if (QLayout* pLayout = qobject_cast<QLayout*>(pObject))
{
if (QWidget* pParentWidget = pLayout->parentWidget())
return pParentWidget->window();
}
return nullptr;
}
QDialogButtonBox* QtBuilder::findButtonBox(QDialog* pDialog)
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
{
assert(pDialog);
QLayout* pLayout = pDialog->layout();
if (!pLayout)
return nullptr;
tdf#130857 qt weld: Implement QtBuilder + use it for first msg dialog This implements an initial QtBuilder, which is used by QtInstanceBuilder to create weld::Widget instances using native Qt widgets. This tries to be close to the VCL implementation (VclBuilder). The selected approach is based on Caolán's suggestion in [1] to rework VclBuilder to have overridable methods for widgets creation. This way, we can have common code for the UI parser but the function for widget creation is different. Qt equivalents for Gtk's widget classes in the .ui files: * GtkMessageDialog -> QMessageBox * GtkBox -> QLayout (can be QVBoxLayout/QHBoxLayout based on property in .ui file) * GtkButtonBox -> QDialogButtonBox * GtkButton -> QPushButton As QMessageBox already comes with a layout and a QDialogButtonBox, don't create new ones, but return the existing ones in QtBuilder::makeObject. This commit implements initial support for the above-mentioned widget types and adds the first message dialog to the list of supported .ui files in QtInstanceBuilder::IsUIFileSupported, so a native QMessageBox is used for it now, unless environment variable SAL_VCL_QT_NO_WELDED_WIDGETS is set when starting LibreOffice. The dialog ("modules/swriter/ui/inforeadonlydialog.ui") gets shown when taking the following steps: * start Writer * type "hello world" * select text * "Insert" -> "Section" * tick the "Protect" checkbox in the "Write Protection" section * close dialog via "Insert" button * try to type in the protected section The dialog can be dismissed using the default "OK" button. (Handling for response codes for buttons is not implemented yet, which will be needed when welding dialogs that have multiple buttons resulting in different behavior depending on what button gets clicked.) This change was originally submitted as a WIP change as part of Omkar Acharekar's Outreachy project "Implement Qt/KDE Frameworks theming using native Qt widgets" (see [2]), then further refined by Michael Weghorn. [1] https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html [2] https://lists.freedesktop.org/archives/libreoffice/2023-December/091281.html Co-authored-by: Michael Weghorn <m.weghorn@posteo.de> Change-Id: I6dd010a2138c245dc1e6d83dd08123898e9d9048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161831 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-09-25 09:48:09 +02:00
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: */