[Libreoffice-commits] core.git: chart2/source extensions/source framework/source include/vcl vcl/source vcl/unx

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Sun Jul 5 14:44:51 UTC 2020


 chart2/source/controller/dialogs/res_Trendline.cxx        |   22 +
 chart2/source/controller/dialogs/tp_AxisPositions.cxx     |   27 +-
 chart2/source/controller/dialogs/tp_Scale.cxx             |   76 ++++--
 extensions/source/propctrlr/usercontrol.cxx               |   47 ++-
 extensions/source/propctrlr/usercontrol.hxx               |    4 
 framework/source/uielement/spinfieldtoolbarcontroller.cxx |   62 +----
 include/vcl/fmtfield.hxx                                  |    1 
 include/vcl/formatter.hxx                                 |   12 
 include/vcl/weld.hxx                                      |   46 +--
 include/vcl/weldutils.hxx                                 |   23 +
 vcl/source/app/salvtables.cxx                             |   76 ------
 vcl/source/app/weldutils.cxx                              |   76 +++++-
 vcl/source/control/fmtfield.cxx                           |   17 -
 vcl/unx/gtk3/gtk3gtkinst.cxx                              |  173 ++++----------
 14 files changed, 332 insertions(+), 330 deletions(-)

New commits:
commit 95cfa85395f983df3ba044192b29ce0bbc5e6085
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Jul 3 12:08:02 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Sun Jul 5 16:44:09 2020 +0200

    adjust FormattedSpinButton to be driven by an EntryFormatter
    
    so we can have the same backend driving the FormattedSpinButtons as a
    FormattedEntry
    
    Change-Id: I07a472315a04787eb5fcf992cde8f758af742156
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97860
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/chart2/source/controller/dialogs/res_Trendline.cxx b/chart2/source/controller/dialogs/res_Trendline.cxx
index 0eaea7b4e163..11514a19a84a 100644
--- a/chart2/source/controller/dialogs/res_Trendline.cxx
+++ b/chart2/source/controller/dialogs/res_Trendline.cxx
@@ -24,6 +24,7 @@
 #include <svl/intitem.hxx>
 #include <svl/stritem.hxx>
 #include <svl/zforlist.hxx>
+#include <vcl/formatter.hxx>
 #include <vcl/weld.hxx>
 
 namespace chart
@@ -31,8 +32,9 @@ namespace chart
 
 static void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue )
 {
-    rFmtField.set_value(fValue);
-//TODO    rFmtField.SetDefaultValue( fValue );
+    Formatter& rFieldFormatter = rFmtField.GetFormatter();
+    rFieldFormatter.SetValue(fValue);
+    rFieldFormatter.SetDefaultValue( fValue );
 }
 
 TrendlineResources::TrendlineResources(weld::Builder& rBuilder, const SfxItemSet& rInAttrs)
@@ -66,6 +68,16 @@ TrendlineResources::TrendlineResources(weld::Builder& rBuilder, const SfxItemSet
 {
     FillValueSets();
 
+    Formatter& rForwardFormatter = m_xFmtFld_ExtrapolateForward->GetFormatter();
+    rForwardFormatter.ClearMinValue();
+    rForwardFormatter.ClearMaxValue();
+    Formatter& rBackwardFormatter = m_xFmtFld_ExtrapolateBackward->GetFormatter();
+    rBackwardFormatter.ClearMinValue();
+    rBackwardFormatter.ClearMaxValue();
+    Formatter& rInterceptFormatter = m_xFmtFld_InterceptValue->GetFormatter();
+    rInterceptFormatter.ClearMinValue();
+    rInterceptFormatter.ClearMaxValue();
+
     Link<weld::ToggleButton&,void> aLink = LINK(this, TrendlineResources, SelectTrendLine);
     m_xRB_Linear->connect_toggled( aLink );
     m_xRB_Logarithmic->connect_toggled( aLink );
@@ -369,9 +381,9 @@ IMPL_LINK_NOARG(TrendlineResources, ChangeFormattedValue, weld::FormattedSpinBut
 void TrendlineResources::SetNumFormatter( SvNumberFormatter* pFormatter )
 {
     m_pNumFormatter = pFormatter;
-    m_xFmtFld_ExtrapolateForward->set_formatter( m_pNumFormatter );
-    m_xFmtFld_ExtrapolateBackward->set_formatter( m_pNumFormatter );
-    m_xFmtFld_InterceptValue->set_formatter( m_pNumFormatter );
+    m_xFmtFld_ExtrapolateForward->GetFormatter().SetFormatter(m_pNumFormatter);
+    m_xFmtFld_ExtrapolateBackward->GetFormatter().SetFormatter(m_pNumFormatter);
+    m_xFmtFld_InterceptValue->GetFormatter().SetFormatter(m_pNumFormatter);
 }
 
 void TrendlineResources::SetNbPoints( sal_Int32 nNbPoints )
diff --git a/chart2/source/controller/dialogs/tp_AxisPositions.cxx b/chart2/source/controller/dialogs/tp_AxisPositions.cxx
index 89b8c3899881..f94f09b98690 100644
--- a/chart2/source/controller/dialogs/tp_AxisPositions.cxx
+++ b/chart2/source/controller/dialogs/tp_AxisPositions.cxx
@@ -25,6 +25,7 @@
 #include <rtl/math.hxx>
 #include <svx/chrtitem.hxx>
 #include <svl/intitem.hxx>
+#include <vcl/formatter.hxx>
 
 using namespace ::com::sun::star;
 
@@ -59,10 +60,12 @@ AxisPositionsTabPage::AxisPositionsTabPage(weld::Container* pPage, weld::DialogC
     m_xLB_CrossesAt->connect_changed(LINK(this, AxisPositionsTabPage, CrossesAtSelectHdl));
     m_xLB_PlaceLabels->connect_changed(LINK(this, AxisPositionsTabPage, PlaceLabelsSelectHdl));
 
-    const double nMin = static_cast<double>(SAL_MIN_INT64);
-    const double nMax = static_cast<double>(SAL_MAX_INT64);
-    m_xED_CrossesAt->set_range(nMin, nMax);
-    m_xED_LabelDistance->set_range(nMin, nMax);
+    Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter();
+    rCrossFormatter.ClearMinValue();
+    rCrossFormatter.ClearMaxValue();
+    Formatter& rDistanceFormatter = m_xED_CrossesAt->GetFormatter();
+    rDistanceFormatter.ClearMinValue();
+    rDistanceFormatter.ClearMaxValue();
 }
 
 AxisPositionsTabPage::~AxisPositionsTabPage()
@@ -81,7 +84,8 @@ bool AxisPositionsTabPage::FillItemSet(SfxItemSet* rOutAttrs)
     rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_POSITION, nPos+1 ));
     if( nPos==2 )
     {
-        double fCrossover = m_xED_CrossesAt->get_value();
+        Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter();
+        double fCrossover = rCrossFormatter.GetValue();
         if( m_bCrossingAxisIsCategoryAxis )
             fCrossover = m_xED_CrossesAtCategory->get_active()+1;
         rOutAttrs->Put(SvxDoubleItem(fCrossover,SCHATTR_AXIS_POSITION_VALUE));
@@ -167,7 +171,10 @@ void AxisPositionsTabPage::Reset(const SfxItemSet* rInAttrs)
             if( m_bCrossingAxisIsCategoryAxis )
                 m_xED_CrossesAtCategory->set_active( static_cast<sal_uInt16>(::rtl::math::round(fCrossover-1.0)) );
             else
-                m_xED_CrossesAt->set_value(fCrossover);
+            {
+                Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter();
+                rCrossFormatter.SetValue(fCrossover);
+            }
         }
         else
         {
@@ -251,13 +258,15 @@ DeactivateRC AxisPositionsTabPage::DeactivatePage(SfxItemSet* pItemSet)
 void AxisPositionsTabPage::SetNumFormatter( SvNumberFormatter* pFormatter )
 {
     m_pNumFormatter = pFormatter;
-    m_xED_CrossesAt->set_formatter(m_pNumFormatter);
+    Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter();
+    rCrossFormatter.SetFormatter(m_pNumFormatter);
+    rCrossFormatter.UseInputStringForFormatting();
 
     const SfxPoolItem *pPoolItem = nullptr;
     if( GetItemSet().GetItemState( SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT, true, &pPoolItem ) == SfxItemState::SET )
     {
         sal_uLong nFmt = static_cast<const SfxUInt32Item*>(pPoolItem)->GetValue();
-        m_xED_CrossesAt->set_format_key( nFmt );
+        rCrossFormatter.SetFormatKey(nFmt);
     }
 }
 
@@ -288,7 +297,7 @@ IMPL_LINK_NOARG(AxisPositionsTabPage, CrossesAtSelectHdl, weld::ComboBox&, void)
     m_xED_CrossesAtCategory->set_visible( (nPos==2) && m_bCrossingAxisIsCategoryAxis );
 
     if (m_xED_CrossesAt->get_text().isEmpty())
-        m_xED_CrossesAt->set_value(0.0);
+        m_xED_CrossesAt->GetFormatter().SetValue(0.0);
     if (m_xED_CrossesAtCategory->get_active() == -1)
         m_xED_CrossesAtCategory->set_active(0);
 
diff --git a/chart2/source/controller/dialogs/tp_Scale.cxx b/chart2/source/controller/dialogs/tp_Scale.cxx
index 0c626667790c..b9b31019803d 100644
--- a/chart2/source/controller/dialogs/tp_Scale.cxx
+++ b/chart2/source/controller/dialogs/tp_Scale.cxx
@@ -29,6 +29,7 @@
 #include <svx/chrtitem.hxx>
 #include <svl/eitem.hxx>
 #include <svl/intitem.hxx>
+#include <vcl/formatter.hxx>
 #include <vcl/weld.hxx>
 #include <svl/zformat.hxx>
 #include <vcl/svapp.hxx>
@@ -45,7 +46,7 @@ namespace
 
 void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue)
 {
-    rFmtField.set_value(fValue);
+    rFmtField.GetFormatter().SetValue(fValue);
 }
 
 }
