include/vcl/weld.hxx | 54 ++++++++++++++++------- sc/source/ui/inc/navipi.hxx | 2 sc/source/ui/navipi/navipi.cxx | 19 +++----- sd/source/ui/dlg/diactrl.cxx | 26 +++++------ sd/source/ui/inc/diactrl.hxx | 2 svtools/source/dialogs/ServerDetailsControls.cxx | 2 vcl/source/app/salvtables.cxx | 4 - vcl/source/window/builder.cxx | 22 ++++----- vcl/unx/gtk3/gtkinst.cxx | 4 - 9 files changed, 78 insertions(+), 57 deletions(-)
New commits: commit 76396a371eb7dfef79963d00fea54a989f54fbbc Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Feb 15 13:44:50 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Sun Feb 16 11:11:57 2025 +0100 tdf#130857 weld: Abstract from "input"/"output" SpinButton signals So far, the weld::SpinButton logic to retrieve a value from text in its entry and (the other way around) to format a value into text to show in the entry was based on the concept of GtkSpinButton and its "input" [1] and "output" [2] signals for which handlers can be set that directly retrieve/set the text and value in the SpinButton. Continue and finish the work from previous commits Change-Id: I53df480e5b3b2e4eeb9f9fb0c24e8e735fae063b Author: Michael Weghorn <m.wegh...@posteo.de> Date: Fri Feb 14 20:38:28 2025 +0100 tdf#130857 weld: Let SpinButton output hdl only format the string and Change-Id: I4962497122b79c320f3c60e5565cd64973af6df3 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Sat Feb 15 01:19:56 2025 +0100 tdf#130857 weld: Let SpinButton::signal_output return text and Change-Id: Icb55f49cddeb1d039f4b4c8359058769cea77f14 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Sat Feb 15 11:22:54 2025 +0100 tdf#130857 weld: Let SpinButton input hdl only parse value from string to abstract away from those signals. Consider this as an implementation detail that dialog implementations don't have to deal with. It also doesn't match the approach that Qt's QSpinBox/QDoubleSpinBox uses for the value <-> text conversion. Instead, use the approach of having methods that simply convert a given value to a formatted string and vice versa, and call those from the "output" callback/handler in the GTK implementation of weld::SpinButton, GtkInstanceSpinButton, and call the method to set text/value with the returned value there. Dialogs (users of weld::SpinButton) can set a "value formatter" (a method that returns a formatted string for a given value) and a "text parser" (that returns an integer value for a given text). Part of the logic was already introduced in the above-mentioned commits. This commit adjusts the former weld::SpinButton::signal_output to take the value to format as an input parameter instead of calling weld::SpinButton::get_value itself to get the current value. Similarly, the former weld::SpinButton::signal_input now gets the text to parse as an input paramter instead of calling weld::SpinButton::get_text itself. Rename the methods to reflect the new semantics: * weld::SpinButton::signal_output -> weld::SpinButton::format_value * weld::SpinButton::signal_input -> weld::SpinButton::parse_text * weld::SpinButton::connect_output -> weld::SpinButton::set_value_formatter * weld::SpinButton::connect_input -> weld::SpinButton::set_text_parser GtkInstanceSpinButton and SalInstanceSpinButton are adjusted to pass the values accordingly, so no change in behavior is to be expected. [1] https://docs.gtk.org/gtk3/signal.SpinButton.input.html [2] https://docs.gtk.org/gtk3/signal.SpinButton.output.html Change-Id: If4cd12ef947233331a5deccba5c14a15e30a30c8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181714 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index df754db1a68a..e6d74e906dca 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1856,36 +1856,37 @@ class VCL_DLLPUBLIC SpinButton : virtual public Entry friend class ::LOKTrigger; Link<SpinButton&, void> m_aValueChangedHdl; - Link<sal_Int64, OUString> m_aOutputHdl; - Link<const OUString&, std::optional<int>> m_aInputHdl; + Link<sal_Int64, OUString> m_aFormatValueHdl; + Link<const OUString&, std::optional<int>> m_aParseTextHdl; protected: void signal_value_changed() { m_aValueChangedHdl.Call(*this); } - /** If a custom output handler (which provides a formatted string for a value) - * is set, the formatted string is set in the returned std::optional. + /** If a custom value formatter was set via <a>set_value_formatter</a>, + * that one gets called to create a text representation of the value + * and that one gets returned. * Otherwise, an empty std::optional is returned. */ - std::optional<OUString> signal_output() + std::optional<OUString> format_value(sal_Int64 nValue) { - if (!m_aOutputHdl.IsSet()) + if (!m_aFormatValueHdl.IsSet()) return {}; - const OUString sText = m_aOutputHdl.Call(get_value()); + const OUString sText = m_aFormatValueHdl.Call(nValue); return sText; } - /** If a custom input handler (which parses a value from the current text) - * is set and the current text can be parsed, this method sets that value + /** If a custom text parser (which parses a value from the given text) + * is set and the text can be parsed, this method sets that value * in <a>result</a> and returns <a>TRISTATE_TRUE</a>. * Returns <a>TRISTATE_FALSE</a> if a custom handler is set, but the text * cannot be parsed. * Returns <a>TRISTATE_INDET</a> if no custom input handler is set. */ - TriState signal_input(int* result) + TriState parse_text(const OUString& rText, int* result) { - if (!m_aInputHdl.IsSet()) + if (!m_aParseTextHdl.IsSet()) return TRISTATE_INDET; - std::optional<int> aValue = m_aInputHdl.Call(get_text()); + std::optional<int> aValue = m_aParseTextHdl.Call(rText); if (!aValue.has_value()) return TRISTATE_FALSE; @@ -1929,10 +1930,18 @@ public: void connect_value_changed(const Link<SpinButton&, void>& rLink) { m_aValueChangedHdl = rLink; } - void connect_output(const Link<sal_Int64, OUString>& rLink) { m_aOutputHdl = rLink; } - void connect_input(const Link<const OUString&, std::optional<int>>& rLink) + /** Set a value formatter that receives the value as a parameter and returns the + * text representation to display in the SpinButton. + */ + void set_value_formatter(const Link<sal_Int64, OUString>& rLink) { m_aFormatValueHdl = rLink; } + + /** Set a parser that receives the text as a parameter and returns the value + * parsed from the text, or an empty std::optional if a value cannot be + * parsed from the text. + */ + void set_text_parser(const Link<const OUString&, std::optional<int>>& rLink) { - m_aInputHdl = rLink; + m_aParseTextHdl = rLink; } sal_Int64 normalize(sal_Int64 nValue) const { return (nValue * Power10(get_digits())); } @@ -2117,8 +2126,8 @@ public: , m_xSpinButton(std::move(pSpinButton)) { update_width_chars(); - m_xSpinButton->connect_output(LINK(this, MetricSpinButton, spin_button_output)); - m_xSpinButton->connect_input(LINK(this, MetricSpinButton, spin_button_input)); + m_xSpinButton->set_value_formatter(LINK(this, MetricSpinButton, spin_button_output)); + m_xSpinButton->set_text_parser(LINK(this, MetricSpinButton, spin_button_input)); m_xSpinButton->connect_value_changed( LINK(this, MetricSpinButton, spin_button_value_changed)); m_xSpinButton->set_text(spin_button_output(m_xSpinButton->get_value())); diff --git a/sc/source/ui/navipi/navipi.cxx b/sc/source/ui/navipi/navipi.cxx index 557f648813f1..247355551fc7 100644 --- a/sc/source/ui/navipi/navipi.cxx +++ b/sc/source/ui/navipi/navipi.cxx @@ -344,8 +344,8 @@ ScNavigatorDlg::ScNavigatorDlg(SfxBindings* pB, weld::Widget* pParent, SfxNaviga m_xEdRow->connect_activate(LINK(this, ScNavigatorDlg, ExecuteRowHdl)); m_xEdCol->connect_activate(LINK(this, ScNavigatorDlg, ExecuteColHdl)); - m_xEdCol->connect_output(LINK(this, ScNavigatorDlg, FormatRowOutputHdl)); - m_xEdCol->connect_input(LINK(this, ScNavigatorDlg, ParseRowInputHdl)); + m_xEdCol->set_value_formatter(LINK(this, ScNavigatorDlg, FormatRowOutputHdl)); + m_xEdCol->set_text_parser(LINK(this, ScNavigatorDlg, ParseRowInputHdl)); m_xTbxCmd1->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl)); m_xTbxCmd2->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl)); diff --git a/sd/source/ui/dlg/diactrl.cxx b/sd/source/ui/dlg/diactrl.cxx index 0e50ba8bc288..3c99dca8cd62 100644 --- a/sd/source/ui/dlg/diactrl.cxx +++ b/sd/source/ui/dlg/diactrl.cxx @@ -65,8 +65,8 @@ SdPagesField::SdPagesField( vcl::Window* pParent, m_xWidget->set_range(1, MAX_PAGES_PER_ROW); m_xWidget->set_increments(1, 5); m_xWidget->connect_value_changed(LINK(this, SdPagesField, ModifyHdl)); - m_xWidget->connect_output(LINK(this, SdPagesField, OutputHdl)); - m_xWidget->connect_input(LINK(this, SdPagesField, spin_button_input)); + m_xWidget->set_value_formatter(LINK(this, SdPagesField, OutputHdl)); + m_xWidget->set_text_parser(LINK(this, SdPagesField, spin_button_input)); m_xWidget->connect_key_press(LINK(this, SdPagesField, KeyInputHdl)); auto width = std::max(m_xWidget->get_pixel_size(format_number(1)).Width(), diff --git a/svtools/source/dialogs/ServerDetailsControls.cxx b/svtools/source/dialogs/ServerDetailsControls.cxx index a90d308a89e0..65f15d2e10f5 100644 --- a/svtools/source/dialogs/ServerDetailsControls.cxx +++ b/svtools/source/dialogs/ServerDetailsControls.cxx @@ -35,7 +35,7 @@ using namespace com::sun::star::uno; DetailsContainer::DetailsContainer(PlaceEditDialog* pDialog) : m_pDialog(pDialog) { - m_pDialog->m_xEDPort->connect_output(LINK(this, DetailsContainer, FormatPortHdl)); + m_pDialog->m_xEDPort->set_value_formatter(LINK(this, DetailsContainer, FormatPortHdl)); } //format without thousand separator diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index b4d6a0ec18c3..c56972ffa9d2 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -5943,7 +5943,7 @@ IMPL_LINK_NOARG(SalInstanceSpinButton, LoseFocusHdl, Control&, void) { signal_va IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, LinkParamNone*, bool) { - std::optional<OUString> aText = signal_output(); + std::optional<OUString> aText = format_value(get_value()); if (!aText.has_value()) return false; @@ -5954,7 +5954,7 @@ IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, LinkParamNone*, bool) IMPL_LINK(SalInstanceSpinButton, InputHdl, sal_Int64*, pResult, TriState) { int nResult; - TriState eRet = signal_input(&nResult); + TriState eRet = parse_text(get_text(), &nResult); if (eRet == TRISTATE_TRUE) *pResult = nResult; return eRet; diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 417da140f4f5..76bb5bcafc08 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -17657,7 +17657,7 @@ private: if (m_bBlockOutput) return true; m_bFormatting = true; - std::optional<OUString> aText = signal_output(); + std::optional<OUString> aText = format_value(get_value()); if (aText.has_value()) set_text(aText.value()); m_bFormatting = false; @@ -17676,7 +17676,7 @@ private: GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); SolarMutexGuard aGuard; int result; - TriState eHandled = pThis->signal_input(&result); + TriState eHandled = pThis->parse_text(pThis->get_text(), &result); if (eHandled == TRISTATE_INDET) return 0; if (eHandled == TRISTATE_TRUE) commit 15ad64a412d80fdf05ee1783bcc277753eaa34bc Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Feb 15 11:22:54 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Sun Feb 16 11:11:49 2025 +0100 tdf#130857 weld: Let SpinButton input hdl only parse value from string Similar to how commit bbc51c66a3b499c3f4ac71e4e6f7a0f2d9984dfc Author: Michael Weghorn <m.wegh...@posteo.de> Date: Fri Feb 14 20:38:28 2025 +0100 tdf#130857 weld: Let SpinButton output hdl only format the string adjusted the logic to let weld::SpinButton::m_aOutputHdl only format a value into a string, also adjust the logic for weld::SpinButton::m_aInputHdl: Let it take a string and convert that into a value/integer, without having to retrieve the text from the SpinButton itself. As the text may not be parseable into an integer, use std::optional<int> as a return value. (An empty std::optial means that parsing failed, which was previously indicated by a return value of `false`). Besides simplifying the implementations (set via SpinButton::connect_input), this also aligns the logic more with what Qt's QDoubleSpinBox::valueFromText [1] does and thus prepares for implementing the required logic for QtInstanceSpinButton. [1] https://doc.qt.io/qt-6/qdoublespinbox.html#valueFromText Change-Id: Icb55f49cddeb1d039f4b4c8359058769cea77f14 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181713 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 964baac7c730..df754db1a68a 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1857,7 +1857,7 @@ class VCL_DLLPUBLIC SpinButton : virtual public Entry Link<SpinButton&, void> m_aValueChangedHdl; Link<sal_Int64, OUString> m_aOutputHdl; - Link<int*, bool> m_aInputHdl; + Link<const OUString&, std::optional<int>> m_aInputHdl; protected: void signal_value_changed() { m_aValueChangedHdl.Call(*this); } @@ -1874,11 +1874,23 @@ protected: return sText; } + /** If a custom input handler (which parses a value from the current text) + * is set and the current text can be parsed, this method sets that value + * in <a>result</a> and returns <a>TRISTATE_TRUE</a>. + * Returns <a>TRISTATE_FALSE</a> if a custom handler is set, but the text + * cannot be parsed. + * Returns <a>TRISTATE_INDET</a> if no custom input handler is set. + */ TriState signal_input(int* result) { if (!m_aInputHdl.IsSet()) return TRISTATE_INDET; - return m_aInputHdl.Call(result) ? TRISTATE_TRUE : TRISTATE_FALSE; + std::optional<int> aValue = m_aInputHdl.Call(get_text()); + if (!aValue.has_value()) + return TRISTATE_FALSE; + + *result = aValue.value(); + return TRISTATE_TRUE; } public: @@ -1918,7 +1930,10 @@ public: void connect_value_changed(const Link<SpinButton&, void>& rLink) { m_aValueChangedHdl = rLink; } void connect_output(const Link<sal_Int64, OUString>& rLink) { m_aOutputHdl = rLink; } - void connect_input(const Link<int*, bool>& rLink) { m_aInputHdl = rLink; } + void connect_input(const Link<const OUString&, std::optional<int>>& rLink) + { + m_aInputHdl = rLink; + } sal_Int64 normalize(sal_Int64 nValue) const { return (nValue * Power10(get_digits())); } @@ -2088,7 +2103,7 @@ class VCL_DLLPUBLIC MetricSpinButton final DECL_LINK(spin_button_value_changed, weld::SpinButton&, void); DECL_LINK(spin_button_output, sal_Int64, OUString); - DECL_LINK(spin_button_input, int* result, bool); + DECL_LINK(spin_button_input, const OUString&, std::optional<int>); void signal_value_changed() { m_aValueChangedHdl.Call(*this); } diff --git a/sc/source/ui/inc/navipi.hxx b/sc/source/ui/inc/navipi.hxx index c377ce9ead4d..50bc5795b012 100644 --- a/sc/source/ui/inc/navipi.hxx +++ b/sc/source/ui/inc/navipi.hxx @@ -132,7 +132,7 @@ private: DECL_LINK(ToolBoxDropdownClickHdl, const OUString&, void); DECL_LINK(MenuSelectHdl, const OUString&, void); DECL_STATIC_LINK(ScNavigatorDlg, FormatRowOutputHdl, sal_Int64, OUString); - DECL_LINK(ParseRowInputHdl, int*, bool); + DECL_LINK(ParseRowInputHdl, const OUString&, std::optional<int>); void UpdateButtons(); void SetCurrentCell( SCCOL nCol, SCROW Row ); diff --git a/sc/source/ui/navipi/navipi.cxx b/sc/source/ui/navipi/navipi.cxx index 6dcbe4389be3..557f648813f1 100644 --- a/sc/source/ui/navipi/navipi.cxx +++ b/sc/source/ui/navipi/navipi.cxx @@ -108,27 +108,24 @@ namespace } } -IMPL_LINK(ScNavigatorDlg, ParseRowInputHdl, int*, result, bool) +IMPL_LINK(ScNavigatorDlg, ParseRowInputHdl, const OUString&, rStrCol, std::optional<int>) { SCCOL nCol(0); - OUString aStrCol = m_xEdCol->get_text(); - - if (!aStrCol.isEmpty()) + if (!rStrCol.isEmpty()) { if (ScViewData* pData = GetViewData()) { ScDocument& rDoc = pData->GetDocument(); - if ( CharClass::isAsciiNumeric(aStrCol) ) - nCol = NumToAlpha(rDoc.GetSheetLimits(), static_cast<SCCOL>(aStrCol.toInt32())); + if ( CharClass::isAsciiNumeric(rStrCol) ) + nCol = NumToAlpha(rDoc.GetSheetLimits(), static_cast<SCCOL>(rStrCol.toInt32())); else - nCol = AlphaToNum( rDoc, aStrCol ); + nCol = AlphaToNum( rDoc, rStrCol ); } } - *result = nCol; - return true; + return std::optional<int>(nCol); } IMPL_LINK_NOARG(ScNavigatorDlg, ExecuteColHdl, weld::Entry&, bool) diff --git a/sd/source/ui/dlg/diactrl.cxx b/sd/source/ui/dlg/diactrl.cxx index c2cdcb2ecbd9..0e50ba8bc288 100644 --- a/sd/source/ui/dlg/diactrl.cxx +++ b/sd/source/ui/dlg/diactrl.cxx @@ -114,20 +114,20 @@ IMPL_STATIC_LINK(SdPagesField, OutputHdl, sal_Int64, nValue, OUString) return format_number(nValue); } -IMPL_LINK(SdPagesField, spin_button_input, int*, result, bool) +IMPL_LINK(SdPagesField, spin_button_input, const OUString&, rText, std::optional<int>) { const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); double fResult(0.0); - bool bRet = vcl::TextToValue(m_xWidget->get_text(), fResult, 0, m_xWidget->get_digits(), rLocaleData, FieldUnit::NONE); - if (bRet) - { - if (fResult > SAL_MAX_INT32) - fResult = SAL_MAX_INT32; - else if (fResult < SAL_MIN_INT32) - fResult = SAL_MIN_INT32; - *result = fResult; - } - return bRet; + bool bRet = vcl::TextToValue(rText, fResult, 0, m_xWidget->get_digits(), rLocaleData, FieldUnit::NONE); + if (!bRet) + return {}; + + if (fResult > SAL_MAX_INT32) + fResult = SAL_MAX_INT32; + else if (fResult < SAL_MIN_INT32) + fResult = SAL_MIN_INT32; + + return std::optional<int>(fResult); } IMPL_LINK_NOARG(SdPagesField, ModifyHdl, weld::SpinButton&, void) diff --git a/sd/source/ui/inc/diactrl.hxx b/sd/source/ui/inc/diactrl.hxx index caf2a0a533bb..552a424db526 100644 --- a/sd/source/ui/inc/diactrl.hxx +++ b/sd/source/ui/inc/diactrl.hxx @@ -38,7 +38,7 @@ private: DECL_LINK(ModifyHdl, weld::SpinButton&, void); DECL_STATIC_LINK(SdPagesField, OutputHdl, sal_Int64, OUString); - DECL_LINK(spin_button_input, int* result, bool); + DECL_LINK(spin_button_input, const OUString&, std::optional<int>); DECL_LINK(KeyInputHdl, const KeyEvent&, bool); public: diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index 12d5c1c4e628..41f95fe286ca 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -371,20 +371,20 @@ namespace weld return vcl::ConvertValue(nValue, 0, m_xSpinButton->get_digits(), eInUnit, eOutUnit); } - IMPL_LINK(MetricSpinButton, spin_button_input, int*, result, bool) + IMPL_LINK(MetricSpinButton, spin_button_input, const OUString&, rText, std::optional<int>) { const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); double fResult(0.0); - bool bRet = vcl::TextToValue(get_text(), fResult, 0, m_xSpinButton->get_digits(), rLocaleData, m_eSrcUnit); - if (bRet) - { - if (fResult > SAL_MAX_INT32) - fResult = SAL_MAX_INT32; - else if (fResult < SAL_MIN_INT32) - fResult = SAL_MIN_INT32; - *result = fResult; - } - return bRet; + bool bRet = vcl::TextToValue(rText, fResult, 0, m_xSpinButton->get_digits(), rLocaleData, m_eSrcUnit); + if (!bRet) + return {}; + + if (fResult > SAL_MAX_INT32) + fResult = SAL_MAX_INT32; + else if (fResult < SAL_MIN_INT32) + fResult = SAL_MIN_INT32; + + return std::optional<int>(fResult); } EntryTreeView::EntryTreeView(std::unique_ptr<Entry> xEntry, std::unique_ptr<TreeView> xTreeView)