include/vcl/fmtfield.hxx        |  229 ----------------
 include/vcl/formatter.hxx       |  261 ++++++++++++++++++
 solenv/clang-format/blacklist   |    1 
 vcl/inc/salvtables.hxx          |    2 
 vcl/source/app/salvtables.cxx   |   10 
 vcl/source/control/fmtfield.cxx |  569 +++++++++++++++++++++-------------------
 6 files changed, 583 insertions(+), 489 deletions(-)

New commits:
commit 175eba0d87cc0d4693920341077617ef443809b4
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Wed Jul 1 15:49:57 2020 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Wed Jul 1 21:12:51 2020 +0200

    split Formatter part of FormattedField from SpinButton part
    
    Change-Id: Ic1454d63a17bd3ec1d70cd5eef5895aee2d919ec
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97642
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/include/vcl/fmtfield.hxx b/include/vcl/fmtfield.hxx
index be6c82ff003a..08fc7d9174f8 100644
--- a/include/vcl/fmtfield.hxx
+++ b/include/vcl/fmtfield.hxx
@@ -20,147 +20,15 @@
 #ifndef INCLUDED_VCL_FMTFIELD_HXX
 #define INCLUDED_VCL_FMTFIELD_HXX
 
-#include <config_options.h>
+#include <vcl/formatter.hxx>
 #include <vcl/spinfld.hxx>
-#include <memory>
-
-class SvNumberFormatter;
-
-namespace validation { class NumberValidator; }
-
-enum class FORMAT_CHANGE_TYPE
-{
-    KEYONLY           = 0x00,        // only a new key was set
-    FORMATTER         = 0x01,        // a new formatter was set, usually 
implies a change of the key, too
-    PRECISION         = 0x02,        // a new precision was set
-    THOUSANDSSEP      = 0x03,        // the thousands separator setting changed
-    CURRENCY_SYMBOL   = 0x10,
-    CURRSYM_POSITION  = 0x20,
-};
-
 
 class VCL_DLLPUBLIC FormattedField : public SpinField
+                                   , public Formatter
 {
-private:
-    // A SvNumberFormatter is very expensive (regarding time and space), it is 
a Singleton
-    class StaticFormatter
-    {
-        static SvNumberFormatter*   s_cFormatter;
-        static sal_uLong                s_nReferences;
-    public:
-        StaticFormatter();
-        ~StaticFormatter();
-
-        operator SvNumberFormatter* () { return GetFormatter(); }
-        UNLESS_MERGELIBS(VCL_DLLPUBLIC) static SvNumberFormatter* 
GetFormatter();
-    };
-
-protected:
-    OUString      m_sLastValidText;
-    // Has nothing to do with the current value. It is the last text, which 
was valid at input (checked by CheckText,
-    // not yet through formatter)
-    Selection   m_aLastSelection;
-
-    double              m_dMinValue;
-    double              m_dMaxValue;
-    bool                m_bHasMin : 1;
-    bool                m_bHasMax : 1;
-
-    bool                m_bWrapOnLimits : 1;
-    bool                m_bStrictFormat : 1;
-
-    bool                m_bEnableEmptyField : 1;
-    bool                m_bAutoColor : 1;
-    bool                m_bEnableNaN : 1;
-    bool                m_bDisableRemainderFactor : 1;
-    enum valueState { valueDirty, valueString, valueDouble };
-    valueState          m_ValueState;
-    double              m_dCurrentValue;
-    double              m_dDefaultValue;
-
-    sal_uLong               m_nFormatKey;
-    SvNumberFormatter*  m_pFormatter;
-    StaticFormatter     m_aStaticFormatter;
-
-    double              m_dSpinSize;
-    double              m_dSpinFirst;
-    double              m_dSpinLast;
-
-    // There is a difference, when text formatting is enabled, if LostFocus 
formats the current String and displays it,
-    // or if a double is created from the String and then
-    bool                m_bTreatAsNumber;
-    // And with the following members we can use it for formatted text output 
as well ...
-    OUString            m_sCurrentTextValue;
-    OUString            m_sDefaultText;
-
-    // The last color from the Formatter at the last output operation (not we 
would use it, but you can get it)
-    Color*              m_pLastOutputColor;
-
-    bool                m_bUseInputStringForFormatting;
-
 public:
     FormattedField(vcl::Window* pParent, WinBits nStyle);
 
-    // Min-/Max-management
-    bool    HasMinValue() const         { return m_bHasMin; }
-    void    ClearMinValue()             { m_bHasMin = false; }
-    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);
-    double  GetMaxValue() const         { return m_dMaxValue; }
-
-    // Current value
-    void    SetValue(double dVal);
-    double  GetValue();
-    // The default implementation uses a formatter, if available
-
-    void    SetTextValue(const OUString& rText);
-    // The String is transformed to a double (with a formatter) and SetValue 
is called afterwards
-    //
-    void    SetValueFromString(const OUString& rStr);
-
-    bool    IsEmptyFieldEnabled() const         { return m_bEnableEmptyField; }
-    void    EnableEmptyField(bool bEnable);
-    // If disabled, the value will be reset to the last valid value on leave
-
-    void    SetDefaultValue(double dDefault)    { m_dDefaultValue = dDefault; 
m_ValueState = valueDirty; }
-    // If the current String is invalid, GetValue() returns this value
-    double  GetDefaultValue() const             { return m_dDefaultValue; }
-
-    // Settings for the format
-    sal_uLong   GetFormatKey() const                { return m_nFormatKey; }
-    void    SetFormatKey(sal_uLong nFormatKey);
-
-    SvNumberFormatter*  GetFormatter() const    { return m_pFormatter; }
-    void    SetFormatter(SvNumberFormatter* pFormatter, bool bResetFormat = 
true);
-    // If bResetFormat is sal_False, the old format is tried to be kept. 
(expensive, if it is no default format, available in all formatters)
-    // If sal_True, the new FormatKey is set to zero
-
-    bool    GetThousandsSep() const;
-    void    SetThousandsSep(bool _bUseSeparator);
-        // the is no check if the current format is numeric, so be cautious 
when calling these functions
-
-    void    DisableRemainderFactor();
-
-    sal_uInt16  GetDecimalDigits() const;
-    void    SetDecimalDigits(sal_uInt16 _nPrecision);
-        // There is no check if the current format is numeric, so be cautious 
when calling these functions
-
-    SvNumberFormatter*  StandardFormatter() { return m_aStaticFormatter; }
-    // If no new Formatter is created explicitly, this can be used in 
SetFormatter...
-
-    OUString    GetFormat(LanguageType& eLang) const;
-    bool        SetFormat(const OUString& rFormatString, LanguageType eLang);
-    // sal_False, if the FormatString could not be set (and very probably is 
invalid)
-    // This Object is shared via all instances, so be careful!
-
-    bool    IsStrictFormat() const              { return m_bStrictFormat; }
-    void    SetStrictFormat(bool bEnable)       { m_bStrictFormat = bEnable; }
-    // Check format during input
-
     // Spin-Handling
     virtual void Up() override;
     virtual void Down() override;