@@ -97,12 +98,18 @@ ScaleTabPage::ScaleTabPage(weld::Container* pPage, weld::DialogController* pCont
     m_xCbxAutoOrigin->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl));
     m_xCbx_AutoTimeResolution->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl));
 
-    const double nMin = static_cast<double>(SAL_MIN_INT64);
-    const double nMax = static_cast<double>(SAL_MAX_INT64);
-    m_xFmtFldMin->set_range(nMin, nMax);
-    m_xFmtFldMax->set_range(nMin, nMax);
-    m_xFmtFldStepMain->set_range(nMin, nMax);
-    m_xFmtFldOrigin->set_range(nMin, nMax);
+    Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter();
+    rFmtFldMax.ClearMinValue();
+    rFmtFldMax.ClearMaxValue();
+    Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter();
+    rFmtFldMin.ClearMinValue();
+    rFmtFldMin.ClearMaxValue();
+    Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter();
+    rFmtFldStepMain.ClearMinValue();
+    rFmtFldStepMain.ClearMaxValue();
+    Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter();
+    rFmtFldOrigin.ClearMinValue();
+    rFmtFldOrigin.ClearMaxValue();
 
     m_xLB_AxisType->connect_changed(LINK(this, ScaleTabPage, SelectAxisTypeHdl));
 
@@ -144,7 +151,7 @@ void ScaleTabPage::EnableControls()
         if( bWasDateAxis )
             lcl_setValue( *m_xFmtFldStepMain, m_xMt_MainDateStep->get_value() );
         else
-            m_xMt_MainDateStep->set_value(m_xFmtFldStepMain->get_value());
+            m_xMt_MainDateStep->set_value(m_xFmtFldStepMain->GetFormatter().GetValue());
     }
 
     m_xFmtFldStepMain->set_visible( bValueAxis && !bDateAxis );
@@ -379,11 +386,11 @@ DeactivateRC ScaleTabPage::DeactivatePage(SfxItemSet* pItemSet)
 
     bool bDateAxis = m_nAxisType == chart2::AxisType::DATE;
 
-    sal_uInt32 nMinMaxOriginFmt = m_xFmtFldMax->get_format_key();
+    sal_uInt32 nMinMaxOriginFmt = m_xFmtFldMax->GetFormatter().GetFormatKey();
     if (pNumFormatter->GetType(nMinMaxOriginFmt) == SvNumFormatType::TEXT)
         nMinMaxOriginFmt = 0;
     // numberformat_text cause numbers to fail being numbers...  Shouldn't happen, but can.
-    sal_uInt32 nStepFmt = m_xFmtFldStepMain->get_format_key();
+    sal_uInt32 nStepFmt = m_xFmtFldStepMain->GetFormatter().GetFormatKey();
     if (pNumFormatter->GetType(nStepFmt) == SvNumFormatType::TEXT)
         nStepFmt = 0;
 
@@ -391,10 +398,10 @@ DeactivateRC ScaleTabPage::DeactivatePage(SfxItemSet* pItemSet)
     const char* pErrStrId = nullptr;
     double fDummy;
 
-    fMax = m_xFmtFldMax->get_value();
-    fMin = m_xFmtFldMin->get_value();
-    fOrigin = m_xFmtFldOrigin->get_value();
-    fStepMain = bDateAxis ? m_xMt_MainDateStep->get_value() : m_xFmtFldStepMain->get_value();
+    fMax = m_xFmtFldMax->GetFormatter().GetValue();
+    fMin = m_xFmtFldMin->GetFormatter().GetValue();
+    fOrigin = m_xFmtFldOrigin->GetFormatter().GetValue();
+    fStepMain = bDateAxis ? m_xMt_MainDateStep->get_value() : m_xFmtFldStepMain->GetFormatter().GetValue();
     nStepHelp = m_xMtStepHelp->get_value();
     m_nTimeResolution = m_xLB_TimeResolution->get_active();
     m_nMainTimeUnit = m_xLB_MainTimeUnit->get_active();
