weld FormattedControl

by using the newly split out Formatter to do the number formatting
but input/output to/from a weld::Entry

Change-Id: Ic9e619dc5d1ed2fae87e2d89a40dc51f3881468f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97660
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/chart2/source/controller/dialogs/DataBrowser.cxx b/chart2/source/controller/dialogs/DataBrowser.cxx
index a693b14..6971be7 100644
--- a/chart2/source/controller/dialogs/DataBrowser.cxx
+++ b/chart2/source/controller/dialogs/DataBrowser.cxx
@@ -497,7 +497,7 @@ DataBrowser::DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent,
    m_nSeekRow( 0 ),
    m_bIsReadOnly( false ),
    m_bDataValid( true ),
    m_aNumberEditField( VclPtr<FormattedField>::Create( & EditBrowseBox::GetDataWindow(), WB_NOBORDER ) ),
    m_aNumberEditField(VclPtr<FormattedControl>::Create(&EditBrowseBox::GetDataWindow())),
    m_aTextEditField(VclPtr<EditControl>::Create(&EditBrowseBox::GetDataWindow())),
    m_pColumnsWin(pColumns),
    m_pColorsWin(pColors),
@@ -506,8 +506,9 @@ DataBrowser::DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent,
{
    double fNan;
    ::rtl::math::setNan( & fNan );
    m_aNumberEditField->SetDefaultValue( fNan );
    m_aNumberEditField->TreatAsNumber( true );
    Formatter& rFormatter = m_aNumberEditField->get_formatter();
    rFormatter.SetDefaultValue( fNan );
    rFormatter.TreatAsNumber( true );
    RenewTable();
}