@@ -170,104 +38,29 @@ public:
     // Default Implementation: Current double is set to the first or last value
 
     virtual bool set_property(const OString &rKey, const OUString &rValue) 
override;
-
-    void    SetSpinSize(double dStep)   { m_dSpinSize = dStep; }
-    double  GetSpinSize() const         { return m_dSpinSize; }
-
-    void    SetSpinFirst(double dFirst) { m_dSpinFirst = dFirst; }
-    double  GetSpinFirst() const        { return m_dSpinFirst; }
-
-    void    SetSpinLast(double dLast)   { m_dSpinLast = dLast; }
-    double  GetSpinLast() const         { return m_dSpinLast; }
-
-    bool    TreatingAsNumber() const    { return m_bTreatAsNumber; }
-    void    TreatAsNumber(bool bDoSo) { m_bTreatAsNumber = bDoSo; }
-
-    void    SetOutputHdl(const Link<Edit&, bool>& rLink) { m_aOutputHdl = 
rLink; }
-    void    SetInputHdl(const Link<sal_Int64*,TriState>& rLink) { m_aInputHdl 
= rLink; }
 public:
     virtual void SetText( const OUString& rStr ) override;
     virtual void SetText( const OUString& rStr, const Selection& rNewSelection 
) override;
 
-    //The following methods are interesting, if m_bTreatAsNumber is set to 
sal_False
-    //If someone does not care about all the double handling and just wants to 
print the text formatted.
-    //(((The text will be formatted, using the Formatter, and then set)
-    void SetTextFormatted(const OUString& rText);
-    OUString const & GetTextValue() const;
-
-    void      SetDefaultText(const OUString& rDefault) { m_sDefaultText = 
rDefault; }
-    const OUString& GetDefaultText() const { return m_sDefaultText; }
-
-    // The last colour from the Formatter's last output operation. Output 
operations get triggered by:
-    // SetValue, SetTextValue, SetTextFormatted, also indirectly via SetMin - 
/ -MaxValue
-    Color*  GetLastOutputColor() const { return m_pLastOutputColor; }
-
-    /** reformats the current text. Interesting if the user entered some text 
in an "input format", and
-        this should be formatted in the "output format" (which may differ, 
e.g. by additional numeric
-        digits or such).
-    */
-    void    Commit();
-
-    // enable automatic coloring. if set to sal_True, and the format the field 
is working with for any current value
-    // says that it has to be painted in a special color (e.g. a format where 
negative numbers should be printed
-    // red), the text is painted with that color automatically.
-    // The color used is the same as returned by GetLastOutputColor()
-    void    SetAutoColor(bool _bAutomatic);
-
-    /** enables handling of not-a-number value.
-
-        When this is set to <FALSE/> (the default), then invalid inputs (i.e. 
text which cannot be
-        interpreted, according to the current formatting) will be handled as 
if the default value
-        has been entered. GetValue the will return this default value.
-
-        When set to <TRUE/>, then GetValue will return NaN (not a number, see 
<method scope="rtl::math">isNan</method>)
-        when the current input is invalid.
-
-        Note that setting this to <TRUE/> implies that upon leaving the 
control, the input
-        will *not* be corrected to a valid value. For example, if the user 
enters "foo" in the
-        control, and then tabs out of it, the text "foo" will persist, and 
GetValue will
-        return NaN in subsequent calls.
-    */
-    void    EnableNotANumber( bool _bEnable );
-
-    /** When being set to true, the strings in the field are formatted using 
the
-        InputLine format.  That's also what you get in Calc when you edit a 
cell
-        using F2
-     */
-    void    UseInputStringForFormatting();
-    bool    IsUsingInputStringForFormatting() const { return 
m_bUseInputStringForFormatting;}
+    void SetValueFromString(const OUString& rStr); // currently used by online
 
     virtual void DumpAsPropertyTree(tools::JsonWriter&) override;
 
     virtual FactoryFunction GetUITestFactory() const override;
 
+    // Formatter overrides
+    virtual Selection GetEntrySelection() const override;
+    virtual OUString GetEntryText() const override;
+    virtual void SetEntryText(const OUString& rText, const Selection& rSel) 
override;
+    virtual void SetEntryTextColor(const Color* pColor) override;
+    virtual SelectionOptions GetEntrySelectionOptions() const override;
+    virtual void FieldModified() override;
+
 protected:
     virtual bool EventNotify(NotifyEvent& rNEvt) override;
-    void impl_Modify(bool makeValueDirty = true);
     virtual void Modify() override;
 
-    // Override CheckText for input-time checks
-    virtual bool CheckText(const OUString&) const { return true; }
-
-    // any aspect of the current format has changed
-    virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat);
-
-    void ImplSetTextImpl(const OUString& rNew, Selection const * pNewSel);
-    void ImplSetValue(double dValue, bool bForce);
-    bool ImplGetValue(double& dNewVal);
-
-    void ImplSetFormatKey(sal_uLong nFormatKey);
-        // SetFormatKey without FormatChanged notification
-
-    SvNumberFormatter*  CreateFormatter() { SetFormatter(StandardFormatter()); 
return m_pFormatter; }
-    SvNumberFormatter*  ImplGetFormatter() const { return m_pFormatter ? 
m_pFormatter : const_cast<FormattedField*>(this)->CreateFormatter(); }
-
     bool PreNotify(NotifyEvent& rNEvt) override;
-
-    void ReFormat();
-private:
-    Link<Edit&, bool>       m_aOutputHdl;
-    Link<sal_Int64*, TriState> m_aInputHdl;
 };
 
 class UNLESS_MERGELIBS(VCL_DLLPUBLIC) DoubleNumericField final : public 