@@ -491,10 +498,26 @@ DeactivateRC ScaleTabPage::DeactivatePage(SfxItemSet* pItemSet)
 void ScaleTabPage::SetNumFormatter( SvNumberFormatter* pFormatter )
 {
     pNumFormatter = pFormatter;
-    m_xFmtFldMax->set_formatter( pNumFormatter );
-    m_xFmtFldMin->set_formatter( pNumFormatter );
-    m_xFmtFldStepMain->set_formatter( pNumFormatter );
-    m_xFmtFldOrigin->set_formatter( pNumFormatter );
+
+    Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter();
+    Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter();
+    Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter();
+    Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter();
+
+    rFmtFldMax.SetFormatter( pNumFormatter );
+    rFmtFldMin.SetFormatter( pNumFormatter );
+    rFmtFldStepMain.SetFormatter( pNumFormatter );
+    rFmtFldOrigin.SetFormatter( pNumFormatter );
+
+    // #i6278# allow more decimal places than the output format.  As
+    // the numbers shown in the edit fields are used for input, it makes more
+    // sense to display the values in the input format rather than the output
+    // format.
+    rFmtFldMax.UseInputStringForFormatting();
+    rFmtFldMin.UseInputStringForFormatting();
+    rFmtFldStepMain.UseInputStringForFormatting();
+    rFmtFldOrigin.UseInputStringForFormatting();
+
     SetNumFormat();
 }
 
@@ -507,9 +530,12 @@ void ScaleTabPage::SetNumFormat()
 
     sal_uLong nFmt = static_cast<const SfxUInt32Item*>(pPoolItem)->GetValue();
 
-    m_xFmtFldMax->set_format_key(nFmt);
-    m_xFmtFldMin->set_format_key(nFmt);
-    m_xFmtFldOrigin->set_format_key(nFmt);
+    Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter();
+    rFmtFldMax.SetFormatKey(nFmt);
+    Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter();
+    rFmtFldMin.SetFormatKey(nFmt);
+    Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter();
+    rFmtFldOrigin.SetFormatKey(nFmt);
 
     if( pNumFormatter )
     {
@@ -541,13 +567,13 @@ void ScaleTabPage::SetNumFormat()
             else
                 nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::DATE );
 
-            m_xFmtFldMax->set_format_key(nFmt);
-            m_xFmtFldMin->set_format_key(nFmt);
-            m_xFmtFldOrigin->set_format_key(nFmt);
+            rFmtFldMax.SetFormatKey(nFmt);
+            rFmtFldMin.SetFormatKey(nFmt);
+            rFmtFldOrigin.SetFormatKey(nFmt);
         }
     }
 
-    m_xFmtFldStepMain->set_format_key(nFmt);
+    m_xFmtFldStepMain->GetFormatter().SetFormatKey(nFmt);
 }
 
 void ScaleTabPage::ShowAxisOrigin( bool bShowOrigin )
diff --git a/extensions/source/propctrlr/usercontrol.cxx b/extensions/source/propctrlr/usercontrol.cxx
index cab4402c77d8..4fef3424cc7c 100644
--- a/extensions/source/propctrlr/usercontrol.cxx
+++ b/extensions/source/propctrlr/usercontrol.cxx
@@ -55,18 +55,19 @@ namespace pcr
 
     void OFormatSampleControl::SetFormatSupplier( const SvNumberFormatsSupplierObj* pSupplier )
     {
+        Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
         if (pSupplier)
         {
-            m_xSpinButton->treat_as_number(true);
+            rFieldFormatter.TreatAsNumber(true);
 
             SvNumberFormatter* pFormatter = pSupplier->GetNumberFormatter();
-            m_xSpinButton->set_formatter(pFormatter);
-            m_xSpinButton->set_value( 1234.56789 );
+            rFieldFormatter.SetFormatter(pFormatter);
+            rFieldFormatter.SetValue( 1234.56789 );
         }
         else
         {
-            m_xSpinButton->treat_as_number(false);
-            m_xSpinButton->set_formatter(nullptr);
+            rFieldFormatter.TreatAsNumber(false);
+            rFieldFormatter.SetFormatter(nullptr);
             m_xSpinButton->set_text( "" );
         }
 
@@ -78,7 +79,8 @@ namespace pcr
         , m_xSpinButton(m_xBuilder->weld_formatted_spin_button("sample"))
         , m_xEntry(m_xBuilder->weld_entry("entry"))
     {
-        m_xSpinButton->treat_as_number(true);
+        Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+        rFieldFormatter.TreatAsNumber(true);
         m_xEntry->connect_key_press(LINK(this, OFormatSampleControl, KeyInputHdl));
     }
 
@@ -88,9 +90,10 @@ namespace pcr
         if ( _rValue >>= nFormatKey )
         {
             // else set the new format key, the text will be reformatted
-            m_xSpinButton->set_format_key( nFormatKey );
+            Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+            rFieldFormatter.SetFormatKey(nFormatKey);
 
-            SvNumberFormatter* pNF = m_xSpinButton->get_formatter();
+            SvNumberFormatter* pNF = rFieldFormatter.GetFormatter();
             const SvNumberformat* pEntry = pNF->GetEntry( nFormatKey );
             OSL_ENSURE( pEntry, "OFormatSampleControl::setValue: invalid format entry!" );
 
@@ -98,7 +101,7 @@ namespace pcr
             if ( bIsTextFormat )
                 m_xSpinButton->set_text( PcrRes( RID_STR_TEXT_FORMAT ) );
             else
-                m_xSpinButton->set_value( pEntry ? getPreviewValue( *pEntry ) : 1234.56789 );
+                rFieldFormatter.SetValue( pEntry ? getPreviewValue( *pEntry ) : 1234.56789 );
         }
         else
             m_xSpinButton->set_text( "" );
@@ -146,7 +149,10 @@ namespace pcr
     {
         Any aPropValue;
         if ( !m_xSpinButton->get_text().isEmpty() )
-            aPropValue <<= m_xSpinButton->get_value();
+        {
+            Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+            aPropValue <<= rFieldFormatter.GetValue();
+        }
         return aPropValue;
     }
 
@@ -158,7 +164,7 @@ namespace pcr
     OFormattedNumericControl::OFormattedNumericControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
         : OFormattedNumericControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly)
     {
-        getTypedControlWindow()->treat_as_number(true);
+        getTypedControlWindow()->GetFormatter().TreatAsNumber(true);
     }
 
     OFormattedNumericControl::~OFormattedNumericControl()
@@ -169,7 +175,7 @@ namespace pcr
     {
         double nValue( 0 );
         if ( _rValue >>= nValue )
-            getTypedControlWindow()->set_value( nValue );
+            getTypedControlWindow()->GetFormatter().SetValue(nValue);
         else
             getTypedControlWindow()->set_text("");
     }
@@ -178,7 +184,7 @@ namespace pcr
     {
         Any aPropValue;
         if ( !getTypedControlWindow()->get_text().isEmpty() )
-            aPropValue <<= getTypedControlWindow()->get_value();
+            aPropValue <<= getTypedControlWindow()->GetFormatter().GetValue();
         return aPropValue;
     }
 