@@ -828,7 +829,7 @@ bool DataBrowser::IsDataValid() const
    {
        sal_uInt32 nDummy = 0;
        double fDummy = 0.0;
        OUString aText( m_aNumberEditField->GetText());
        OUString aText(m_aNumberEditField->get_widget().get_text());

        if( !aText.isEmpty() &&
            m_spNumberFormatterWrapper &&
@@ -860,7 +861,8 @@ void DataBrowser::SetDataFromModel(
        std::make_shared<NumberFormatterWrapper>(
            Reference< util::XNumberFormatsSupplier >( m_xChartDoc, uno::UNO_QUERY ));

    m_aNumberEditField->SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() );
    Formatter& rFormatter = m_aNumberEditField->get_formatter();
    rFormatter.SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() );

    RenewTable();

@@ -1114,8 +1116,9 @@ bool DataBrowser::IsTabAllowed( bool bForward ) const

    if( CellContainsNumbers( nCol ))
    {
        m_aNumberEditField->UseInputStringForFormatting();
        m_aNumberEditField->SetFormatKey( GetNumberFormatKey( nCol ));
        Formatter& rFormatter = m_aNumberEditField->get_formatter();
        rFormatter.UseInputStringForFormatting();
        rFormatter.SetFormatKey( GetNumberFormatKey( nCol ));
        return m_rNumberEditController.get();
    }

@@ -1135,13 +1138,14 @@ void DataBrowser::InitController(
    else if( rController == m_rNumberEditController )
    {
        // treat invalid and empty text as Nan
        m_aNumberEditField->EnableNotANumber( true );
        Formatter& rFormatter = m_aNumberEditField->get_formatter();
        rFormatter.EnableNotANumber( true );
        if( std::isnan( GetCellNumber( nRow, nCol )))
            m_aNumberEditField->SetTextValue( OUString());
            rFormatter.SetTextValue( OUString());
        else
            m_aNumberEditField->SetValue( GetCellNumber( nRow, nCol ) );
        OUString aText( m_aNumberEditField->GetText());
        m_aNumberEditField->SetSelection( ::Selection( 0, aText.getLength()));
            rFormatter.SetValue( GetCellNumber( nRow, nCol ) );
        weld::Entry& rEntry = m_aNumberEditField->get_widget();
        rEntry.select_region(0, -1);
    }
    else
    {
@@ -1194,7 +1198,7 @@ bool DataBrowser::SaveModified()
        {
            sal_uInt32 nDummy = 0;
            double fDummy = 0.0;
            OUString aText( m_aNumberEditField->GetText());
            OUString aText(m_aNumberEditField->get_widget().get_text());
            // an empty string is valid, if no numberformatter exists, all
            // values are treated as valid
            if( !aText.isEmpty() && pSvNumberFormatter &&
@@ -1204,7 +1208,8 @@ bool DataBrowser::SaveModified()
            }
            else
            {
                double fData = m_aNumberEditField->GetValue();
                Formatter& rFormatter = m_aNumberEditField->get_formatter();
                double fData = rFormatter.GetValue();
                bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData );
            }
        }
diff --git a/chart2/source/controller/dialogs/DataBrowser.hxx b/chart2/source/controller/dialogs/DataBrowser.hxx
index 7f21338..a199122 100644
--- a/chart2/source/controller/dialogs/DataBrowser.hxx
+++ b/chart2/source/controller/dialogs/DataBrowser.hxx
@@ -21,7 +21,6 @@
#define INCLUDED_CHART2_SOURCE_CONTROLLER_DIALOGS_DATABROWSER_HXX

#include <svtools/editbrowsebox.hxx>
#include <vcl/fmtfield.hxx>
#include <vcl/weld.hxx>

#include <memory>
@@ -160,7 +159,7 @@ private:
    bool                m_bIsReadOnly;
    bool                m_bDataValid;

    VclPtr<FormattedField>      m_aNumberEditField;
    VclPtr<svt::FormattedControl> m_aNumberEditField;
    VclPtr<svt::EditControl>    m_aTextEditField;
    weld::Container*            m_pColumnsWin;
    weld::Container*            m_pColorsWin;
diff --git a/dbaccess/source/ui/browser/brwctrlr.cxx b/dbaccess/source/ui/browser/brwctrlr.cxx
index c6a414a..8a0bb0c 100644
--- a/dbaccess/source/ui/browser/brwctrlr.cxx
+++ b/dbaccess/source/ui/browser/brwctrlr.cxx
@@ -1457,11 +1457,11 @@ FeatureState SbaXDataBrowserController::GetState(sal_uInt16 nId) const
            case ID_BROWSER_CUT:
            {
                CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller();
                if (xCurrentController.is() && nullptr != dynamic_cast< const EditCellController* >(xCurrentController.get()))
                if (const EditCellController* pController = dynamic_cast<const EditCellController*>(xCurrentController.get()))
                {
                    Edit& rEdit = static_cast<Edit&>(xCurrentController->GetWindow());
                    bool bHasLen = (rEdit.GetSelection().Len() != 0);
                    bool bIsReadOnly = rEdit.IsReadOnly();
                    const IEditImplementation* pEditImplementation = pController->GetEditImplementation();
                    bool bHasLen = pEditImplementation->GetSelection().Len() != 0;
                    bool bIsReadOnly = pEditImplementation->IsReadOnly();
                    switch (nId)
                    {
                        case ID_BROWSER_CUT:    aReturn.bEnabled = m_aCurrentFrame.isActive() && bHasLen && !bIsReadOnly; break;
@@ -1927,22 +1927,23 @@ void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< Property
        case ID_BROWSER_PASTE:
        {
            CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller();
            if (!xCurrentController.is())
                // should be intercepted by GetState. Normally.
                // Unfortunately ID_BROWSER_PASTE is a 'fast call' slot, which means it may be executed without checking if it is
                // enabled. This would be really deadly herein if the current cell has no controller ...
                return;

            Edit& rEdit = static_cast<Edit&>(xCurrentController->GetWindow());
            switch (nId)
            if (EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get()))
            {
                case ID_BROWSER_CUT :       rEdit.Cut();    break;
                case SID_COPY   :           rEdit.Copy();   break;
                case ID_BROWSER_PASTE   :   rEdit.Paste();  break;
            }
            if (ID_BROWSER_CUT == nId || ID_BROWSER_PASTE == nId)
            {
                rEdit.Modify();
                IEditImplementation* pEditImplementation = pController->GetEditImplementation();
                switch (nId)
                {
                    case ID_BROWSER_CUT:
                        pEditImplementation->Cut();
                        break;
                    case SID_COPY:
                        pEditImplementation->Copy();
                        break;
                    case ID_BROWSER_PASTE:
                        pEditImplementation->Paste();
                        break;
                }
                if (ID_BROWSER_CUT == nId || ID_BROWSER_PASTE == nId)
                    pController->Modify();
            }
        }
        break;
diff --git a/dbaccess/source/ui/browser/sbagrid.cxx b/dbaccess/source/ui/browser/sbagrid.cxx
index 2089f5d..b3f442e 100644
--- a/dbaccess/source/ui/browser/sbagrid.cxx
+++ b/dbaccess/source/ui/browser/sbagrid.cxx
@@ -1309,9 +1309,9 @@ sal_Int8 SbaGridControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt )
            ActivateCell();

        CellControllerRef xCurrentController = Controller();
        if (!xCurrentController.is() || nullptr == dynamic_cast< const EditCellController* >(xCurrentController.get()))
        EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get());
        if (!pController)
            return DND_ACTION_NONE;
        Edit& rEdit = static_cast<Edit&>(xCurrentController->GetWindow());

        // get the dropped string
        TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable );
@@ -1319,9 +1319,10 @@ sal_Int8 SbaGridControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt )
        if ( !aDropped.GetString( SotClipboardFormatId::STRING, sDropped ) )
            return DND_ACTION_NONE;

        rEdit.SetText( sDropped );
        IEditImplementation* pEditImplementation = pController->GetEditImplementation();
        pEditImplementation->SetText(sDropped);
        // SetText itself doesn't call a Modify as it isn't a user interaction
        rEdit.Modify();
        pController->Modify();

        return DND_ACTION_COPY;
    }