FormattedField
diff --git a/include/vcl/formatter.hxx b/include/vcl/formatter.hxx
new file mode 100644
index 000000000000..8f02969635e9
--- /dev/null
+++ b/include/vcl/formatter.hxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <vcl/settings.hxx>
+#include <memory>
+
+class SvNumberFormatter;
+
+namespace validation { class NumberValidator; }
+
+enum class FORMAT_CHANGE_TYPE
+{
+    KEYONLY           = 0x00,        // only a new key was set
+    FORMATTER         = 0x01,        // a new formatter was set, usually 
implies a change of the key, too
+    PRECISION         = 0x02,        // a new precision was set
+    THOUSANDSSEP      = 0x03,        // the thousands separator setting changed
+    CURRENCY_SYMBOL   = 0x10,
+    CURRSYM_POSITION  = 0x20,
+};
+
+class VCL_DLLPUBLIC Formatter
+{
+private:
+    // A SvNumberFormatter is very expensive (regarding time and space), it is 
a Singleton
+    class StaticFormatter
+    {
+        static SvNumberFormatter*   s_cFormatter;
+        static sal_uLong                s_nReferences;
+    public:
+        StaticFormatter();
+        ~StaticFormatter();
+
+        operator SvNumberFormatter* () { return GetFormatter(); }
+        UNLESS_MERGELIBS(VCL_DLLPUBLIC) static SvNumberFormatter* 
GetFormatter();
+    };
+
+protected:
+    OUString      m_sLastValidText;
+    // Has nothing to do with the current value. It is the last text, which 
was valid at input (checked by CheckText,
+    // not yet through formatter)
+    Selection   m_aLastSelection;
+
+    double              m_dMinValue;
+    double              m_dMaxValue;
+    bool                m_bHasMin : 1;
+    bool                m_bHasMax : 1;
+
+    bool                m_bWrapOnLimits : 1;
+    bool                m_bStrictFormat : 1;
+
+    bool                m_bEnableEmptyField : 1;
+    bool                m_bAutoColor : 1;
+    bool                m_bEnableNaN : 1;
+    bool                m_bDisableRemainderFactor : 1;
+    enum valueState { valueDirty, valueString, valueDouble };
+    valueState          m_ValueState;
+    double              m_dCurrentValue;
+    double              m_dDefaultValue;
+
+    sal_uLong               m_nFormatKey;
+    SvNumberFormatter*  m_pFormatter;
+    StaticFormatter     m_aStaticFormatter;
+
+    double              m_dSpinSize;
+    double              m_dSpinFirst;
+    double              m_dSpinLast;
+
+    // There is a difference, when text formatting is enabled, if LostFocus 
formats the current String and displays it,
+    // or if a double is created from the String and then
+    bool                m_bTreatAsNumber;
+    // And with the following members we can use it for formatted text output 
as well ...
+    OUString            m_sCurrentTextValue;
+    OUString            m_sDefaultText;
+
+    // The last color from the Formatter at the last output operation (not we 
would use it, but you can get it)
+    Color*              m_pLastOutputColor;
+
+    bool                m_bUseInputStringForFormatting;
+
+    Link<sal_Int64*, TriState> m_aInputHdl;
+    Link<LinkParamNone*, bool> m_aOutputHdl;
+
+public:
+    Formatter();
+    virtual ~Formatter();
+
+    void SetFieldText(const OUString& rText, const Selection& rNewSelection);
+
+    virtual Selection GetEntrySelection() const = 0;
+    virtual OUString GetEntryText() const = 0;
+    virtual SelectionOptions GetEntrySelectionOptions() const = 0;
+    virtual void SetEntryText(const OUString& rText, const Selection& rSel) = 
0;
+    virtual void SetEntryTextColor(const Color* pColor) = 0;
+    virtual void FieldModified() = 0;
+
+    // Min-/Max-management
+    bool    HasMinValue() const         { return m_bHasMin; }
+    void    ClearMinValue()             { m_bHasMin = false; }
+    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);
+    double  GetMaxValue() const         { return m_dMaxValue; }
+
+    // Current value
+    void    SetValue(double dVal);
+    double  GetValue();
+    // The default implementation uses a formatter, if available
+
+    void    SetTextValue(const OUString& rText);
+    // The String is transformed to a double (with a formatter) and SetValue 
is called afterwards
+
+    bool    IsEmptyFieldEnabled() const         { return m_bEnableEmptyField; }
+    void    EnableEmptyField(bool bEnable);
+    // If disabled, the value will be reset to the last valid value on leave
+
+    void    SetDefaultValue(double dDefault)    { m_dDefaultValue = dDefault; 
m_ValueState = valueDirty; }
+    // If the current String is invalid, GetValue() returns this value
+    double  GetDefaultValue() const             { return m_dDefaultValue; }
+
+    // Settings for the format
+    sal_uLong   GetFormatKey() const                { return m_nFormatKey; }
+    void    SetFormatKey(sal_uLong nFormatKey);
+
+    SvNumberFormatter*  GetFormatter() const    { return m_pFormatter; }
+    void    SetFormatter(SvNumberFormatter* pFormatter, bool bResetFormat = 
true);
+    // If bResetFormat is sal_False, the old format is tried to be kept. 
(expensive, if it is no default format, available in all formatters)
+    // If sal_True, the new FormatKey is set to zero
+
+    bool    GetThousandsSep() const;
+    void    SetThousandsSep(bool _bUseSeparator);
+        // the is no check if the current format is numeric, so be cautious 
when calling these functions
+
+    void    DisableRemainderFactor();
+
+    sal_uInt16  GetDecimalDigits() const;
+    void    SetDecimalDigits(sal_uInt16 _nPrecision);
+        // There is no check if the current format is numeric, so be cautious 
when calling these functions
+
+    SvNumberFormatter*  StandardFormatter() { return m_aStaticFormatter; }
+    // If no new Formatter is created explicitly, this can be used in 
SetFormatter...
+
+    OUString    GetFormat(LanguageType& eLang) const;
+    bool        SetFormat(const OUString& rFormatString, LanguageType eLang);
+    // sal_False, if the FormatString could not be set (and very probably is 
invalid)
+    // This Object is shared via all instances, so be careful!
+
+    bool    IsStrictFormat() const              { return m_bStrictFormat; }
+    void    SetStrictFormat(bool bEnable)       { m_bStrictFormat = bEnable; }
+    // Check format during input
+
+    void    SetSpinSize(double dStep)   { m_dSpinSize = dStep; }
+    double  GetSpinSize() const         { return m_dSpinSize; }
+
+    void    SetSpinFirst(double dFirst) { m_dSpinFirst = dFirst; }
+    double  GetSpinFirst() const        { return m_dSpinFirst; }
+
+    void    SetSpinLast(double dLast)   { m_dSpinLast = dLast; }
+    double  GetSpinLast() const         { return m_dSpinLast; }
+
+    bool    TreatingAsNumber() const    { return m_bTreatAsNumber; }
+    void    TreatAsNumber(bool bDoSo) { m_bTreatAsNumber = bDoSo; }
+
+    void    SetInputHdl(const Link<sal_Int64*,TriState>& rLink) { m_aInputHdl 
= rLink; }
+    void    SetOutputHdl(const Link<LinkParamNone*, bool>& rLink) { 
m_aOutputHdl = rLink; }
+public:
+
+    //The following methods are interesting, if m_bTreatAsNumber is set to 
sal_False
+    //If someone does not care about all the double handling and just wants to 
print the text formatted.
+    //(((The text will be formatted, using the Formatter, and then set)
+    void SetTextFormatted(const OUString& rText);
+    OUString const & GetTextValue() const;
+
+    void      SetDefaultText(const OUString& rDefault) { m_sDefaultText = 
rDefault; }
+    const OUString& GetDefaultText() const { return m_sDefaultText; }
+
+    // The last colour from the Formatter's last output operation. Output 
operations get triggered by:
+    // SetValue, SetTextValue, SetTextFormatted, also indirectly via SetMin - 
/ -MaxValue
+    Color*  GetLastOutputColor() const { return m_pLastOutputColor; }
+
+    /** reformats the current text. Interesting if the user entered some text 
in an "input format", and
+        this should be formatted in the "output format" (which may differ, 
e.g. by additional numeric
+        digits or such).
+    */
+    void    Commit();
+
+    // enable automatic coloring. if set to sal_True, and the format the field 
is working with for any current value
+    // says that it has to be painted in a special color (e.g. a format where 
negative numbers should be printed
+    // red), the text is painted with that color automatically.
+    // The color used is the same as returned by GetLastOutputColor()
+    void    SetAutoColor(bool _bAutomatic);
+
+    /** enables handling of not-a-number value.
+
+        When this is set to <FALSE/> (the default), then invalid inputs (i.e. 
text which cannot be
+        interpreted, according to the current formatting) will be handled as 
if the default value
+        has been entered. GetValue the will return this default value.
+
+        When set to <TRUE/>, then GetValue will return NaN (not a number, see 
<method scope="rtl::math">isNan</method>)
+        when the current input is invalid.
+
+        Note that setting this to <TRUE/> implies that upon leaving the 
control, the input
+        will *not* be corrected to a valid value. For example, if the user 
enters "foo" in the
+        control, and then tabs out of it, the text "foo" will persist, and 
GetValue will
+        return NaN in subsequent calls.
+    */
+    void    EnableNotANumber( bool _bEnable );
+
+    /** When being set to true, the strings in the field are formatted using 
the
+        InputLine format.  That's also what you get in Calc when you edit a 
cell
+        using F2
+     */
+    void    UseInputStringForFormatting();
+    bool    IsUsingInputStringForFormatting() const { return 
m_bUseInputStringForFormatting;}
+
+protected:
+    void impl_Modify(bool makeValueDirty = true);
+
+    // Override CheckText for input-time checks
+    virtual bool CheckText(const OUString&) const { return true; }
+
+    // any aspect of the current format has changed
+    virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat);
+
+    void ImplSetTextImpl(const OUString& rNew, Selection const * pNewSel);
+    void ImplSetValue(double dValue, bool bForce);
+    bool ImplGetValue(double& dNewVal);
+
+    void ImplSetFormatKey(sal_uLong nFormatKey);
+        // SetFormatKey without FormatChanged notification
+
+    void EntryLostFocus();
+
+    SvNumberFormatter*  CreateFormatter() { SetFormatter(StandardFormatter()); 
return m_pFormatter; }
+    SvNumberFormatter*  ImplGetFormatter() const { return m_pFormatter ? 
m_pFormatter : const_cast<Formatter*>(this)->CreateFormatter(); }
+
+    void ReFormat();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index 52d307c81f1b..65e2e76c035a 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -7350,6 +7350,7 @@ include/vcl/extoutdevdata.hxx
 include/vcl/field.hxx
 include/vcl/fixed.hxx
 include/vcl/floatwin.hxx