@@ -191,16 +197,17 @@ namespace pcr
     {
         bool bFallback = true;
 
+        Formatter& rFieldFormatter = getTypedControlWindow()->GetFormatter();
         if (rDesc.pSupplier)
         {
-            getTypedControlWindow()->treat_as_number(true);
+            rFieldFormatter.TreatAsNumber(true);
 
             SvNumberFormatter* pFormatter = rDesc.pSupplier->GetNumberFormatter();
-            if (pFormatter != getTypedControlWindow()->get_formatter())
-                getTypedControlWindow()->set_formatter(pFormatter);
-            getTypedControlWindow()->set_format_key(rDesc.nKey);
+            if (pFormatter != rFieldFormatter.GetFormatter())
+                rFieldFormatter.SetFormatter(pFormatter);
+            rFieldFormatter.SetFormatKey(rDesc.nKey);
 
-            const SvNumberformat* pEntry = getTypedControlWindow()->get_formatter()->GetEntry(getTypedControlWindow()->get_format_key());
+            const SvNumberformat* pEntry = rFieldFormatter.GetFormatter()->GetEntry(rFieldFormatter.GetFormatKey());
             DBG_ASSERT( pEntry, "OFormattedNumericControl::SetFormatDescription: invalid format key!" );
             if ( pEntry )
             {
@@ -211,8 +218,8 @@ namespace pcr
 
         if ( bFallback )
         {
-            getTypedControlWindow()->treat_as_number(false);
-            getTypedControlWindow()->set_formatter(nullptr);
+            rFieldFormatter.TreatAsNumber(false);
+            rFieldFormatter.SetFormatter(nullptr);
             getTypedControlWindow()->set_text("");
         }
     }
diff --git a/extensions/source/propctrlr/usercontrol.hxx b/extensions/source/propctrlr/usercontrol.hxx
index 93969d2afb21..002c209ce7b1 100644
--- a/extensions/source/propctrlr/usercontrol.hxx
+++ b/extensions/source/propctrlr/usercontrol.hxx
@@ -98,8 +98,8 @@ namespace pcr
         void SetFormatDescription( const FormatDescription& rDesc );
 
         // make some FormattedField methods available
-        void SetDecimalDigits(sal_uInt16 nPrecision) { getTypedControlWindow()->set_digits(nPrecision); }
-        void SetDefaultValue(double dDef) { getTypedControlWindow()->set_value(dDef); }
+        void SetDecimalDigits(sal_uInt16 nPrecision) { getTypedControlWindow()->GetFormatter().SetDecimalDigits(nPrecision); }
+        void SetDefaultValue(double dDef) { getTypedControlWindow()->GetFormatter().SetDefaultValue(dDef); }
 
         virtual void SetModifyHandler() override
         {
diff --git a/framework/source/uielement/spinfieldtoolbarcontroller.cxx b/framework/source/uielement/spinfieldtoolbarcontroller.cxx
index 04de7c1a7db5..dfcd5a6c4342 100644
--- a/framework/source/uielement/spinfieldtoolbarcontroller.cxx
+++ b/framework/source/uielement/spinfieldtoolbarcontroller.cxx
@@ -28,6 +28,7 @@
 #include <svtools/toolboxcontroller.hxx>
 #include <vcl/InterimItemWindow.hxx>
 #include <vcl/event.hxx>
+#include <vcl/formatter.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/toolbox.hxx>
 #include <o3tl/char16_t2wchar_t.hxx>
@@ -59,33 +60,16 @@ public:
         InterimItemWindow::GetFocus();
     }
 
-    void set_value(double fValue);
-
-    void set_digits(int nDigits)
-    {
-        m_xWidget->set_digits(nDigits);
-    }
-
-    void set_min(double fMin)
-    {
-        m_xWidget->set_min(fMin);
-    }
-
-    void set_max(double fMax)
-    {
-        m_xWidget->set_max(fMax);
-    }
-
-    void set_step(double fStep)
+    Formatter& GetFormatter()
     {
-        m_xWidget->set_increments(fStep, fStep * 10);
+        return m_xWidget->GetFormatter();
     }
 
     OUString get_entry_text() const { return m_xWidget->get_text(); }
 
     DECL_LINK(ValueChangedHdl, weld::FormattedSpinButton&, void);
-    DECL_LINK(FormatOutputHdl, weld::FormattedSpinButton&, void);
-    DECL_LINK(ParseInputHdl, double*, bool);
+    DECL_LINK(FormatOutputHdl, LinkParamNone*, bool);
+    DECL_LINK(ParseInputHdl, sal_Int64*, TriState);
     DECL_LINK(ModifyHdl, weld::Entry&, void);
     DECL_LINK(ActivateHdl, weld::Entry&, bool);
     DECL_LINK(FocusInHdl, weld::Widget&, void);
@@ -104,9 +88,10 @@ SpinfieldControl::SpinfieldControl(vcl::Window* pParent, SpinfieldToolbarControl
 {
     m_xWidget->connect_focus_in(LINK(this, SpinfieldControl, FocusInHdl));
     m_xWidget->connect_focus_out(LINK(this, SpinfieldControl, FocusOutHdl));
+    Formatter& rFormatter = m_xWidget->GetFormatter();
+    rFormatter.SetOutputHdl(LINK(this, SpinfieldControl, FormatOutputHdl));
+    rFormatter.SetInputHdl(LINK(this, SpinfieldControl, ParseInputHdl));
     m_xWidget->connect_value_changed(LINK(this, SpinfieldControl, ValueChangedHdl));
-    m_xWidget->connect_output(LINK(this, SpinfieldControl, FormatOutputHdl));
-    m_xWidget->connect_input(LINK(this, SpinfieldControl, ParseInputHdl));
     m_xWidget->connect_changed(LINK(this, SpinfieldControl, ModifyHdl));
     m_xWidget->connect_activate(LINK(this, SpinfieldControl, ActivateHdl));
     m_xWidget->connect_key_press(LINK(this, SpinfieldControl, KeyInputHdl));
@@ -118,23 +103,15 @@ SpinfieldControl::SpinfieldControl(vcl::Window* pParent, SpinfieldToolbarControl
     SetSizePixel(get_preferred_size());
 }
 
-void SpinfieldControl::set_value(double fValue)
-{
-    OUString aOutString = m_pSpinfieldToolbarController->FormatOutputString(fValue);
-    m_xWidget->set_value(fValue);
-    m_xWidget->set_text(aOutString);
-    m_pSpinfieldToolbarController->Modify();
-}
-
 IMPL_LINK(SpinfieldControl, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)
 {
     return ChildKeyInput(rKEvt);
 }
 
-IMPL_LINK(SpinfieldControl, ParseInputHdl, double*, result, bool)
+IMPL_LINK(SpinfieldControl, ParseInputHdl, sal_Int64*, result, TriState)
 {
-    *result = m_xWidget->get_text().toDouble();
-    return true;
+    *result = m_xWidget->get_text().toDouble() * weld::SpinButton::Power10(m_xWidget->GetFormatter().GetDecimalDigits());
+    return TRISTATE_TRUE;
 }
 
 SpinfieldControl::~SpinfieldControl()
@@ -184,10 +161,11 @@ IMPL_LINK_NOARG(SpinfieldControl, ActivateHdl, weld::Entry&, bool)
     return bConsumed;
 }
 
-IMPL_LINK_NOARG(SpinfieldControl, FormatOutputHdl, weld::FormattedSpinButton&, void)
+IMPL_LINK_NOARG(SpinfieldControl, FormatOutputHdl, LinkParamNone*, bool)
 {
-    OUString aText = m_pSpinfieldToolbarController->FormatOutputString(m_xWidget->get_value());
+    OUString aText = m_pSpinfieldToolbarController->FormatOutputString(m_xWidget->GetFormatter().GetValue());
     m_xWidget->set_text(aText);
+    return true;
 }
 
 SpinfieldToolbarController::SpinfieldToolbarController(
@@ -387,29 +365,31 @@ void SpinfieldToolbarController::executeControlCommand( const css::frame::Contro
         }
     }
 
+    Formatter& rFormatter = m_pSpinfieldControl->GetFormatter();
+
     // Check values and set members
     if (bFloatValue)
-        m_pSpinfieldControl->set_digits(2);
+        rFormatter.SetDecimalDigits(2);
     if ( !aValue.isEmpty() )
     {
         m_bFloat = bFloatValue;
         m_nValue = aValue.toDouble();
-        m_pSpinfieldControl->set_value(m_nValue);
+        rFormatter.SetValue(m_nValue);
     }
     if ( !aMax.isEmpty() )
     {
         m_nMax = aMax.toDouble();
-        m_pSpinfieldControl->set_max(m_nMax);
+        rFormatter.SetMaxValue(m_nMax);
     }
     if ( !aMin.isEmpty() )
     {
         m_nMin = aMin.toDouble();
-        m_pSpinfieldControl->set_min(m_nMin);
+        rFormatter.SetMinValue(m_nMin);
     }
     if ( !aStep.isEmpty() )
     {
         m_nStep = aStep.toDouble();
-        m_pSpinfieldControl->set_step(m_nStep);
+        rFormatter.SetSpinSize(m_nStep);
     }
 }
 
diff --git a/include/vcl/fmtfield.hxx b/include/vcl/fmtfield.hxx
index 26715e687218..1d92a1b957b4 100644
--- a/include/vcl/fmtfield.hxx
+++ b/include/vcl/fmtfield.hxx
@@ -48,6 +48,7 @@ public:
     virtual FactoryFunction GetUITestFactory() const override;
 
     Formatter* GetFormatter();
+    void SetFormatter(Formatter* pFormatter);
 
 protected:
     std::unique_ptr<Formatter> m_xFormatter;
diff --git a/include/vcl/formatter.hxx b/include/vcl/formatter.hxx
index f54d59ca4600..4f9a016cc6da 100644
--- a/include/vcl/formatter.hxx
+++ b/include/vcl/formatter.hxx
@@ -156,13 +156,13 @@ public:
 
     // Min-/Max-management
     bool    HasMinValue() const         { return m_bHasMin; }
-    void    ClearMinValue()             { m_bHasMin = false; }
-    void    SetMinValue(double dMin);
+    virtual void ClearMinValue()        { m_bHasMin = false; }
+    virtual void SetMinValue(double dMin);
     double  GetMinValue() const         { return m_dMinValue; }
 
     bool    HasMaxValue() const         { return m_bHasMax; }
-    void    ClearMaxValue()             { m_bHasMax = false; }
-    void    SetMaxValue(double dMax);
+    virtual void ClearMaxValue()             { m_bHasMax = false; }
+    virtual void SetMaxValue(double dMax);
     double  GetMaxValue() const         { return m_dMaxValue; }
 
     // Current value
@@ -219,7 +219,7 @@ public:
     void    SetStrictFormat(bool bEnable)       { m_bStrictFormat = bEnable; }
     // Check format during input
 
-    void    SetSpinSize(double dStep)   { m_dSpinSize = dStep; }
+    virtual void SetSpinSize(double dStep)   { m_dSpinSize = dStep; }
     double  GetSpinSize() const         { return m_dSpinSize; }
 
     void    SetSpinFirst(double dFirst) { m_dSpinFirst = dFirst; }
@@ -304,6 +304,8 @@ protected:
 
     SvNumberFormatter*  CreateFormatter() { SetFormatter(StandardFormatter()); return m_pFormatter; }
 
+    virtual void UpdateCurrentValue(double dCurrentValue) { m_dCurrentValue = dCurrentValue; }
+
     void ReFormat();
 };
 
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index ee110a049888..88dbcf0dad5f 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -62,6 +62,7 @@ typedef css::uno::Reference<css::accessibility::XAccessibleRelationSet> a11yrela
 enum class PointerStyle;
 class CommandEvent;
 class KeyEvent;
+class Formatter;
 class MouseEvent;
 class SvNumberFormatter;
 class TransferDataContainer;
@@ -1506,7 +1507,7 @@ public:
     */
     virtual void set_font_color(const Color& rColor) = 0;
 
-    void connect_changed(const Link<Entry&, void>& rLink) { m_aChangeHdl = rLink; }
+    virtual void connect_changed(const Link<Entry&, void>& rLink) { m_aChangeHdl = rLink; }
     void connect_insert_text(const Link<OUString&, bool>& rLink) { m_aInsertTextHdl = rLink; }
     // callback returns true to indicated no further processing of activate wanted
     void connect_activate(const Link<Entry&, bool>& rLink) { m_aActivateHdl = rLink; }
@@ -1596,52 +1597,31 @@ public:
     static unsigned int Power10(unsigned int n);
 };
 