diff --git a/dbaccess/source/ui/control/TableGrantCtrl.cxx b/dbaccess/source/ui/control/TableGrantCtrl.cxx
index 729106e..dd2f4b4 100644
--- a/dbaccess/source/ui/control/TableGrantCtrl.cxx
+++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx
@@ -275,7 +275,7 @@ void OTableGrantControl::InitController( CellControllerRef& /*rController*/, lon
{
    OUString sTablename = m_aTableNames[nRow];
    // special case for tablename
    if(nColumnId == COL_TABLE_NAME)
    if (nColumnId == COL_TABLE_NAME)
        m_pEdit->get_widget().set_text(sTablename);
    else
    {
diff --git a/include/svtools/editbrowsebox.hxx b/include/svtools/editbrowsebox.hxx
index 73f12c5..d2cbbaa 100644
--- a/include/svtools/editbrowsebox.hxx
+++ b/include/svtools/editbrowsebox.hxx
@@ -32,6 +32,7 @@
#include <tools/lineend.hxx>
#include <vcl/InterimItemWindow.hxx>
#include <vcl/vclmedit.hxx>
#include <vcl/weldutils.hxx>
#include <o3tl/typed_flags_set.hxx>

class Button;
@@ -143,6 +144,10 @@ namespace svt
        virtual bool                IsValueChangedFromSaved() const = 0;
        virtual void                SaveValue() = 0;
        virtual void                SetModifyHdl( const Link<LinkParamNone*,void>& _rLink ) = 0;

        virtual void                Cut() = 0;
        virtual void                Copy() = 0;
        virtual void                Paste() = 0;
    };


@@ -179,43 +184,68 @@ namespace svt
        virtual bool                IsValueChangedFromSaved() const override;
        virtual void                SaveValue() override;
        virtual void                SetModifyHdl( const Link<LinkParamNone*,void>& _rLink ) override;

        virtual void                Cut() override;
        virtual void                Copy() override;
        virtual void                Paste() override;
    };

    class SVT_DLLPUBLIC EditControl final : public InterimItemWindow
    class SVT_DLLPUBLIC EditControlBase : public InterimItemWindow
    {
    public:
        EditControlBase(vcl::Window* pParent);

        virtual void dispose() override;

        virtual void GetFocus() override
        {
            if (m_pEntry)
                m_pEntry->grab_focus();
            InterimItemWindow::GetFocus();
        }

        weld::Entry& get_widget() { return *m_pEntry; }

        virtual void connect_changed(const Link<weld::Entry&, void>& rLink) = 0;

    protected:
        void init(weld::Entry* pEntry);

    private:
        weld::Entry* m_pEntry;

        DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
    };

    class SVT_DLLPUBLIC EditControl final : public EditControlBase
    {
    public:
        EditControl(vcl::Window* pParent);

        virtual void dispose() override;

        virtual void GetFocus() override
        virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override
        {
            if (m_xWidget)
                m_xWidget->grab_focus();
            InterimItemWindow::GetFocus();
            m_xWidget->connect_changed(rLink);
        }

        weld::Entry& get_widget() { return *m_xWidget; }

    private:
        std::unique_ptr<weld::Entry> m_xWidget;

        DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
    };

    class SVT_DLLPUBLIC EntryImplementation : public IEditImplementation
    {
        EditControl& m_rEdit;
        EditControlBase& m_rEdit;
        int m_nMaxTextLen;
        Link<LinkParamNone*,void> m_aModifyHdl;

        DECL_LINK(ModifyHdl, weld::Entry&, void);
    public:
        EntryImplementation(EditControl& rEdit)
        EntryImplementation(EditControlBase& rEdit)
            : m_rEdit(rEdit)
            , m_nMaxTextLen(EDIT_NOLIMIT)
        {
            m_rEdit.get_widget().connect_changed(LINK(this, EntryImplementation, ModifyHdl));
            m_rEdit.connect_changed(LINK(this, EntryImplementation, ModifyHdl));
        }

        virtual Control& GetControl() override
@@ -264,7 +294,9 @@ namespace svt

        virtual void SetSelection( const Selection& rSelection ) override
        {
            m_rEdit.get_widget().select_region(rSelection.Min(), rSelection.Max());
            auto nMin = rSelection.Min();
            auto nMax = rSelection.Max();
            m_rEdit.get_widget().select_region(nMin < 0 ? 0 : nMin, nMax == SELECTION_MAX ? -1 : nMax);
        }

        virtual void ReplaceSelected( const OUString& rStr ) override
@@ -295,6 +327,21 @@ namespace svt
        {
            m_aModifyHdl = rLink;
        }

        virtual void Cut() override
        {
            m_rEdit.get_widget().cut_clipboard();
        }

        virtual void Copy() override
        {
            m_rEdit.get_widget().copy_clipboard();
        }

        virtual void Paste() override
        {
            m_rEdit.get_widget().paste_clipboard();
        }
    };

    #include <svtools/editimplementation.hxx>
@@ -358,7 +405,7 @@ namespace svt

    public:
        EditCellController( Edit* _pEdit );
        EditCellController( EditControl* _pEdit );
        EditCellController( EditControlBase* _pEdit );
        EditCellController( IEditImplementation* _pImplementation );
        virtual ~EditCellController( ) override;

@@ -368,6 +415,11 @@ namespace svt
        virtual bool IsValueChangedFromSaved() const override;
        virtual void SaveValue() override;

        void Modify()
        {
            ModifyHdl(nullptr);
        }

    protected:
        virtual bool MoveAllowed(const KeyEvent& rEvt) const override;
    private:
@@ -519,16 +571,33 @@ namespace svt
        DECL_LINK(ListBoxSelectHdl, weld::ComboBox&, void);
    };

    class SVT_DLLPUBLIC FormattedControl : public EditControlBase
    {
    public:
        FormattedControl(vcl::Window* pParent);

        virtual void dispose() override;

        virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override
        {
            m_xFormattedEntry->connect_changed(rLink);
        }

        weld::FormattedEntry& get_formatter() { return *m_xFormattedEntry; }

    private:
        std::unique_ptr<weld::FormattedEntry> m_xFormattedEntry;
    };

    //= FormattedFieldCellController
    class SVT_DLLPUBLIC FormattedFieldCellController final : public EditCellController
    {
    public:
        FormattedFieldCellController( FormattedField* _pFormatted );
        FormattedFieldCellController( FormattedControl* _pFormatted );

        virtual void CommitModifications() override;
    };


    //= EditBrowserHeader
    class SVT_DLLPUBLIC EditBrowserHeader : public BrowserHeader
    {
diff --git a/include/svtools/editimplementation.hxx b/include/svtools/editimplementation.hxx
index 9797009..04bc287 100644
--- a/include/svtools/editimplementation.hxx
+++ b/include/svtools/editimplementation.hxx
@@ -120,4 +120,22 @@ void GenericEditImplementation< EDIT >::SetModifyHdl( const Link<LinkParamNone*,
    m_aModifyHdl = _rLink;
}

template <class EDIT>
void GenericEditImplementation< EDIT >::Cut()
{
    m_rEdit.Cut();
}

template <class EDIT>
void GenericEditImplementation< EDIT >::Copy()
{
    m_rEdit.Copy();
}

template <class EDIT>
void GenericEditImplementation< EDIT >::Paste()
{
    m_rEdit.Paste();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/weldutils.hxx b/include/vcl/weldutils.hxx
index 90a8a20..a6a8738 100644
--- a/include/vcl/weldutils.hxx
+++ b/include/vcl/weldutils.hxx
@@ -16,6 +16,7 @@
#include <cppuhelper/compbase.hxx>
#include <tools/link.hxx>
#include <vcl/dllapi.h>
#include <vcl/formatter.hxx>
#include <vcl/weld.hxx>

namespace weld
@@ -153,6 +154,33 @@ public:
    }
};