+include/vcl/formatter.hxx
 include/vcl/fmtfield.hxx
 include/vcl/fntstyle.hxx
 include/vcl/font.hxx
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 7e1e0dc9defa..d44ad491a628 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -619,7 +619,7 @@ private:
 
     DECL_LINK(UpDownHdl, SpinField&, void);
     DECL_LINK(LoseFocusHdl, Control&, void);
-    DECL_LINK(OutputHdl, Edit&, bool);
+    DECL_LINK(OutputHdl, LinkParamNone*, bool);
     DECL_LINK(InputHdl, sal_Int64*, TriState);
     DECL_LINK(ActivateHdl, Edit&, bool);
 
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index cd1109bb4f36..67f26faf9e59 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5300,7 +5300,7 @@ SalInstanceSpinButton::~SalInstanceSpinButton()
     else
         m_xButton->SetActivateHdl(Link<Edit&, bool>());
     m_xButton->SetInputHdl(Link<sal_Int64*, TriState>());
-    m_xButton->SetOutputHdl(Link<Edit&, bool>());
+    m_xButton->SetOutputHdl(Link<LinkParamNone*, bool>());
     m_xButton->SetLoseFocusHdl(Link<Control&, void>());
     m_xButton->SetDownHdl(Link<SpinField&, void>());
     m_xButton->SetUpHdl(Link<SpinField&, void>());
@@ -5317,7 +5317,7 @@ IMPL_LINK_NOARG(SalInstanceSpinButton, UpDownHdl, 
SpinField&, void) { signal_val
 
 IMPL_LINK_NOARG(SalInstanceSpinButton, LoseFocusHdl, Control&, void) { 
signal_value_changed(); }
 
-IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, Edit&, bool) { return 
signal_output(); }
+IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, LinkParamNone*, bool) { 
return signal_output(); }
 
 IMPL_LINK(SalInstanceSpinButton, InputHdl, sal_Int64*, pResult, TriState)
 {
@@ -5336,7 +5336,7 @@ class SalInstanceFormattedSpinButton : public 
SalInstanceEntry,
 private:
     VclPtr<FormattedField> m_xButton;
 
-    DECL_LINK(OutputHdl, Edit&, bool);
+    DECL_LINK(OutputHdl, LinkParamNone*, bool);
     DECL_LINK(InputHdl, sal_Int64*, TriState);
 
 public:
@@ -5358,7 +5358,7 @@ public:
     virtual ~SalInstanceFormattedSpinButton() override
     {
         m_xButton->SetInputHdl(Link<sal_Int64*, TriState>());
-        m_xButton->SetOutputHdl(Link<Edit&, bool>());
+        m_xButton->SetOutputHdl(Link<LinkParamNone*, bool>());
     }
 
     virtual double get_value() const override { return m_xButton->GetValue(); }
@@ -5401,7 +5401,7 @@ public:
     virtual void set_digits(unsigned int digits) override { 
m_xButton->SetDecimalDigits(digits); }
 };
 
-IMPL_LINK_NOARG(SalInstanceFormattedSpinButton, OutputHdl, Edit&, bool)
+IMPL_LINK_NOARG(SalInstanceFormattedSpinButton, OutputHdl, LinkParamNone*, 
bool)
 {
     // allow an explicit handler
     if (!m_aOutputHdl.IsSet())
diff --git a/vcl/source/control/fmtfield.cxx b/vcl/source/control/fmtfield.cxx
index c00a721250dc..f3a703cc3306 100644
--- a/vcl/source/control/fmtfield.cxx
+++ b/vcl/source/control/fmtfield.cxx
@@ -296,9 +296,8 @@ FormattedField::StaticFormatter::~StaticFormatter()
     }
 }
 
-FormattedField::FormattedField(vcl::Window* pParent, WinBits nStyle)
-    :SpinField(pParent, nStyle, WindowType::FORMATTEDFIELD)
-    ,m_aLastSelection(0,0)
+Formatter::Formatter()
+    :m_aLastSelection(0,0)
     ,m_dMinValue(0)
     ,m_dMaxValue(0)
     ,m_bHasMin(false)
@@ -323,21 +322,17 @@ FormattedField::FormattedField(vcl::Window* pParent, 
WinBits nStyle)
 {
 }
 
-void FormattedField::SetText(const OUString& rStr)
+Formatter::~Formatter()
 {
-
-    SpinField::SetText(rStr);
-    m_ValueState = valueDirty;
 }
 
-void FormattedField::SetText( const OUString& rStr, const Selection& 
rNewSelection )
+void Formatter::SetFieldText(const OUString& rStr, const Selection& 
rNewSelection)
 {
-
-    SpinField::SetText( rStr, rNewSelection );
+    SetEntryText(rStr, rNewSelection);
     m_ValueState = valueDirty;
 }
 