+class EntryFormatter;
+
+// Similar to a SpinButton, but input and output formatting and range/value
+// are managed by a more complex Formatter which can support doubles.
 class VCL_DLLPUBLIC FormattedSpinButton : virtual public Entry
 {
 protected:
     Link<FormattedSpinButton&, void> m_aValueChangedHdl;
-    Link<FormattedSpinButton&, void> m_aOutputHdl;
-    Link<double*, bool> m_aInputHdl;
 
     void signal_value_changed() { m_aValueChangedHdl.Call(*this); }
 
 public:
-    virtual void set_value(double value) = 0;
-    virtual double get_value() const = 0;
-    virtual void set_range(double min, double max) = 0;
-    virtual void get_range(double& min, double& max) const = 0;
-    virtual void set_increments(double step, double page) = 0;
-
-    void set_min(double min)
-    {
-        double max, dummy;
-        get_range(dummy, max);
-        set_range(min, max);
-    }
-
-    void set_max(double max)
-    {
-        double min, dummy;
-        get_range(min, dummy);
-        set_range(min, max);
-    }
-
-    virtual void set_formatter(SvNumberFormatter* pFormatter) = 0;
-    virtual SvNumberFormatter* get_formatter() = 0;
-    virtual sal_Int32 get_format_key() const = 0;
-    virtual void set_format_key(sal_Int32 nFormatKey) = 0;
-
-    virtual void set_digits(unsigned int digits) = 0;
-
-    virtual void treat_as_number(bool bSet) = 0;
+    virtual Formatter& GetFormatter() = 0;
+    virtual void SetFormatter(weld::EntryFormatter* pFormatter) = 0;
 
     void connect_value_changed(const Link<FormattedSpinButton&, void>& rLink)
     {
         m_aValueChangedHdl = rLink;
     }
 
-    void connect_output(const Link<FormattedSpinButton&, void>& rLink) { m_aOutputHdl = rLink; }
-    void connect_input(const Link<double*, bool>& rLink) { m_aInputHdl = rLink; }
+private:
+    friend class EntryFormatter;
+    virtual void sync_range_from_formatter() = 0;
+    virtual void sync_value_from_formatter() = 0;
+    virtual void sync_increments_from_formatter() = 0;
 };
 
 class VCL_DLLPUBLIC Image : virtual public Widget