class VCL_DLLPUBLIC FormattedEntry : public Formatter
{
public:
    FormattedEntry(std::unique_ptr<weld::Entry> xEntry);

    void connect_changed(const Link<weld::Entry&, void>& rLink) { m_aModifyHdl = rLink; }

    weld::Entry* get_widget() { return m_xEntry.get(); }

    // 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;

    void SetEntrySelectionOptions(SelectionOptions eOptions) { m_eOptions = eOptions; }

private:
    std::unique_ptr<weld::Entry> m_xEntry;
    Link<weld::Entry&, void> m_aModifyHdl;
    SelectionOptions m_eOptions;
    DECL_DLLPRIVATE_LINK(ModifyHdl, weld::Entry&, void);
    DECL_DLLPRIVATE_LINK(FocusOutHdl, weld::Widget&, void);
};

// get the row the iterator is on
VCL_DLLPUBLIC size_t GetAbsPos(const weld::TreeView& rTreeView, const weld::TreeIter& rIter);

diff --git a/svtools/inc/pch/precompiled_svt.hxx b/svtools/inc/pch/precompiled_svt.hxx
index 3122d26..9654a9c 100644
--- a/svtools/inc/pch/precompiled_svt.hxx
+++ b/svtools/inc/pch/precompiled_svt.hxx
@@ -13,7 +13,7 @@
 manual changes will be rewritten by the next run of update_pch.sh (which presumably
 also fixes all possible problems, so it's usually better to use it).

 Generated on 2020-06-26 20:20:06 using:
 Generated on 2020-07-02 16:19:19 using:
 ./bin/update_pch svtools svt --cutoff=4 --exclude:system --include:module --exclude:local

 If after updating build fails, use the following command to locate conflicting headers:
@@ -114,6 +114,7 @@
#include <vcl/floatwin.hxx>
#include <vcl/fntstyle.hxx>
#include <vcl/font.hxx>
#include <vcl/formatter.hxx>
#include <vcl/gfxlink.hxx>
#include <vcl/graph.hxx>
#include <vcl/graphicfilter.hxx>
@@ -295,6 +296,7 @@
#include <cppu/cppudllapi.h>
#include <cppu/unotype.hxx>
#include <cppuhelper/basemutex.hxx>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/compbase_ex.hxx>
#include <cppuhelper/cppuhelperdllapi.h>
#include <cppuhelper/implbase.hxx>
diff --git a/svtools/source/brwbox/ebbcontrols.cxx b/svtools/source/brwbox/ebbcontrols.cxx
index c2534dc..29d4c06c 100644
--- a/svtools/source/brwbox/ebbcontrols.cxx
+++ b/svtools/source/brwbox/ebbcontrols.cxx
@@ -346,26 +346,56 @@ namespace svt
        m_aModifyHdl.Call(nullptr);
    }

    EditControl::EditControl(vcl::Window* pParent)
    EditControlBase::EditControlBase(vcl::Window* pParent)
        : InterimItemWindow(pParent, "svt/ui/thineditcontrol.ui", "EditControl") // *thin*editcontrol has no frame/border
        , m_xWidget(m_xBuilder->weld_entry("entry"))
    {
        m_xWidget->set_width_chars(1); // so a smaller than default width can be used
        m_xWidget->connect_key_press(LINK(this, EditControl, KeyInputHdl));
    }

    IMPL_LINK(EditControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
    void EditControlBase::init(weld::Entry* pEntry)
    {
        m_pEntry = pEntry;
        m_pEntry->set_width_chars(1); // so a smaller than default width can be used
        m_pEntry->connect_key_press(LINK(this, EditControl, KeyInputHdl));
    }

    IMPL_LINK(EditControlBase, KeyInputHdl, const KeyEvent&, rKEvt, bool)
    {
        return ChildKeyInput(rKEvt);
    }

    void EditControlBase::dispose()
    {
        m_pEntry = nullptr;
        InterimItemWindow::dispose();
    }

    EditControl::EditControl(vcl::Window* pParent)
        : EditControlBase(pParent)
        , m_xWidget(m_xBuilder->weld_entry("entry"))
    {
        init(m_xWidget.get());
    }

    void EditControl::dispose()
    {
        m_xWidget.reset();
        InterimItemWindow::dispose();
        EditControlBase::dispose();
    }

    EditCellController::EditCellController(EditControl* pEdit)
    FormattedControl::FormattedControl(vcl::Window* pParent)
        : EditControlBase(pParent)
        , m_xFormattedEntry(new weld::FormattedEntry(m_xBuilder->weld_entry("entry")))
    {
        init(m_xFormattedEntry->get_widget());
    }

    void FormattedControl::dispose()
    {
        m_xFormattedEntry.reset();
        EditControlBase::dispose();
    }

    EditCellController::EditCellController(EditControlBase* pEdit)
        : CellController(pEdit)
        , m_pEditImplementation(new EntryImplementation(*pEdit))
        , m_bOwnImplementation(true)
@@ -475,30 +505,23 @@ namespace svt
    }

    //= FormattedFieldCellController


    FormattedFieldCellController::FormattedFieldCellController( FormattedField* _pFormatted )
        :EditCellController( _pFormatted )
    FormattedFieldCellController::FormattedFieldCellController( FormattedControl* _pFormatted )
        : EditCellController(_pFormatted)
    {
    }


    void FormattedFieldCellController::CommitModifications()
    {
        static_cast< FormattedField& >( GetWindow() ).Commit();
        static_cast<FormattedControl&>(GetWindow()).get_formatter().Commit();
    }


    //= MultiLineTextCell


    void MultiLineTextCell::Modify()
    {
        GetTextEngine()->SetModified( true );
        VclMultiLineEdit::Modify();
    }


    bool MultiLineTextCell::dispatchKeyEvent( const KeyEvent& _rEvent )
    {
        Selection aOldSelection( GetSelection() );
diff --git a/svtools/source/brwbox/editbrowsebox.cxx b/svtools/source/brwbox/editbrowsebox.cxx
index 1db43ea..1f79a36 100644
--- a/svtools/source/brwbox/editbrowsebox.cxx
+++ b/svtools/source/brwbox/editbrowsebox.cxx
@@ -24,7 +24,6 @@
#include <vcl/window.hxx>

#include <vcl/button.hxx>
#include <vcl/edit.hxx>
#include <vcl/settings.hxx>

#include <bitmaps.hlst>
diff --git a/svx/inc/pch/precompiled_svxcore.hxx b/svx/inc/pch/precompiled_svxcore.hxx
index f3a192f..9e628b6 100644
--- a/svx/inc/pch/precompiled_svxcore.hxx
+++ b/svx/inc/pch/precompiled_svxcore.hxx
@@ -13,7 +13,7 @@
 manual changes will be rewritten by the next run of update_pch.sh (which presumably
 also fixes all possible problems, so it's usually better to use it).

 Generated on 2020-06-26 20:21:18 using:
 Generated on 2020-07-02 16:18:48 using:
 ./bin/update_pch svx svxcore --cutoff=7 --exclude:system --include:module --exclude:local

 If after updating build fails, use the following command to locate conflicting headers:
@@ -119,6 +119,7 @@
#include <vcl/floatwin.hxx>
#include <vcl/fntstyle.hxx>
#include <vcl/font.hxx>
#include <vcl/formatter.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/gfxlink.hxx>
#include <vcl/graph.hxx>
diff --git a/svx/source/fmcomp/gridcell.cxx b/svx/source/fmcomp/gridcell.cxx
index b502d39..dfcec5e 100644
--- a/svx/source/fmcomp/gridcell.cxx
+++ b/svx/source/fmcomp/gridcell.cxx
@@ -1041,11 +1041,11 @@ void DbLimitedLengthField::implAdjustGenericFieldSetting( const Reference< XProp
    }
}

void DbLimitedLengthField::implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen )
void DbLimitedLengthField::implSetEffectiveMaxTextLen(sal_Int32 nMaxLen)
{
    dynamic_cast<Edit&>(*m_pWindow).SetMaxTextLen(_nMaxLen);
    dynamic_cast<EditControlBase&>(*m_pWindow).get_widget().set_max_length(nMaxLen);
    if (m_pPainter)
        dynamic_cast<Edit&>(*m_pPainter).SetMaxTextLen(_nMaxLen);
        dynamic_cast<EditControlBase&>(*m_pPainter).get_widget().set_max_length(nMaxLen);
}