-void FormattedField::SetTextFormatted(const OUString& rStr)
+void Formatter::SetTextFormatted(const OUString& rStr)
 {
     SAL_INFO_IF(ImplGetFormatter()->IsTextFormat(m_nFormatKey), "svtools",
         "FormattedField::SetTextFormatted : valid only with text formats !");
@@ -362,11 +357,11 @@ void FormattedField::SetTextFormatted(const OUString& 
rStr)
     }
 
     // calculate the new selection
-    Selection aSel(GetSelection());
+    Selection aSel(GetEntrySelection());
     Selection aNewSel(aSel);
     aNewSel.Justify();
     sal_Int32 nNewLen = sFormatted.getLength();
-    sal_Int32 nCurrentLen = GetText().getLength();
+    sal_Int32 nCurrentLen = GetEntryText().getLength();
     if ((nNewLen > nCurrentLen) && (aNewSel.Max() == nCurrentLen))
     {   // the new text is longer and the cursor was behind the last char (of 
the old text)
         if (aNewSel.Min() == 0)
@@ -374,7 +369,7 @@ void FormattedField::SetTextFormatted(const OUString& rStr)
             aNewSel.Max() = nNewLen;
             if (!nCurrentLen)
             {   // there wasn't really a previous selection (as there was no 
previous text), we're setting a new one -> check the selection options
-                SelectionOptions nSelOptions = 
GetSettings().GetStyleSettings().GetSelectionOptions();
+                SelectionOptions nSelOptions = GetEntrySelectionOptions();
                 if (nSelOptions & SelectionOptions::ShowFirst)
                 {   // selection should be from right to left -> swap min and 
max
                     aNewSel.Min() = aNewSel.Max();
@@ -392,21 +387,21 @@ void FormattedField::SetTextFormatted(const OUString& 
rStr)
         aNewSel.Max() = nNewLen;
     else
         aNewSel = aSel; // don't use the justified version
-    SpinField::SetText(sFormatted, aNewSel);
+    SetEntryText(sFormatted, aNewSel);
     m_ValueState = valueString;
 }
 
-OUString const & FormattedField::GetTextValue() const
+OUString const & Formatter::GetTextValue() const
 {
     if (m_ValueState != valueString )
     {
-        const_cast<FormattedField*>(this)->m_sCurrentTextValue = GetText();
-        const_cast<FormattedField*>(this)->m_ValueState = valueString;
+        const_cast<Formatter*>(this)->m_sCurrentTextValue = GetEntryText();
+        const_cast<Formatter*>(this)->m_ValueState = valueString;
     }
     return m_sCurrentTextValue;
 }
 
-void FormattedField::EnableNotANumber( bool _bEnable )
+void Formatter::EnableNotANumber(bool _bEnable)
 {
     if ( m_bEnableNaN == _bEnable )
         return;
@@ -414,37 +409,34 @@ void FormattedField::EnableNotANumber( bool _bEnable )
     m_bEnableNaN = _bEnable;
 }
 
-void FormattedField::SetAutoColor(bool _bAutomatic)
+void Formatter::SetAutoColor(bool _bAutomatic)
 {
     if (_bAutomatic == m_bAutoColor)
         return;
 
     m_bAutoColor = _bAutomatic;
     if (m_bAutoColor)
-    {   // if auto color is switched on, adjust the current text color, too
-        if (m_pLastOutputColor)
-            SetControlForeground(*m_pLastOutputColor);
-        else
-            SetControlForeground();
+    {
+        // if auto color is switched on, adjust the current text color, too
+        SetEntryTextColor(m_pLastOutputColor);
     }
 }
 
-void FormattedField::impl_Modify(bool makeValueDirty)
+void Formatter::impl_Modify(bool makeValueDirty)
 {
-
     if (!IsStrictFormat())
     {
         if(makeValueDirty)
             m_ValueState = valueDirty;
-        SpinField::Modify();
+        FieldModified();
         return;
     }
 
-    OUString sCheck = GetText();
+    OUString sCheck = GetEntryText();
     if (CheckText(sCheck))
     {
         m_sLastValidText = sCheck;
-        m_aLastSelection = GetSelection();
+        m_aLastSelection = GetEntrySelection();
         if(makeValueDirty)
             m_ValueState = valueDirty;
     }
@@ -453,35 +445,23 @@ void FormattedField::impl_Modify(bool makeValueDirty)
         ImplSetTextImpl(m_sLastValidText, &m_aLastSelection);
     }
 
-    SpinField::Modify();
-}
-
-void FormattedField::Modify()
-{
-
-    impl_Modify();
+    FieldModified();
 }
 
-void FormattedField::ImplSetTextImpl(const OUString& rNew, Selection const * 
pNewSel)
+void Formatter::ImplSetTextImpl(const OUString& rNew, Selection const * 
pNewSel)
 {
-
     if (m_bAutoColor)
-    {
-        if (m_pLastOutputColor)
-            SetControlForeground(*m_pLastOutputColor);
-        else
-            SetControlForeground();
-    }
+        SetEntryTextColor(m_pLastOutputColor);
 
     if (pNewSel)
-        SpinField::SetText(rNew, *pNewSel);
+        SetEntryText(rNew, *pNewSel);
     else
     {
-        Selection aSel(GetSelection());
+        Selection aSel(GetEntrySelection());
         aSel.Justify();
 
         sal_Int32 nNewLen = rNew.getLength();
-        sal_Int32 nCurrentLen = GetText().getLength();
+        sal_Int32 nCurrentLen = GetEntryText().getLength();
 
         if ((nNewLen > nCurrentLen) && (aSel.Max() == nCurrentLen))
         {   // new text is longer and the cursor is behind the last char
@@ -504,20 +484,13 @@ void FormattedField::ImplSetTextImpl(const OUString& 
rNew, Selection const * pNe
         }
         else if (aSel.Max() > nNewLen)
             aSel.Max() = nNewLen;
-        SpinField::SetText(rNew, aSel);
+        SetEntryText(rNew, aSel);
     }
 
     m_ValueState = valueDirty; // not always necessary, but better re-evaluate 
for safety reasons
 }
 
-bool FormattedField::PreNotify(NotifyEvent& rNEvt)
-{
-    if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
-        m_aLastSelection = GetSelection();
-    return SpinField::PreNotify(rNEvt);
-}
-
-void FormattedField::ImplSetFormatKey(sal_uLong nFormatKey)
+void Formatter::ImplSetFormatKey(sal_uLong nFormatKey)
 {
 
     m_nFormatKey = nFormatKey;
@@ -536,14 +509,14 @@ void FormattedField::ImplSetFormatKey(sal_uLong 
nFormatKey)
     }
 }
 
-void FormattedField::SetFormatKey(sal_uLong nFormatKey)
+void Formatter::SetFormatKey(sal_uLong nFormatKey)
 {
     bool bNoFormatter = (m_pFormatter == nullptr);
     ImplSetFormatKey(nFormatKey);
     FormatChanged((bNoFormatter && (m_pFormatter != nullptr)) ? 
FORMAT_CHANGE_TYPE::FORMATTER : FORMAT_CHANGE_TYPE::KEYONLY);
 }
 
-void FormattedField::SetFormatter(SvNumberFormatter* pFormatter, bool 
bResetFormat)
+void Formatter::SetFormatter(SvNumberFormatter* pFormatter, bool bResetFormat)
 {
 
     if (bResetFormat)
@@ -585,7 +558,7 @@ void FormattedField::SetFormatter(SvNumberFormatter* 
pFormatter, bool bResetForm
     FormatChanged(FORMAT_CHANGE_TYPE::FORMATTER);
 }
 
-OUString FormattedField::GetFormat(LanguageType& eLang) const
+OUString Formatter::GetFormat(LanguageType& eLang) const
 {
     const SvNumberformat* pFormatEntry = 
ImplGetFormatter()->GetEntry(m_nFormatKey);
     DBG_ASSERT(pFormatEntry != nullptr, "FormattedField::GetFormat: no number 
format for the given format key.");
@@ -595,7 +568,7 @@ OUString FormattedField::GetFormat(LanguageType& eLang) 
const
     return sFormatString;
 }
 
-bool FormattedField::SetFormat(const OUString& rFormatString, LanguageType 
eLang)
+bool Formatter::SetFormat(const OUString& rFormatString, LanguageType eLang)
 {
     sal_uInt32 nNewKey = ImplGetFormatter()->TestNewString(rFormatString, 
eLang);
     if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
@@ -613,7 +586,7 @@ bool FormattedField::SetFormat(const OUString& 
rFormatString, LanguageType eLang
     return true;
 }
 
-bool FormattedField::GetThousandsSep() const
+bool Formatter::GetThousandsSep() const
 {
     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
         "FormattedField::GetThousandsSep : Are you sure what you are doing 
when setting the precision of a text format?");
@@ -625,7 +598,7 @@ bool FormattedField::GetThousandsSep() const
     return bThousand;
 }
 
-void FormattedField::SetThousandsSep(bool _bUseSeparator)
+void Formatter::SetThousandsSep(bool _bUseSeparator)
 {
     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
         "FormattedField::SetThousandsSep : Are you sure what you are doing 
when setting the precision of a text format?");
@@ -654,7 +627,7 @@ void FormattedField::SetThousandsSep(bool _bUseSeparator)
     FormatChanged(FORMAT_CHANGE_TYPE::THOUSANDSSEP);
 }
 
-sal_uInt16 FormattedField::GetDecimalDigits() const
+sal_uInt16 Formatter::GetDecimalDigits() const
 {
     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
         "FormattedField::GetDecimalDigits : Are you sure what you are doing 
when setting the precision of a text format?");
@@ -666,7 +639,7 @@ sal_uInt16 FormattedField::GetDecimalDigits() const
     return nPrecision;
 }
 
-void FormattedField::SetDecimalDigits(sal_uInt16 _nPrecision)
+void Formatter::SetDecimalDigits(sal_uInt16 _nPrecision)
 {
     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
         "FormattedField::SetDecimalDigits : Are you sure what you are doing 
when setting the precision of a text format?");
@@ -695,7 +668,7 @@ void FormattedField::SetDecimalDigits(sal_uInt16 
_nPrecision)
     FormatChanged(FORMAT_CHANGE_TYPE::PRECISION);
 }
 
-void FormattedField::FormatChanged( FORMAT_CHANGE_TYPE _nWhat )
+void Formatter::FormatChanged(FORMAT_CHANGE_TYPE _nWhat)
 {
     m_pLastOutputColor = nullptr;
 
@@ -705,16 +678,46 @@ void FormattedField::FormatChanged( FORMAT_CHANGE_TYPE 
_nWhat )
     ReFormat();
 }
 
-void FormattedField::Commit()
+void Formatter::EntryLostFocus()
+{
+    // special treatment for empty texts
+    if (GetEntryText().isEmpty())
+    {
+        if (!IsEmptyFieldEnabled())
+        {
+            if (TreatingAsNumber())
+            {
+                ImplSetValue(m_dCurrentValue, true);
+                impl_Modify();
+                m_ValueState = valueDouble;
+            }
+            else
+            {
+                OUString sNew = GetTextValue();
+                if (!sNew.isEmpty())
+                    SetTextFormatted(sNew);
+                else
+                    SetTextFormatted(m_sDefaultText);
+                m_ValueState = valueString;
+            }
+        }
+    }
+    else
+    {
+        Commit();
+    }
+}
+
+void Formatter::Commit()
 {
     // remember the old text
-    OUString sOld( GetText() );
+    OUString sOld(GetEntryText());
 
     // do the reformat
     ReFormat();
 
     // did the text change?
-    if ( GetText() != sOld )
+    if (GetEntryText() != sOld)
     {   // consider the field as modified,
         // but we already have the most recent value;
         // don't reparse it from the text
@@ -724,9 +727,9 @@ void FormattedField::Commit()
     }
 }
 
-void FormattedField::ReFormat()
+void Formatter::ReFormat()
 {
-    if (!IsEmptyFieldEnabled() || !GetText().isEmpty())
+    if (!IsEmptyFieldEnabled() || !GetEntryText().isEmpty())
     {
         if (TreatingAsNumber())
         {
@@ -740,78 +743,8 @@ void FormattedField::ReFormat()
     }
 }
 
-bool FormattedField::EventNotify(NotifyEvent& rNEvt)
-{
-
-    if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !IsReadOnly())
-    {
-        const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
-        sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
-        switch ( rKEvt.GetKeyCode().GetCode() )
-        {
-            case KEY_UP:
-            case KEY_DOWN:
-            case KEY_PAGEUP:
-            case KEY_PAGEDOWN:
-                if (!nMod && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
-                {
-                    // the base class would translate this into calls to 
Up/Down/First/Last,
-                    // but we don't want this if we are text-formatted
-                    return true;
-                }
-        }
-    }
-
-    if ((rNEvt.GetType() == MouseNotifyEvent::COMMAND) && !IsReadOnly())
-    {
-        const CommandEvent* pCommand = rNEvt.GetCommandEvent();
-        if (pCommand->GetCommand() == CommandEventId::Wheel)
-        {
-            const CommandWheelData* pData = 
rNEvt.GetCommandEvent()->GetWheelData();
-            if ((pData->GetMode() == CommandWheelMode::SCROLL) && 
ImplGetFormatter()->IsTextFormat(m_nFormatKey))
-            {
-                // same as above : prevent the base class from doing 
Up/Down-calls
-                // (normally I should put this test into the Up/Down methods 
itself, shouldn't I ?)
-                // FS - 71553 - 19.01.00
-                return true;
-            }
-        }
-    }
 
-    if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS)
-    {
-        // special treatment for empty texts
-        if (GetText().isEmpty())
-        {
-            if (!IsEmptyFieldEnabled())
-            {
-                if (TreatingAsNumber())
-                {
-                    ImplSetValue(m_dCurrentValue, true);
-                    Modify();
-                    m_ValueState = valueDouble;
-                }
-                else
-                {
-                    OUString sNew = GetTextValue();
-                    if (!sNew.isEmpty())
-                        SetTextFormatted(sNew);
-                    else
-                        SetTextFormatted(m_sDefaultText);
-                    m_ValueState = valueString;
-                }
-            }
-        }
-        else
-        {
-            Commit();
-        }
-    }
-
-    return SpinField::EventNotify( rNEvt );
-}
-
-void FormattedField::SetMinValue(double dMin)
+void Formatter::SetMinValue(double dMin)
 {
     DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be 
used in numeric mode !");
 
@@ -821,7 +754,7 @@ void FormattedField::SetMinValue(double dMin)
     ReFormat();
 }
 
-void FormattedField::SetMaxValue(double dMax)
+void Formatter::SetMaxValue(double dMax)
 {
     DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMaxValue : only to be 
used in numeric mode !");
 
@@ -831,46 +764,23 @@ void FormattedField::SetMaxValue(double dMax)
     ReFormat();
 }
 
-void FormattedField::SetTextValue(const OUString& rText)
+void Formatter::SetTextValue(const OUString& rText)
 {
-    SetText(rText);
+    SetFieldText(rText, Selection(0, 0));
     ReFormat();
 }
 
-// currently used by online
-void FormattedField::SetValueFromString(const OUString& rStr)
-{
-    sal_Int32 nEnd;
-    rtl_math_ConversionStatus eStatus;
-    double fValue = ::rtl::math::stringToDouble(rStr, '.', GetDecimalDigits(), 
&eStatus, &nEnd );
-
-    if (eStatus == rtl_math_ConversionStatus_Ok &&
-        nEnd == rStr.getLength())
-    {
-        SetValue(fValue);
-        SetModifyFlag();
-        Modify();
-
-        // Notify the value has changed
-        SpinField::Up();
-    }
-    else
-    {
-        SAL_WARN("vcl", "fail to convert the value: " << rStr);
-    }
-}
-
-void FormattedField::EnableEmptyField(bool bEnable)
+void Formatter::EnableEmptyField(bool bEnable)
 {
     if (bEnable == m_bEnableEmptyField)
         return;
 
     m_bEnableEmptyField = bEnable;
-    if (!m_bEnableEmptyField && GetText().isEmpty())
+    if (!m_bEnableEmptyField && GetEntryText().isEmpty())
         ImplSetValue(m_dCurrentValue, true);
 }
 
-void FormattedField::ImplSetValue(double dVal, bool bForce)
+void Formatter::ImplSetValue(double dVal, bool bForce)
 {
     if (m_bHasMin && (dVal<m_dMinValue))
     {
@@ -890,7 +800,7 @@ void FormattedField::ImplSetValue(double dVal, bool bForce)
     m_ValueState = valueDouble;
     m_dCurrentValue = dVal;
 
-    if (!m_aOutputHdl.IsSet() || !m_aOutputHdl.Call(*this))
+    if (!m_aOutputHdl.IsSet() || !m_aOutputHdl.Call(nullptr))
     {
         OUString sNewText;
         if (ImplGetFormatter()->IsTextFormat(m_nFormatKey))
@@ -919,14 +829,14 @@ void FormattedField::ImplSetValue(double dVal, bool 
bForce)
     m_ValueState = valueDouble;
 }
 
-bool FormattedField::ImplGetValue(double& dNewVal)
+bool Formatter::ImplGetValue(double& dNewVal)
 {
     dNewVal = m_dCurrentValue;
     if (m_ValueState == valueDouble)
         return true;
 
     dNewVal = m_dDefaultValue;
-    OUString sText(GetText());
+    OUString sText(GetEntryText());
     if (sText.isEmpty())
         return true;
 
@@ -987,12 +897,12 @@ bool FormattedField::ImplGetValue(double& dNewVal)
     return true;
 }
 
-void FormattedField::SetValue(double dVal)
+void Formatter::SetValue(double dVal)
 {
     ImplSetValue(dVal, m_ValueState != valueDouble);
 }
 
-double FormattedField::GetValue()
+double Formatter::GetValue()
 {
 
     if ( !ImplGetValue( m_dCurrentValue ) )
@@ -1007,104 +917,17 @@ double FormattedField::GetValue()
     return m_dCurrentValue;
 }
 
-void FormattedField::DisableRemainderFactor()
+void Formatter::DisableRemainderFactor()
 {
     m_bDisableRemainderFactor = true;
 }
 
-bool FormattedField::set_property(const OString &rKey, const OUString &rValue)
-{
-    if (rKey == "digits")
-        SetDecimalDigits(rValue.toInt32());
-    else if (rKey == "wrap")
-        m_bWrapOnLimits = toBool(rValue);
-    else
-        return SpinField::set_property(rKey, rValue);
-    return true;
-}
 
-void FormattedField::Up()
-{
-    auto nScale = weld::SpinButton::Power10(GetDecimalDigits());
-
-    sal_Int64 nValue = std::round(GetValue() * nScale);
-    sal_Int64 nSpinSize = std::round(m_dSpinSize * nScale);
-    sal_Int64 nRemainder = m_bDisableRemainderFactor ? 0 : nValue % nSpinSize;
-    if (nValue >= 0)
-        nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue + nSpinSize - 
nRemainder;
-    else
-        nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue - nRemainder;
-
-    // setValue handles under- and overflows (min/max) automatically
-    SetValue(static_cast<double>(nValue) / nScale);
-    SetModifyFlag();
-    Modify();
-
-    SpinField::Up();
-}
-
-void FormattedField::Down()
-{
-    auto nScale = weld::SpinButton::Power10(GetDecimalDigits());
-
-    sal_Int64 nValue = std::round(GetValue() * nScale);
-    sal_Int64 nSpinSize = std::round(m_dSpinSize * nScale);
-    sal_Int64 nRemainder = m_bDisableRemainderFactor ? 0 : nValue % nSpinSize;
-    if (nValue >= 0)
-        nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nRemainder;
-    else
-        nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nSpinSize - 
nRemainder;
-
-    // setValue handles under- and overflows (min/max) automatically
-    SetValue(static_cast<double>(nValue) / nScale);
-    SetModifyFlag();
-    Modify();
-
-    SpinField::Down();
-}
-
-void FormattedField::First()
-{
-    if (m_bHasMin)
-    {
-        SetValue(m_dMinValue);
-        SetModifyFlag();
-        Modify();
-    }
-
-    SpinField::First();
-}
-
-void FormattedField::Last()
-{
-    if (m_bHasMax)
-    {
-        SetValue(m_dMaxValue);
-        SetModifyFlag();
-        Modify();
-    }
-
-    SpinField::Last();
-}
-
-void FormattedField::UseInputStringForFormatting()
+void Formatter::UseInputStringForFormatting()
 {
     m_bUseInputStringForFormatting = true;
 }
 
-void FormattedField::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
-{
-    SpinField::DumpAsPropertyTree(rJsonWriter);
-    rJsonWriter.put("min", GetMinValue());
-    rJsonWriter.put("max", GetMaxValue());
-    rJsonWriter.put("value", GetValue());
-}
-
-FactoryFunction FormattedField::GetUITestFactory() const
-{
-    return FormattedFieldUIObject::create;
-}
-
 DoubleNumericField::DoubleNumericField(vcl::Window* pParent, WinBits nStyle)
     : FormattedField(pParent, nStyle)
 {
@@ -1284,4 +1107,220 @@ void DoubleCurrencyField::UpdateCurrencyFormat()
     m_bChangingFormat = false;
 }
 
+FormattedField::FormattedField(vcl::Window* pParent, WinBits nStyle)
+    : SpinField(pParent, nStyle, WindowType::FORMATTEDFIELD)
+{
+}
+
+void FormattedField::SetText(const OUString& rStr)
+{
+    SetFieldText(rStr, Selection(0, 0));
+}
+
+void FormattedField::SetText(const OUString& rStr, const Selection& 
rNewSelection)
+{
+    SetFieldText(rStr, rNewSelection);
+    SetSelection(rNewSelection);
+}
+
+bool FormattedField::set_property(const OString &rKey, const OUString &rValue)
+{
+    if (rKey == "digits")
+        SetDecimalDigits(rValue.toInt32());
+    else if (rKey == "wrap")
+        m_bWrapOnLimits = toBool(rValue);
+    else
+        return SpinField::set_property(rKey, rValue);
+    return true;
+}
+
+void FormattedField::Up()
+{
+    auto nScale = weld::SpinButton::Power10(GetDecimalDigits());
+
+    sal_Int64 nValue = std::round(GetValue() * nScale);
+    sal_Int64 nSpinSize = std::round(m_dSpinSize * nScale);
+    sal_Int64 nRemainder = m_bDisableRemainderFactor ? 0 : nValue % nSpinSize;
+    if (nValue >= 0)
+        nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue + nSpinSize - 
nRemainder;
+    else
+        nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue - nRemainder;
+
+    // setValue handles under- and overflows (min/max) automatically
+    SetValue(static_cast<double>(nValue) / nScale);
+    SetModifyFlag();
+    Modify();
+
+    SpinField::Up();
+}
+
+void FormattedField::Down()
+{
+    auto nScale = weld::SpinButton::Power10(GetDecimalDigits());
+
+    sal_Int64 nValue = std::round(GetValue() * nScale);
+    sal_Int64 nSpinSize = std::round(m_dSpinSize * nScale);
+    sal_Int64 nRemainder = m_bDisableRemainderFactor ? 0 : nValue % nSpinSize;
+    if (nValue >= 0)
+        nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nRemainder;
+    else
+        nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nSpinSize - 
nRemainder;
+
+    // setValue handles under- and overflows (min/max) automatically
+    SetValue(static_cast<double>(nValue) / nScale);
+    SetModifyFlag();
+    Modify();
+
+    SpinField::Down();
+}
+
+void FormattedField::First()
+{
+    if (m_bHasMin)
+    {
+        SetValue(m_dMinValue);
+        SetModifyFlag();
+        Modify();
+    }
+
+    SpinField::First();
+}
+
+void FormattedField::Last()
+{
+    if (m_bHasMax)
+    {
+        SetValue(m_dMaxValue);
+        SetModifyFlag();
+        Modify();
+    }
+
+    SpinField::Last();
+}
+
+void FormattedField::Modify()
+{
+    impl_Modify();
+}
+
+bool FormattedField::PreNotify(NotifyEvent& rNEvt)
+{
+    if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
+        m_aLastSelection = GetSelection();
+    return SpinField::PreNotify(rNEvt);
+}
+
+bool FormattedField::EventNotify(NotifyEvent& rNEvt)
+{
+
+    if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !IsReadOnly())
+    {
+        const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
+        sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
+        switch ( rKEvt.GetKeyCode().GetCode() )
+        {
+            case KEY_UP:
+            case KEY_DOWN:
+            case KEY_PAGEUP:
+            case KEY_PAGEDOWN:
+                if (!nMod && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
+                {
+                    // the base class would translate this into calls to 
Up/Down/First/Last,
+                    // but we don't want this if we are text-formatted
+                    return true;
+                }
+        }
+    }
+
+    if ((rNEvt.GetType() == MouseNotifyEvent::COMMAND) && !IsReadOnly())
+    {
+        const CommandEvent* pCommand = rNEvt.GetCommandEvent();
+        if (pCommand->GetCommand() == CommandEventId::Wheel)
+        {
+            const CommandWheelData* pData = 
rNEvt.GetCommandEvent()->GetWheelData();
+            if ((pData->GetMode() == CommandWheelMode::SCROLL) && 
ImplGetFormatter()->IsTextFormat(m_nFormatKey))
+            {
+                // same as above : prevent the base class from doing 
Up/Down-calls
+                // (normally I should put this test into the Up/Down methods 
itself, shouldn't I ?)
+                // FS - 71553 - 19.01.00
+                return true;
+            }
+        }
+    }
+
+    if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS)
+        EntryLostFocus();
+
+    return SpinField::EventNotify( rNEvt );
+}
+
+Selection FormattedField::GetEntrySelection() const
+{
+    return GetSelection();
+}
+
+OUString FormattedField::GetEntryText() const
+{
+    return GetText();
+}
+
+void FormattedField::SetEntryText(const OUString& rText, const Selection& rSel)
+{
+    SpinField::SetText(rText, rSel);
+}
+
+void FormattedField::SetEntryTextColor(const Color* pColor)
+{
+    if (pColor)
+        SetControlForeground(*pColor);
+    else
+        SetControlForeground();
+}
+
+SelectionOptions FormattedField::GetEntrySelectionOptions() const
+{
+    return GetSettings().GetStyleSettings().GetSelectionOptions();
+}
+
+void FormattedField::FieldModified()
+{
+    SpinField::Modify();
+}
+
+// currently used by online
+void FormattedField::SetValueFromString(const OUString& rStr)
+{
+    sal_Int32 nEnd;
+    rtl_math_ConversionStatus eStatus;
+    double fValue = ::rtl::math::stringToDouble(rStr, '.', GetDecimalDigits(), 
&eStatus, &nEnd );
+
+    if (eStatus == rtl_math_ConversionStatus_Ok &&
+        nEnd == rStr.getLength())
+    {
+        SetValue(fValue);
+        SetModifyFlag();
+        Modify();
+
+        // Notify the value has changed
+        SpinField::Up();
+    }
+    else
+    {
+        SAL_WARN("vcl", "fail to convert the value: " << rStr);
+    }
+}
+
+void FormattedField::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
+{
+    SpinField::DumpAsPropertyTree(rJsonWriter);
+    rJsonWriter.put("min", GetMinValue());
+    rJsonWriter.put("max", GetMaxValue());
+    rJsonWriter.put("value", GetValue());
+}
+
+FactoryFunction FormattedField::GetUITestFactory() const
+{
+    return FormattedFieldUIObject::create;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to