diff --git a/include/vcl/weldutils.hxx b/include/vcl/weldutils.hxx
index 299d3ee3135b..757303fdcabf 100644
--- a/include/vcl/weldutils.hxx
+++ b/include/vcl/weldutils.hxx
@@ -158,12 +158,17 @@ class VCL_DLLPUBLIC EntryFormatter : public Formatter
 {
 public:
     EntryFormatter(weld::Entry& rEntry);
+    EntryFormatter(weld::FormattedSpinButton& rSpinButton);
 
+    // EntryFormatter will set listeners to "changed" and "focus-out" of the
+    // entry so users that want to add their own listeners to those must set
+    // them through this formatter and not directly on the entry
     void connect_changed(const Link<weld::Entry&, void>& rLink) { m_aModifyHdl = rLink; }
+    void connect_focus_out(const Link<weld::Widget&, void>& rLink) { m_aFocusOutHdl = rLink; }
 
     weld::Entry& get_widget() { return m_rEntry; }
 
-    // Formatter overrides
+    // public Formatter overrides, drives interactions with the Entry
     virtual Selection GetEntrySelection() const override;
     virtual OUString GetEntryText() const override;
     virtual void SetEntryText(const OUString& rText, const Selection& rSel) override;
@@ -171,14 +176,30 @@ public:
     virtual SelectionOptions GetEntrySelectionOptions() const override;
     virtual void FieldModified() override;
 
+    // public Formatter overrides, drives optional SpinButton settings
+    virtual void ClearMinValue() override;
+    virtual void SetMinValue(double dMin) override;
+    virtual void ClearMaxValue() override;
+    virtual void SetMaxValue(double dMin) override;
+
+    virtual void SetSpinSize(double dStep) override;
+
     void SetEntrySelectionOptions(SelectionOptions eOptions) { m_eOptions = eOptions; }
 
+    virtual ~EntryFormatter() override;
+
 private:
     weld::Entry& m_rEntry;
+    weld::FormattedSpinButton* m_pSpinButton;
     Link<weld::Entry&, void> m_aModifyHdl;
+    Link<weld::Widget&, void> m_aFocusOutHdl;
     SelectionOptions m_eOptions;
     DECL_DLLPRIVATE_LINK(ModifyHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(FocusOutHdl, weld::Widget&, void);
+    void Init();
+
+    // private Formatter overrides
+    virtual void UpdateCurrentValue(double dCurrentValue) override;
 };
 
 // get the row the iterator is on
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 22b8329cb9f5..f646beb64d9a 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -65,6 +65,7 @@
 #include <vcl/toolkit/throbber.hxx>
 #include <vcl/toolkit/unowrap.hxx>
 #include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
 #include <vcl/vclmedit.hxx>
 #include <vcl/viewdataentry.hxx>
 #include <vcl/virdev.hxx>
@@ -5325,96 +5326,41 @@ class SalInstanceFormattedSpinButton : public SalInstanceEntry,
 {
 private:
     VclPtr<FormattedField> m_xButton;
-    Formatter* m_pFormatter;
-
-    DECL_LINK(OutputHdl, LinkParamNone*, bool);
-    DECL_LINK(InputHdl, sal_Int64*, TriState);
 
 public:
     SalInstanceFormattedSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder,
                                    bool bTakeOwnership)
         : SalInstanceEntry(pButton, pBuilder, bTakeOwnership)
         , m_xButton(pButton)
-        , m_pFormatter(m_xButton->GetFormatter())
-    {
-        m_pFormatter->SetOutputHdl(LINK(this, SalInstanceFormattedSpinButton, OutputHdl));
-        m_pFormatter->SetInputHdl(LINK(this, SalInstanceFormattedSpinButton, InputHdl));
-
-        // #i6278# allow more decimal places than the output format.  As
-        // the numbers shown in the edit fields are used for input, it makes more
-        // sense to display the values in the input format rather than the output
-        // format.
-        m_pFormatter->UseInputStringForFormatting();
-    }
-
-    virtual ~SalInstanceFormattedSpinButton() override
     {
-        m_pFormatter->SetInputHdl(Link<sal_Int64*, TriState>());
-        m_pFormatter->SetOutputHdl(Link<LinkParamNone*, bool>());
     }
 
-    virtual double get_value() const override { return m_pFormatter->GetValue(); }
-
-    virtual void set_value(double value) override { m_pFormatter->SetValue(value); }
-
-    virtual void set_range(double min, double max) override
+    virtual void SetFormatter(weld::EntryFormatter* pFormatter) override
     {
-        m_pFormatter->SetMinValue(min);
-        m_pFormatter->SetMaxValue(max);
+        m_xButton->SetFormatter(pFormatter);
     }
 
-    virtual void get_range(double& min, double& max) const override
+    virtual void sync_value_from_formatter() override
     {
-        min = m_pFormatter->GetMinValue();
-        max = m_pFormatter->GetMaxValue();
+        // no-op for gen
     }
 
-    virtual void set_increments(double step, double /*page*/) override
+    virtual void sync_range_from_formatter() override
     {
-        m_pFormatter->SetSpinSize(step);
+        // no-op for gen
     }
 
-    virtual void set_formatter(SvNumberFormatter* pFormatter) override
+    virtual void sync_increments_from_formatter() override
     {
-        m_pFormatter->SetFormatter(pFormatter);
+        // no-op for gen
     }
 
-    virtual SvNumberFormatter* get_formatter() override { return m_pFormatter->GetFormatter(); }
-
-    virtual sal_Int32 get_format_key() const override { return m_pFormatter->GetFormatKey(); }
-
-    virtual void set_format_key(sal_Int32 nFormatKey) override
+    virtual Formatter& GetFormatter() override
     {
-        m_pFormatter->SetFormatKey(nFormatKey);
+        return *m_xButton->GetFormatter();
     }
-
-    virtual void treat_as_number(bool bSet) override { m_pFormatter->TreatAsNumber(bSet); }
-
-    virtual void set_digits(unsigned int digits) override { m_pFormatter->SetDecimalDigits(digits); }
 };
 
-IMPL_LINK_NOARG(SalInstanceFormattedSpinButton, OutputHdl, LinkParamNone*, bool)
-{
-    // allow an explicit handler
-    if (!m_aOutputHdl.IsSet())
-        return false;
-    m_aOutputHdl.Call(*this);
-    return true;
-}
-
-IMPL_LINK(SalInstanceFormattedSpinButton, InputHdl, sal_Int64*, pResult, TriState)
-{
-    // allow an explicit handler
-    if (!m_aInputHdl.IsSet())
-        return TRISTATE_INDET;
-
-    double value;
-    TriState eRet = m_aInputHdl.Call(&value) ? TRISTATE_TRUE : TRISTATE_FALSE;
-    if (eRet == TRISTATE_TRUE)
-        *pResult = std::round(value * weld::SpinButton::Power10(m_pFormatter->GetDecimalDigits()));
-    return eRet;
-}
-
 }
 
 SalInstanceLabel::SalInstanceLabel(Control* pLabel, SalInstanceBuilder* pBuilder,
diff --git a/vcl/source/app/weldutils.cxx b/vcl/source/app/weldutils.cxx
index d9d237cef5c4..f560923e5609 100644
--- a/vcl/source/app/weldutils.cxx
+++ b/vcl/source/app/weldutils.cxx
@@ -125,9 +125,29 @@ void RemoveParentKeepChildren(weld::TreeView& rTreeView, weld::TreeIter& rParent
     rTreeView.remove(rParent);
 }
 
+EntryFormatter::EntryFormatter(weld::FormattedSpinButton& rSpinButton)
+    : m_rEntry(rSpinButton)
+    , m_pSpinButton(&rSpinButton)
+    , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
+{
+    Init();
+}
+
 EntryFormatter::EntryFormatter(weld::Entry& rEntry)
     : m_rEntry(rEntry)
+    , m_pSpinButton(nullptr)
     , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
+{
+    Init();
+}
+
+EntryFormatter::~EntryFormatter()
+{
+    m_rEntry.connect_changed(Link<weld::Entry&, void>());
+    m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
+}
+
+void EntryFormatter::Init()
 {
     m_rEntry.connect_changed(LINK(this, EntryFormatter, ModifyHdl));
     m_rEntry.connect_focus_out(LINK(this, EntryFormatter, FocusOutHdl));
@@ -155,13 +175,65 @@ void EntryFormatter::SetEntryTextColor(const Color* pColor)
     m_rEntry.set_font_color(pColor ? *pColor : COL_AUTO);
 }
 
+void EntryFormatter::UpdateCurrentValue(double dCurrentValue)
+{
+    Formatter::UpdateCurrentValue(dCurrentValue);
+    if (m_pSpinButton)
+        m_pSpinButton->sync_value_from_formatter();
+}
+
+void EntryFormatter::ClearMinValue()
+{
+    Formatter::ClearMinValue();
+    if (m_pSpinButton)
+        m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetMinValue(double dMin)
+{
+    Formatter::SetMinValue(dMin);
+    if (m_pSpinButton)
+        m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::ClearMaxValue()
+{
+    Formatter::ClearMaxValue();
+    if (m_pSpinButton)
+        m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetMaxValue(double dMin)
+{
+    Formatter::SetMaxValue(dMin);
+    if (m_pSpinButton)
+        m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetSpinSize(double dStep)
+{
+    Formatter::SetSpinSize(dStep);
+    if (m_pSpinButton)
+        m_pSpinButton->sync_increments_from_formatter();
+}
+
 SelectionOptions EntryFormatter::GetEntrySelectionOptions() const { return m_eOptions; }
 
 void EntryFormatter::FieldModified() { m_aModifyHdl.Call(m_rEntry); }
 
-IMPL_LINK_NOARG(EntryFormatter, ModifyHdl, weld::Entry&, void) { Modify(); }
+IMPL_LINK_NOARG(EntryFormatter, ModifyHdl, weld::Entry&, void)
+{
+    // This leads to FieldModified getting called at the end of Modify() and
+    // FieldModified then calls any modification callback
+    Modify();
+}
+
+IMPL_LINK_NOARG(EntryFormatter, FocusOutHdl, weld::Widget&, void)
+{
+    EntryLostFocus();
+    m_aFocusOutHdl.Call(m_rEntry);
+}
 
-IMPL_LINK_NOARG(EntryFormatter, FocusOutHdl, weld::Widget&, void) { EntryLostFocus(); }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/control/fmtfield.cxx b/vcl/source/control/fmtfield.cxx
index d67b0b9ba792..5f1cb134b9d4 100644
--- a/vcl/source/control/fmtfield.cxx
+++ b/vcl/source/control/fmtfield.cxx
@@ -699,7 +699,6 @@ void Formatter::ReFormat()
     }
 }
 
-
 void Formatter::SetMinValue(double dMin)
 {
     DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be used in numeric mode !");
@@ -754,7 +753,7 @@ void Formatter::ImplSetValue(double dVal, bool bForce)
     DBG_ASSERT(GetOrCreateFormatter() != nullptr, "FormattedField::ImplSetValue : can't set a value without a formatter !");
 
     m_ValueState = valueDouble;
-    m_dCurrentValue = dVal;
+    UpdateCurrentValue(dVal);
 
     if (!m_aOutputHdl.IsSet() || !m_aOutputHdl.Call(nullptr))
     {
@@ -860,13 +859,14 @@ void Formatter::SetValue(double dVal)
 
 double Formatter::GetValue()
 {
-
     if ( !ImplGetValue( m_dCurrentValue ) )
     {
-        if ( m_bEnableNaN )
-            ::rtl::math::setNan( &m_dCurrentValue );
+        double dValue;
+        if (m_bEnableNaN)
+            ::rtl::math::setNan(&dValue);
         else
-            m_dCurrentValue = m_dDefaultValue;
+            dValue = m_dDefaultValue;
+        UpdateCurrentValue(dValue);
     }
 
     m_ValueState = valueDouble;
@@ -1308,6 +1308,11 @@ Formatter* FormattedField::GetFormatter()
     return m_xFormatter.get();
 }
 
+void FormattedField::SetFormatter(Formatter* pFormatter)
+{
+    m_xFormatter.reset(pFormatter);
+}
+
 // currently used by online
 void FormattedField::SetValueFromString(const OUString& rStr)
 {
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index a7d8a9cd30a7..bbcb6218aed3 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -12165,39 +12165,14 @@ class GtkInstanceFormattedSpinButton : public GtkInstanceEntry, public virtual w
 {
 private:
     GtkSpinButton* m_pButton;
-    SvNumberFormatter* m_pFormatter;
-    Color* m_pLastOutputColor;
-    sal_uInt32 m_nFormatKey;
-    bool m_bTreatAsNumber;
+    std::unique_ptr<weld::EntryFormatter> m_xFormatter;
     gulong m_nValueChangedSignalId;
     gulong m_nOutputSignalId;
     gulong m_nInputSignalId;
 
     bool signal_output()
     {
-        // allow an explicit handler
-        if (m_aOutputHdl.IsSet())
-        {
-            m_aOutputHdl.Call(*this);
-            return true;
-        }
-        if (!m_pFormatter)
-            return false;
-        double dVal = get_value();
-        OUString sNewText;
-        if (m_pFormatter->IsTextFormat(m_nFormatKey))
-        {
-            // first convert the number as string in standard format
-            OUString sTemp;
-            m_pFormatter->GetOutputString(dVal, 0, sTemp, &m_pLastOutputColor);
-            // then encode the string in the corresponding text format
-            m_pFormatter->GetOutputString(sTemp, m_nFormatKey, sNewText, &m_pLastOutputColor);
-        }
-        else
-        {
-            m_pFormatter->GetInputLineString(dVal, m_nFormatKey, sNewText);
-        }
-        set_text(sNewText);
+        GetFormatter().SetValue(gtk_spin_button_get_value(m_pButton));
         return true;
     }
 
@@ -12210,42 +12185,9 @@ private:
 
     gint signal_input(double* value)
     {
-        // allow an explicit handler
-        if (m_aInputHdl.IsSet())
-            return m_aInputHdl.Call(value) ? 1 : GTK_INPUT_ERROR;
-
-        if (!m_pFormatter)
-            return 0;
-
-        sal_uInt32 nFormatKey = m_nFormatKey; // IsNumberFormat changes the FormatKey!
-
-        if (m_pFormatter->IsTextFormat(nFormatKey) && m_bTreatAsNumber)
-            // for detection of values like "1,1" in fields that are formatted as text
-            nFormatKey = 0;
-
-        OUString sText(get_text());
-
-        // special treatment for percentage formatting
-        if (m_pFormatter->GetType(m_nFormatKey) == SvNumFormatType::PERCENT)
-        {
-            // the language of our format
-            LanguageType eLanguage = m_pFormatter->GetEntry(m_nFormatKey)->GetLanguage();
-            // the default number format for this language
-            sal_uLong nStandardNumericFormat = m_pFormatter->GetStandardFormat(SvNumFormatType::NUMBER, eLanguage);
-
-            sal_uInt32 nTempFormat = nStandardNumericFormat;
-            double dTemp;
-            if (m_pFormatter->IsNumberFormat(sText, nTempFormat, dTemp) &&
-                SvNumFormatType::NUMBER == m_pFormatter->GetType(nTempFormat))
-                // the string is equivalent to a number formatted one (has no % sign) -> append it
-                sText += "%";
-            // (with this, an input of '3' becomes '3%', which then by the formatter is translated
-            // into 0.03. Without this, the formatter would give us the double 3 for an input '3',
-            // which equals 300 percent.
-        }
-        if (!m_pFormatter->IsNumberFormat(sText, nFormatKey, *value))
-            return GTK_INPUT_ERROR;
-
+        Formatter& rFormatter = GetFormatter();
+        rFormatter.Modify();
+        *value = rFormatter.GetValue();
         return 1;
     }
 
@@ -12267,88 +12209,87 @@ public:
     GtkInstanceFormattedSpinButton(GtkSpinButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
         : GtkInstanceEntry(GTK_ENTRY(pButton), pBuilder, bTakeOwnership)
         , m_pButton(pButton)
-        , m_pFormatter(nullptr)
-        , m_pLastOutputColor(nullptr)
-        , m_nFormatKey(0)
-        , m_bTreatAsNumber(true)
         , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this))
         , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this))
         , m_nInputSignalId(g_signal_connect(pButton, "input", G_CALLBACK(signalInput), this))
     {
     }
 
-    virtual double get_value() const override
+    virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override
     {
-        return gtk_spin_button_get_value(m_pButton);
-    }
-
-    virtual void set_value(double value) override
-    {
-        disable_notify_events();
-        gtk_spin_button_set_value(m_pButton, value);
-        enable_notify_events();
-    }
-
-    virtual void set_range(double min, double max) override
-    {
-        disable_notify_events();
-        gtk_spin_button_set_range(m_pButton, min, max);
-        enable_notify_events();
+        if (!m_xFormatter) // once a formatter is set, it takes over "changed"
+        {
+            GtkInstanceEntry::connect_changed(rLink);
+            return;
+        }
+        m_xFormatter->connect_changed(rLink);
     }
 
-    virtual void get_range(double& min, double& max) const override
+    virtual void connect_focus_out(const Link<weld::Widget&, void>& rLink) override
     {
-        gtk_spin_button_get_range(m_pButton, &min, &max);
+        if (!m_xFormatter) // once a formatter is set, it takes over "focus-out"
+        {
+            GtkInstanceEntry::connect_focus_out(rLink);
+            return;
+        }
+        m_xFormatter->connect_focus_out(rLink);
     }
 
-    virtual void set_increments(double step, double page) override
+    virtual void SetFormatter(weld::EntryFormatter* pFormatter) override
     {
-        disable_notify_events();
-        gtk_spin_button_set_increments(m_pButton, step, page);
-        enable_notify_events();
+        m_xFormatter.reset(pFormatter);
+        sync_range_from_formatter();
+        sync_value_from_formatter();
+        sync_increments_from_formatter();
     }
 
-    virtual void set_formatter(SvNumberFormatter* pFormatter) override
+    virtual weld::EntryFormatter& GetFormatter() override
     {
-        m_pFormatter = pFormatter;
-
-        // calc the default format key from the Office's UI locale
-        if (m_pFormatter)
+        if (!m_xFormatter)
         {
-            // get the Office's locale and translate
-            LanguageType eSysLanguage = Application::GetSettings().GetUILanguageTag().getLanguageType( false);
-            // get the standard numeric format for this language
-            m_nFormatKey = m_pFormatter->GetStandardFormat( SvNumFormatType::NUMBER, eSysLanguage );
-        }
-        else
-            m_nFormatKey = 0;
-        signal_output();
-    }
+            auto aFocusOutHdl = m_aFocusOutHdl;
+            m_aFocusOutHdl = Link<weld::Widget&, void>();
+            auto aChangeHdl = m_aChangeHdl;
+            m_aChangeHdl = Link<weld::Entry&, void>();
 
-    virtual SvNumberFormatter* get_formatter() override
-    {
-        return m_pFormatter;
-    }
+            double fValue = gtk_spin_button_get_value(m_pButton);
+            double fMin, fMax;
+            gtk_spin_button_get_range(m_pButton, &fMin, &fMax);
+            double fStep;
+            gtk_spin_button_get_increments(m_pButton, &fStep, nullptr);
+            m_xFormatter.reset(new weld::EntryFormatter(*this));
+            m_xFormatter->SetMinValue(fMin);
+            m_xFormatter->SetMaxValue(fMax);
+            m_xFormatter->SetSpinSize(fStep);
+            m_xFormatter->SetValue(fValue);
 
-    virtual sal_Int32 get_format_key() const override
-    {
-        return m_nFormatKey;
+            m_xFormatter->connect_focus_out(aFocusOutHdl);
+            m_xFormatter->connect_changed(aChangeHdl);
+        }
+        return *m_xFormatter;
     }
 
-    virtual void set_format_key(sal_Int32 nFormatKey) override
+    virtual void sync_value_from_formatter() override
     {
-        m_nFormatKey = nFormatKey;
+        disable_notify_events();
+        gtk_spin_button_set_value(m_pButton, m_xFormatter->GetValue());
+        enable_notify_events();
     }
 
-    virtual void treat_as_number(bool bSet) override
+    virtual void sync_range_from_formatter() override
     {
-        m_bTreatAsNumber = bSet;
+        disable_notify_events();
+        double fMin = m_xFormatter->HasMinValue() ? m_xFormatter->GetMinValue() : DBL_MIN;
+        double fMax = m_xFormatter->HasMaxValue() ? m_xFormatter->GetMaxValue() : DBL_MAX;
+        gtk_spin_button_set_range(m_pButton, fMin, fMax);
+        enable_notify_events();
     }
 
-    virtual void set_digits(unsigned int digits) override
+    virtual void sync_increments_from_formatter() override
     {
         disable_notify_events();
-        gtk_spin_button_set_digits(m_pButton, digits);
+        double fSpinSize = m_xFormatter->GetSpinSize();
+        gtk_spin_button_set_increments(m_pButton, fSpinSize, fSpinSize * 10);
         enable_notify_events();
     }
 


More information about the Libreoffice-commits mailing list