DbTextField::DbTextField(DbGridColumn& _rColumn)
@@ -1239,46 +1239,48 @@ DbFormattedField::DbFormattedField(DbGridColumn& _rColumn)
    doPropertyListening( FM_PROP_FORMATKEY );
}


DbFormattedField::~DbFormattedField()
{
}


void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& xCursor)
{
    sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1);

    Reference< css::beans::XPropertySet >  xUnoModel = m_rColumn.getModel();

    auto xEditControl = VclPtr<FormattedControl>::Create(&rParent);
    auto xEditPainter = VclPtr<FormattedControl>::Create(&rParent);

    weld::FormattedEntry& rControlFormatter = xEditControl->get_formatter();
    weld::FormattedEntry& rPainterFormatter = xEditPainter->get_formatter();

    m_pWindow = xEditControl.get();
    m_pPainter = xEditPainter.get();

    switch (nAlignment)
    {
        case css::awt::TextAlign::RIGHT:
            m_pWindow  = VclPtr<FormattedField>::Create( &rParent, WB_RIGHT );
            m_pPainter = VclPtr<FormattedField>::Create( &rParent, WB_RIGHT );
        case awt::TextAlign::RIGHT:
            xEditControl->get_widget().set_alignment(TxtAlign::Right);
            xEditPainter->get_widget().set_alignment(TxtAlign::Right);
            break;

        case css::awt::TextAlign::CENTER:
            m_pWindow  = VclPtr<FormattedField>::Create( &rParent, WB_CENTER );
            m_pPainter  = VclPtr<FormattedField>::Create( &rParent, WB_CENTER );
        case awt::TextAlign::CENTER:
            xEditControl->get_widget().set_alignment(TxtAlign::Center);
            xEditPainter->get_widget().set_alignment(TxtAlign::Center);
            break;
        default:
            m_pWindow  = VclPtr<FormattedField>::Create( &rParent, WB_LEFT );
            m_pPainter  = VclPtr<FormattedField>::Create( &rParent, WB_LEFT );

        {
            // Everything just so that the selection goes from right to left when getting focus
            AllSettings aSettings = m_pWindow->GetSettings();
            StyleSettings aStyleSettings = aSettings.GetStyleSettings();
            aStyleSettings.SetSelectionOptions(
                aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
            aSettings.SetStyleSettings(aStyleSettings);
            m_pWindow->SetSettings(aSettings);
            SelectionOptions eOptions = rControlFormatter.GetEntrySelectionOptions();
            rControlFormatter.SetEntrySelectionOptions(eOptions | SelectionOptions::ShowFirst);
            break;
        }
    }

    implAdjustGenericFieldSetting( xUnoModel );

    static_cast< FormattedField* >( m_pWindow.get() )->SetStrictFormat( false );
    static_cast< FormattedField* >( m_pPainter.get() )->SetStrictFormat( false );
    rControlFormatter.SetStrictFormat(false);
    rPainterFormatter.SetStrictFormat(false);
        // if one allows any formatting, one cannot make an entry check anyway
        // (the FormattedField does not support that anyway, only derived classes)

@@ -1344,21 +1346,21 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
    // a standard formatter ...
    if (pFormatterUsed == nullptr)
    {
        pFormatterUsed = static_cast<FormattedField*>(m_pWindow.get())->StandardFormatter();
        pFormatterUsed = rControlFormatter.StandardFormatter();
        DBG_ASSERT(pFormatterUsed != nullptr, "DbFormattedField::Init : no standard formatter given by the numeric field !");
    }
    // ... and a standard key
    if (nFormatKey == -1)
        nFormatKey = 0;

    static_cast<FormattedField*>(m_pWindow.get())->SetFormatter(pFormatterUsed);
    static_cast<FormattedField*>(m_pPainter.get())->SetFormatter(pFormatterUsed);
    rControlFormatter.SetFormatter(pFormatterUsed);
    rPainterFormatter.SetFormatter(pFormatterUsed);

    static_cast<FormattedField*>(m_pWindow.get())->SetFormatKey(nFormatKey);
    static_cast<FormattedField*>(m_pPainter.get())->SetFormatKey(nFormatKey);
    rControlFormatter.SetFormatKey(nFormatKey);
    rPainterFormatter.SetFormatKey(nFormatKey);

    static_cast<FormattedField*>(m_pWindow.get())->TreatAsNumber(m_rColumn.IsNumeric());
    static_cast<FormattedField*>(m_pPainter.get())->TreatAsNumber(m_rColumn.IsNumeric());
    rControlFormatter.TreatAsNumber(m_rColumn.IsNumeric());
    rPainterFormatter.TreatAsNumber(m_rColumn.IsNumeric());

    // min and max values
    if (m_rColumn.IsNumeric())
@@ -1371,15 +1373,15 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
            {
                DBG_ASSERT(aMin.getValueType().getTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid min value !");
                double dMin = ::comphelper::getDouble(aMin);
                static_cast<FormattedField*>(m_pWindow.get())->SetMinValue(dMin);
                static_cast<FormattedField*>(m_pPainter.get())->SetMinValue(dMin);
                rControlFormatter.SetMinValue(dMin);
                rPainterFormatter.SetMinValue(dMin);
                bClearMin = false;
            }
        }
        if (bClearMin)
        {
            static_cast<FormattedField*>(m_pWindow.get())->ClearMinValue();
            static_cast<FormattedField*>(m_pPainter.get())->ClearMinValue();
            rControlFormatter.ClearMinValue();
            rPainterFormatter.ClearMinValue();
        }
        bool bClearMax = true;
        if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MAX, xUnoModel))
@@ -1389,15 +1391,15 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
            {
                DBG_ASSERT(aMax.getValueType().getTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid max value !");
                double dMax = ::comphelper::getDouble(aMax);
                static_cast<FormattedField*>(m_pWindow.get())->SetMaxValue(dMax);
                static_cast<FormattedField*>(m_pPainter.get())->SetMaxValue(dMax);
                rControlFormatter.SetMaxValue(dMax);
                rPainterFormatter.SetMaxValue(dMax);
                bClearMax = false;
            }
        }
        if (bClearMax)
        {
            static_cast<FormattedField*>(m_pWindow.get())->ClearMaxValue();
            static_cast<FormattedField*>(m_pPainter.get())->ClearMaxValue();
            rControlFormatter.ClearMaxValue();
            rPainterFormatter.ClearMaxValue();
        }
    }

@@ -1410,16 +1412,16 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
            case TypeClass_DOUBLE:
                if (m_rColumn.IsNumeric())
                {
                    static_cast<FormattedField*>(m_pWindow.get())->SetDefaultValue(::comphelper::getDouble(aDefault));
                    static_cast<FormattedField*>(m_pPainter.get())->SetDefaultValue(::comphelper::getDouble(aDefault));
                    rControlFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
                    rPainterFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
                }
                else
                {
                    OUString sConverted;
                    Color* pDummy;
                    pFormatterUsed->GetOutputString(::comphelper::getDouble(aDefault), 0, sConverted, &pDummy);
                    static_cast<FormattedField*>(m_pWindow.get())->SetDefaultText(sConverted);
                    static_cast<FormattedField*>(m_pPainter.get())->SetDefaultText(sConverted);
                    rControlFormatter.SetDefaultText(sConverted);
                    rPainterFormatter.SetDefaultText(sConverted);
                }
                break;
            case TypeClass_STRING:
@@ -1431,14 +1433,14 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
                    sal_uInt32 nTestFormat(0);
                    if (pFormatterUsed->IsNumberFormat(sDefault, nTestFormat, dVal))
                    {
                        static_cast<FormattedField*>(m_pWindow.get())->SetDefaultValue(dVal);
                        static_cast<FormattedField*>(m_pPainter.get())->SetDefaultValue(dVal);
                        rControlFormatter.SetDefaultValue(dVal);
                        rPainterFormatter.SetDefaultValue(dVal);
                    }
                }
                else
                {
                    static_cast<FormattedField*>(m_pWindow.get())->SetDefaultText(sDefault);
                    static_cast<FormattedField*>(m_pPainter.get())->SetDefaultText(sDefault);
                    rControlFormatter.SetDefaultText(sDefault);
                    rPainterFormatter.SetDefaultText(sDefault);
                }
            }
            break;
@@ -1450,13 +1452,11 @@ void DbFormattedField::Init( vcl::Window& rParent, const Reference< XRowSet >& x
    DbLimitedLengthField::Init( rParent, xCursor );
}


CellControllerRef DbFormattedField::CreateController() const
{
    return new ::svt::FormattedFieldCellController( static_cast< FormattedField* >( m_pWindow.get() ) );
    return new ::svt::FormattedFieldCellController(static_cast<FormattedControl*>(m_pWindow.get()));
}


void DbFormattedField::_propertyChanged( const PropertyChangeEvent& _rEvent )
{
    if (_rEvent.PropertyName == FM_PROP_FORMATKEY )
@@ -1465,9 +1465,9 @@ void DbFormattedField::_propertyChanged( const PropertyChangeEvent& _rEvent )

        DBG_ASSERT(m_pWindow && m_pPainter, "DbFormattedField::_propertyChanged : where are my windows ?");
        if (m_pWindow)
            static_cast< FormattedField* >( m_pWindow.get() )->SetFormatKey( nNewKey );
            static_cast<FormattedControl*>(m_pWindow.get())->get_formatter().SetFormatKey(nNewKey);
        if (m_pPainter)
            static_cast< FormattedField* >( m_pPainter.get() )->SetFormatKey( nNewKey );
            static_cast<FormattedControl*>(m_pPainter.get())->get_formatter().SetFormatKey(nNewKey);
    }
    else
    {
@@ -1475,7 +1475,6 @@ void DbFormattedField::_propertyChanged( const PropertyChangeEvent& _rEvent )
    }
}


OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, Color** ppColor)
{
    // no color specification by default
@@ -1486,6 +1485,9 @@ OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _
    if (!_rxField.is())
        return OUString();

    FormattedControl* pControl = static_cast<FormattedControl*>(m_pPainter.get());
    weld::FormattedEntry& rPainterFormatter = pControl->get_formatter();

    OUString aText;
    try
    {
@@ -1499,7 +1501,7 @@ OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _
            double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
            if (_rxField->wasNull())
                return aText;
            static_cast<FormattedField*>(m_pPainter.get())->SetValue(dValue);
            rPainterFormatter.SetValue(dValue);
        }
        else
        {
@@ -1508,7 +1510,7 @@ OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _
            aText = _rxField->getString();
            if (_rxField->wasNull())
                return aText;
            static_cast<FormattedField*>(m_pPainter.get())->SetTextFormatted(aText);
            rPainterFormatter.SetTextFormatted(aText);
        }
    }
    catch( const Exception& )
@@ -1516,22 +1518,25 @@ OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _
        DBG_UNHANDLED_EXCEPTION("svx");
    }

    aText = m_pPainter->GetText();
    aText = pControl->get_widget().get_text();
    if (ppColor != nullptr)
        *ppColor = static_cast<FormattedField*>(m_pPainter.get())->GetLastOutputColor();
        *ppColor = rPainterFormatter.GetLastOutputColor();

    return aText;
}


void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    try
    {
        FormattedField* pFormattedWindow = static_cast<FormattedField*>(m_pWindow.get());
        FormattedControl* pEditControl = static_cast<FormattedControl*>(m_pWindow.get());
        weld::Entry& rEntry = pEditControl->get_widget();
        weld::FormattedEntry& rEditFormatter = pEditControl->get_formatter();

        if (!_rxField.is())
        {   // NULL value -> empty text
            m_pWindow->SetText(OUString());
        {
            // NULL value -> empty text
            rEntry.set_text(OUString());
        }
        else if (m_rColumn.IsNumeric())
        {
@@ -1542,9 +1547,9 @@ void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rx
            // getDouble, and then I can leave the rest (the formatting) to the FormattedField.
            double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
            if (_rxField->wasNull())
                m_pWindow->SetText(OUString());
                rEntry.set_text(OUString());
            else
                pFormattedWindow->SetValue(dValue);
                rEditFormatter.SetValue(dValue);
        }
        else
        {
@@ -1552,8 +1557,8 @@ void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rx
            // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
            OUString sText( _rxField->getString());

            pFormattedWindow->SetTextFormatted( sText );
            pFormattedWindow->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
            rEditFormatter.SetTextFormatted( sText );
            rEntry.select_region(0, -1);
        }
    }
    catch( const Exception& )
@@ -1562,42 +1567,46 @@ void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rx
    }
}


void DbFormattedField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFormattedField::updateFromModel: invalid call!" );

    FormattedField* pFormattedWindow = static_cast< FormattedField* >( m_pWindow.get() );
    FormattedControl* pEditControl = static_cast<FormattedControl*>(m_pWindow.get());
    weld::Entry& rEntry = pEditControl->get_widget();
    weld::FormattedEntry& rEditFormatter = pEditControl->get_formatter();

    OUString sText;
    Any aValue = _rxModel->getPropertyValue( FM_PROP_EFFECTIVE_VALUE );
    if ( !aValue.hasValue() || (aValue >>= sText) )
    {   // our effective value is transferred as string
        pFormattedWindow->SetTextFormatted( sText );
        pFormattedWindow->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
    {
        // our effective value is transferred as string
        rEditFormatter.SetTextFormatted( sText );
        rEntry.select_region(0, -1);
    }
    else
    {
        double dValue = 0;
        aValue >>= dValue;
        pFormattedWindow->SetValue(dValue);
        rEditFormatter.SetValue(dValue);
    }
}


bool DbFormattedField::commitControl()
{
    Any aNewVal;
    FormattedField& rField = *static_cast<FormattedField*>(m_pWindow.get());
    DBG_ASSERT(&rField == m_pWindow, "DbFormattedField::commitControl : can't work with a window other than my own !");

    FormattedControl* pEditControl = static_cast<FormattedControl*>(m_pWindow.get());
    weld::Entry& rEntry = pEditControl->get_widget();
    weld::FormattedEntry& rEditFormatter = pEditControl->get_formatter();

    if (m_rColumn.IsNumeric())
    {
        if (!rField.GetText().isEmpty())
            aNewVal <<= rField.GetValue();
        if (!rEntry.get_text().isEmpty())
            aNewVal <<= rEditFormatter.GetValue();
        // an empty string is passed on as void by default, to start with
    }
    else
        aNewVal <<= rField.GetTextValue();
        aNewVal <<= rEditFormatter.GetTextValue();

    m_rColumn.getModel()->setPropertyValue(FM_PROP_EFFECTIVE_VALUE, aNewVal);
    return true;
@@ -3555,12 +3564,11 @@ FmXEditCell::FmXEditCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> 
    }
    else
    {
        m_pEditImplementation = new EditImplementation( static_cast< Edit& >( m_pCellControl->GetWindow() ) );
        m_pEditImplementation = new EntryImplementation(static_cast<EditControlBase&>(m_pCellControl->GetWindow()));
        m_bOwnEditImplementation = true;
    }
}


FmXEditCell::~FmXEditCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
diff --git a/vcl/source/app/weldutils.cxx b/vcl/source/app/weldutils.cxx
index 20372a7..9cb6dfd 100644
--- a/vcl/source/app/weldutils.cxx
+++ b/vcl/source/app/weldutils.cxx
@@ -124,6 +124,44 @@ void RemoveParentKeepChildren(weld::TreeView& rTreeView, weld::TreeIter& rParent
    }
    rTreeView.remove(rParent);
}

FormattedEntry::FormattedEntry(std::unique_ptr<weld::Entry> xEntry)
    : m_xEntry(std::move(xEntry))
    , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
{
    m_xEntry->connect_changed(LINK(this, FormattedEntry, ModifyHdl));
    m_xEntry->connect_focus_out(LINK(this, FormattedEntry, FocusOutHdl));
}

Selection FormattedEntry::GetEntrySelection() const
{
    int nStartPos, nEndPos;
    m_xEntry->get_selection_bounds(nStartPos, nEndPos);
    return Selection(nStartPos, nEndPos);
}

OUString FormattedEntry::GetEntryText() const { return m_xEntry->get_text(); }

void FormattedEntry::SetEntryText(const OUString& rText, const Selection& rSel)
{
    m_xEntry->set_text(rText);
    auto nMin = rSel.Min();
    auto nMax = rSel.Max();
    m_xEntry->select_region(nMin < 0 ? 0 : nMin, nMax == SELECTION_MAX ? -1 : nMax);
}

void FormattedEntry::SetEntryTextColor(const Color* pColor)
{
    m_xEntry->set_font_color(pColor ? *pColor : COL_AUTO);
}

SelectionOptions FormattedEntry::GetEntrySelectionOptions() const { return m_eOptions; }

void FormattedEntry::FieldModified() { m_aModifyHdl.Call(*m_xEntry); }

IMPL_LINK_NOARG(FormattedEntry, ModifyHdl, weld::Entry&, void) { impl_Modify(); }

IMPL_LINK_NOARG(FormattedEntry, FocusOutHdl, weld::Widget&, void) { EntryLostFocus(); }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */