vcl/CustomTarget_qt5_moc.mk | 1 vcl/CustomTarget_qt6_moc.mk | 1 vcl/Library_vclplug_qt5.mk | 1 vcl/Library_vclplug_qt6.mk | 1 vcl/inc/qt5/QtInstanceBuilder.hxx | 2 vcl/inc/qt5/QtInstanceFormattedSpinButton.hxx | 42 +++++++++ vcl/inc/qt6/QtInstanceFormattedSpinButton.hxx | 12 ++ vcl/qt5/QtInstanceBuilder.cxx | 9 +- vcl/qt5/QtInstanceFormattedSpinButton.cxx | 117 ++++++++++++++++++++++++++ vcl/qt6/QtInstanceFormattedSpinButton.cxx | 12 ++ 10 files changed, 194 insertions(+), 4 deletions(-)
New commits: commit 2bd9ff78c7be6a66a3f4b381bf6726dcce9e2814 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Tue Feb 18 19:07:07 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Wed Feb 19 08:29:50 2025 +0100 tdf#130857 qt weld: Introduce QtInstanceFormattedSpinField This is the weld::FormattedSpinField implementation using a native Qt widget. Implementation mostly inspired by the GTK implementation in GtkInstanceFormattedSpinButton as well as QtInstanceSpinButton. What's still missing is to implement the conversion between value and text (both ways) similar to what commit 6871b55b6915396caa3e5aca7e233f6a5efc7864 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Sat Feb 15 17:47:01 2025 +0100 tdf#130857 qt weld: Implement SpinButton text <-> value conversion implemented for QtInstanceSpinButton. However, this needs more refactoring elsewhere first. Change-Id: I06647dc1b43a05dd86d4488f213d0f0c72566cd8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181847 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk index 8dd45bc52e24..45c83ba13364 100644 --- a/vcl/CustomTarget_qt5_moc.mk +++ b/vcl/CustomTarget_qt5_moc.mk @@ -24,6 +24,7 @@ $(call gb_CustomTarget_get_target,vcl/qt5) : \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceDrawingArea.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceEntry.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceExpander.moc \ + $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceFormattedSpinButton.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceGrid.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceIconView.moc \ $(gb_CustomTarget_workdir)/vcl/qt5/QtInstanceImage.moc \ diff --git a/vcl/CustomTarget_qt6_moc.mk b/vcl/CustomTarget_qt6_moc.mk index b492cecf95eb..2fc5c72a5f7d 100644 --- a/vcl/CustomTarget_qt6_moc.mk +++ b/vcl/CustomTarget_qt6_moc.mk @@ -24,6 +24,7 @@ $(call gb_CustomTarget_get_target,vcl/qt6) : \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceDrawingArea.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceEntry.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceExpander.moc \ + $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceFormattedSpinButton.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceGrid.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceIconView.moc \ $(gb_CustomTarget_workdir)/vcl/qt6/QtInstanceImage.moc \ diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk index 31b8f75076fa..1ef3fe6b1d77 100644 --- a/vcl/Library_vclplug_qt5.mk +++ b/vcl/Library_vclplug_qt5.mk @@ -109,6 +109,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ vcl/qt5/QtInstanceDrawingArea \ vcl/qt5/QtInstanceEntry \ vcl/qt5/QtInstanceExpander \ + vcl/qt5/QtInstanceFormattedSpinButton \ vcl/qt5/QtInstanceFrame \ vcl/qt5/QtInstanceGrid \ vcl/qt5/QtInstanceIconView \ diff --git a/vcl/Library_vclplug_qt6.mk b/vcl/Library_vclplug_qt6.mk index 09208e7c36af..17ee2027ee92 100644 --- a/vcl/Library_vclplug_qt6.mk +++ b/vcl/Library_vclplug_qt6.mk @@ -108,6 +108,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_qt6,\ vcl/qt6/QtInstanceDrawingArea \ vcl/qt6/QtInstanceEntry \ vcl/qt6/QtInstanceExpander \ + vcl/qt6/QtInstanceFormattedSpinButton \ vcl/qt6/QtInstanceFrame \ vcl/qt6/QtInstanceGrid \ vcl/qt6/QtInstanceIconView \ diff --git a/vcl/inc/qt5/QtInstanceBuilder.hxx b/vcl/inc/qt5/QtInstanceBuilder.hxx index 2ed75b7c4d88..e07645e36b7c 100644 --- a/vcl/inc/qt5/QtInstanceBuilder.hxx +++ b/vcl/inc/qt5/QtInstanceBuilder.hxx @@ -61,7 +61,7 @@ public: virtual std::unique_ptr<weld::MetricSpinButton> weld_metric_spin_button(const OUString& rId, FieldUnit eUnit) override; virtual std::unique_ptr<weld::FormattedSpinButton> - weld_formatted_spin_button(const OUString&) override; + weld_formatted_spin_button(const OUString& rId) override; virtual std::unique_ptr<weld::ComboBox> weld_combo_box(const OUString& rId) override; virtual std::unique_ptr<weld::EntryTreeView> weld_entry_tree_view(const OUString&, const OUString&, const OUString&) override; diff --git a/vcl/inc/qt5/QtInstanceFormattedSpinButton.hxx b/vcl/inc/qt5/QtInstanceFormattedSpinButton.hxx new file mode 100644 index 000000000000..770ac9fdb4e0 --- /dev/null +++ b/vcl/inc/qt5/QtInstanceFormattedSpinButton.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "QtDoubleSpinBox.hxx" +#include "QtInstanceEntry.hxx" + +#include <vcl/weldutils.hxx> + +class QtInstanceFormattedSpinButton : public QtInstanceEntry, + public virtual weld::FormattedSpinButton +{ + Q_OBJECT + + QtDoubleSpinBox* m_pSpinBox; + std::unique_ptr<weld::EntryFormatter> m_xOwnFormatter; + weld::EntryFormatter* m_pFormatter; + +public: + QtInstanceFormattedSpinButton(QtDoubleSpinBox* pSpinBox); + + virtual QWidget* getQWidget() const override; + + virtual Formatter& GetFormatter() override; + virtual void SetFormatter(weld::EntryFormatter* pFormatter) override; + + virtual void sync_range_from_formatter() override; + virtual void sync_value_from_formatter() override; + virtual void sync_increments_from_formatter() override; + +private Q_SLOTS: + void handleValueChanged(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/qt6/QtInstanceFormattedSpinButton.hxx b/vcl/inc/qt6/QtInstanceFormattedSpinButton.hxx new file mode 100644 index 000000000000..ddc304d8039a --- /dev/null +++ b/vcl/inc/qt6/QtInstanceFormattedSpinButton.hxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "../qt5/QtInstanceFormattedSpinButton.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index 7562ce97a310..595236874b20 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -18,6 +18,7 @@ #include <QtInstanceDrawingArea.hxx> #include <QtInstanceEntry.hxx> #include <QtInstanceExpander.hxx> +#include <QtInstanceFormattedSpinButton.hxx> #include <QtInstanceFrame.hxx> #include <QtInstanceGrid.hxx> #include <QtInstanceImage.hxx> @@ -344,10 +345,12 @@ QtInstanceBuilder::weld_metric_spin_button(const OUString& rId, FieldUnit eUnit) } std::unique_ptr<weld::FormattedSpinButton> -QtInstanceBuilder::weld_formatted_spin_button(const OUString&) +QtInstanceBuilder::weld_formatted_spin_button(const OUString& rId) { - assert(false && "Not implemented yet"); - return nullptr; + QtDoubleSpinBox* pSpinBox = m_xBuilder->get<QtDoubleSpinBox>(rId); + std::unique_ptr<weld::FormattedSpinButton> xRet( + pSpinBox ? std::make_unique<QtInstanceFormattedSpinButton>(pSpinBox) : nullptr); + return xRet; } std::unique_ptr<weld::ComboBox> QtInstanceBuilder::weld_combo_box(const OUString& rId) diff --git a/vcl/qt5/QtInstanceFormattedSpinButton.cxx b/vcl/qt5/QtInstanceFormattedSpinButton.cxx new file mode 100644 index 000000000000..eba70b74e65a --- /dev/null +++ b/vcl/qt5/QtInstanceFormattedSpinButton.cxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <QtInstanceFormattedSpinButton.hxx> +#include <QtInstanceFormattedSpinButton.moc> + +QtInstanceFormattedSpinButton::QtInstanceFormattedSpinButton(QtDoubleSpinBox* pSpinBox) + : QtInstanceEntry(pSpinBox->lineEdit()) + , m_pSpinBox(pSpinBox) +{ + assert(pSpinBox); + + connect(m_pSpinBox, QOverload<double>::of(&QtDoubleSpinBox::valueChanged), this, + &QtInstanceFormattedSpinButton::handleValueChanged); + + // While QtInstanceEntry generally takes care of handling signals + // for the spinbox's QLineEdit, this doesn't work when the value + // is changed as a result of setting a new spinbox value (e.g. + // by using the spinbox buttons), as the QLineEdit signals are blocked + // then, see QAbstractSpinBoxPrivate::updateEdit in qtbase: + // https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qabstractspinbox.cpp?id=ced47a590aeb85953a16eaf362887f14c2815c45#n1790 + // Therefore, connect the QDoubleSpinBox::textChanged signal + // to the slot that calls signal_changed() instead to ensure + // it gets called nonetheless, and disconnect from the other signal. + disconnect(pSpinBox->lineEdit(), &QLineEdit::textChanged, this, nullptr); + connect(m_pSpinBox, &QDoubleSpinBox::textChanged, this, + &QtInstanceFormattedSpinButton::handleTextChanged); +} + +QWidget* QtInstanceFormattedSpinButton::getQWidget() const { return m_pSpinBox; } + +Formatter& QtInstanceFormattedSpinButton::GetFormatter() +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (!m_pFormatter) + { + auto aFocusOutHdl = m_aFocusOutHdl; + m_aFocusOutHdl = Link<weld::Widget&, void>(); + auto aChangeHdl = m_aChangeHdl; + m_aChangeHdl = Link<weld::Entry&, void>(); + + m_xOwnFormatter = std::make_unique<weld::EntryFormatter>(*this); + m_xOwnFormatter->SetMinValue(m_pSpinBox->minimum()); + m_xOwnFormatter->SetMaxValue(m_pSpinBox->maximum()); + m_xOwnFormatter->SetSpinSize(m_pSpinBox->singleStep()); + m_xOwnFormatter->SetValue(m_pSpinBox->value()); + + m_xOwnFormatter->connect_focus_out(aFocusOutHdl); + m_xOwnFormatter->connect_changed(aChangeHdl); + + m_pFormatter = m_xOwnFormatter.get(); + } + }); + + return *m_pFormatter; +} + +void QtInstanceFormattedSpinButton::SetFormatter(weld::EntryFormatter* pFormatter) +{ + m_xOwnFormatter.reset(); + m_pFormatter = pFormatter; + sync_range_from_formatter(); + sync_value_from_formatter(); + sync_increments_from_formatter(); +} + +void QtInstanceFormattedSpinButton::sync_range_from_formatter() +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (!m_pFormatter) + return; + + const double fMin = m_pFormatter->HasMinValue() ? m_pFormatter->GetMinValue() + : std::numeric_limits<double>::lowest(); + const double fMax = m_pFormatter->HasMaxValue() ? m_pFormatter->GetMaxValue() + : std::numeric_limits<double>::max(); + m_pSpinBox->setRange(fMin, fMax); + }); +} + +void QtInstanceFormattedSpinButton::sync_value_from_formatter() +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (m_pFormatter) + m_pSpinBox->setValue(m_pFormatter->GetValue()); + }); +} + +void QtInstanceFormattedSpinButton::sync_increments_from_formatter() +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + if (m_pFormatter) + m_pSpinBox->setSingleStep(m_pFormatter->GetSpinSize()); + }); +} + +void QtInstanceFormattedSpinButton::handleValueChanged() +{ + SolarMutexGuard aGuard; + signal_value_changed(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/qt6/QtInstanceFormattedSpinButton.cxx b/vcl/qt6/QtInstanceFormattedSpinButton.cxx new file mode 100644 index 000000000000..6ac4689487cf --- /dev/null +++ b/vcl/qt6/QtInstanceFormattedSpinButton.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "../qt5/QtInstanceFormattedSpinButton.cxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */