weld DateControl

replace SpinButton when WB_SPINBUTTON is set on a date field
to always use a popover with a calendar in it to make it
possible to integrate this with native widgets

Change-Id: I36a26599a154bddf9aec9b50b6570e13477a1f63
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/98858
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/include/svtools/editbrowsebox.hxx b/include/svtools/editbrowsebox.hxx
index b5ffad4..4dc3381 100644
--- a/include/svtools/editbrowsebox.hxx
+++ b/include/svtools/editbrowsebox.hxx
@@ -750,6 +750,27 @@ namespace svt
        TimeControl(BrowserDataWin* pParent, bool bSpinVariant);
    };

    class SVT_DLLPUBLIC DateControl : public FormattedControlBase
    {
    public:
        DateControl(BrowserDataWin* pParent, bool bDropDown);

        void SetDate(const Date& rDate);

        virtual void dispose() override;
    private:
        std::unique_ptr<weld::MenuButton> m_xMenuButton;
        std::unique_ptr<weld::Builder> m_xCalendarBuilder;
        std::unique_ptr<weld::Widget> m_xTopLevel;
        std::unique_ptr<weld::Calendar> m_xCalendar;
        std::unique_ptr<weld::Button> m_xTodayBtn;
        std::unique_ptr<weld::Button> m_xNoneBtn;

        DECL_LINK(ToggleHdl, weld::ToggleButton&, void);
        DECL_LINK(ActivateHdl, weld::Calendar&, void);
        DECL_LINK(ImplClickHdl, weld::Button&, void);
    };

    //= FormattedFieldCellController
    class SVT_DLLPUBLIC FormattedFieldCellController final : public EditCellController
    {
diff --git a/include/vcl/field.hxx b/include/vcl/field.hxx
index 1cb4974..36a78606 100644
--- a/include/vcl/field.hxx
+++ b/include/vcl/field.hxx
@@ -186,83 +186,6 @@ private:

};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) DateFormatter : public FormatterBase
{
private:
    std::unique_ptr<CalendarWrapper> mxCalendarWrapper;
    Date                    maFieldDate;
    Date                    maLastDate;
    Date                    maMin;
    Date                    maMax;
    bool                    mbLongFormat;
    bool                    mbShowDateCentury;
    ExtDateFieldFormat      mnExtDateFormat;
    bool                    mbEnforceValidValue;

protected:
                            DateFormatter(Edit* pEdit);

    SAL_DLLPRIVATE const Date& ImplGetFieldDate() const    { return maFieldDate; }
    SAL_DLLPRIVATE void     ImplDateReformat( const OUString& rStr, OUString& rOutStr );
    SAL_DLLPRIVATE void     ImplSetUserDate( const Date& rNewDate,
                                             Selection const * pNewSelection = nullptr );
    SAL_DLLPRIVATE OUString ImplGetDateAsText( const Date& rDate ) const;
    SAL_DLLPRIVATE void     ImplNewFieldValue( const Date& rDate );
    CalendarWrapper&        GetCalendarWrapper() const;

    SAL_DLLPRIVATE bool     ImplAllowMalformedInput() const;

public:
    virtual                 ~DateFormatter() override;

    virtual void            Reformat() override;
    virtual void            ReformatAll() override;

    void                    SetExtDateFormat( ExtDateFieldFormat eFormat );
    ExtDateFieldFormat      GetExtDateFormat( bool bResolveSystemFormat = false ) const;

    void                    SetMin( const Date& rNewMin );
    const Date&             GetMin() const { return maMin; }

    void                    SetMax( const Date& rNewMax );
    const Date&             GetMax() const { return maMax; }


    // MT: Remove these methods too, ExtDateFormat should be enough!
    //     What should happen if using DDMMYYYY, but ShowCentury=false?

    void                    SetLongFormat( bool bLong );
    bool                    IsLongFormat() const { return mbLongFormat; }
    void                    SetShowDateCentury( bool bShowCentury );
    bool                    IsShowDateCentury() const { return mbShowDateCentury; }


    void                    SetDate( const Date& rNewDate );
    Date                    GetDate() const;
    void                    SetEmptyDate();
    bool                    IsEmptyDate() const;

    void                    ResetLastDate() { maLastDate = Date( Date::EMPTY ); }

    static void             ExpandCentury( Date& rDate );
    static void             ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart );

    /** enables or disables the enforcement of valid values

        If this is set to true (which is the default), then GetDate will always return a valid
        date, no matter whether the current text can really be interpreted as date. (Note: this
        is the compatible behavior).

        If this is set to false, the GetDate will return GetInvalidDate, in case the current text
        cannot be interpreted as date.

        In addition, if this is set to false, the text in the field will \em not be corrected
        when the control loses the focus - instead, the invalid input will be preserved.
    */
    void                    EnforceValidValue( bool _bEnforce ) { mbEnforceValidValue = _bEnforce; }
    bool             IsEnforceValidValue( ) const { return mbEnforceValidValue; }
};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) PatternField final : public SpinField, public PatternFormatter
{
public:
@@ -298,36 +221,6 @@ public:
    virtual void DumpAsPropertyTree(tools::JsonWriter&) override;
};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) DateField : public SpinField, public DateFormatter
{
private:
    Date                    maFirst;
    Date                    maLast;

protected:
    SAL_DLLPRIVATE void     ImplDateSpinArea( bool bUp );

public:
    explicit                DateField( vcl::Window* pParent, WinBits nWinStyle );

    virtual bool            PreNotify( NotifyEvent& rNEvt ) override;
    virtual bool            EventNotify( NotifyEvent& rNEvt ) override;
    virtual void            DataChanged( const DataChangedEvent& rDCEvt ) override;

    virtual void            Modify() override;

    virtual void            Up() override;
    virtual void            Down() override;
    virtual void            First() override;
    virtual void            Last() override;

    void                    SetFirst( const Date& rNewFirst )   { maFirst = rNewFirst; }
    const Date&             GetFirst() const                    { return maFirst; }
    void                    SetLast( const Date& rNewLast )     { maLast = rNewLast; }
    const Date&             GetLast() const                     { return maLast; }
    virtual void            dispose() override;
};

#endif // INCLUDED_VCL_FIELD_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/calendar.hxx b/include/vcl/toolkit/calendar.hxx
similarity index 94%
rename from include/vcl/calendar.hxx
rename to include/vcl/toolkit/calendar.hxx
index a88105e..a1a1cd9 100644
--- a/include/vcl/calendar.hxx
+++ b/include/vcl/toolkit/calendar.hxx
@@ -19,10 +19,14 @@

#pragma once

#if !defined(VCL_DLLIMPLEMENTATION) && !defined(TOOLKIT_DLLIMPLEMENTATION) && !defined(VCL_INTERNALS)
#error "don't use this in new code"
#endif

#include <config_options.h>
#include <vcl/dllapi.h>

#include <vcl/field.hxx>
#include <vcl/toolkit/field.hxx>
#include <vcl/weld.hxx>

class FloatingWindow;
diff --git a/include/vcl/toolkit/field.hxx b/include/vcl/toolkit/field.hxx
index 6b994b0..6316c56 100644
--- a/include/vcl/toolkit/field.hxx
+++ b/include/vcl/toolkit/field.hxx
@@ -260,6 +260,117 @@ public:
    virtual void            dispose() override;
};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) DateFormatter : public FormatterBase
{
private:
    std::unique_ptr<CalendarWrapper> mxCalendarWrapper;
    Date                    maFieldDate;
    Date                    maLastDate;
    Date                    maMin;
    Date                    maMax;
    bool                    mbLongFormat;
    bool                    mbShowDateCentury;
    ExtDateFieldFormat      mnExtDateFormat;
    bool                    mbEnforceValidValue;

protected:
                            DateFormatter(Edit* pEdit);

    SAL_DLLPRIVATE const Date& ImplGetFieldDate() const    { return maFieldDate; }
    SAL_DLLPRIVATE void     ImplDateReformat( const OUString& rStr, OUString& rOutStr );
    SAL_DLLPRIVATE void     ImplSetUserDate( const Date& rNewDate,
                                             Selection const * pNewSelection = nullptr );
    SAL_DLLPRIVATE OUString ImplGetDateAsText( const Date& rDate ) const;
    SAL_DLLPRIVATE void     ImplNewFieldValue( const Date& rDate );
    CalendarWrapper&        GetCalendarWrapper() const;

    SAL_DLLPRIVATE bool     ImplAllowMalformedInput() const;

public:
    static OUString         FormatDate(const Date& rNewDate, ExtDateFieldFormat eFormat, const LocaleDataWrapper& rLocaleData, CalendarWrapper& rCalendarWrapper);
    static bool             TextToDate(const OUString& rStr, Date& rTime, ExtDateFieldFormat eFormat, const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper);
    static int              GetDateArea(ExtDateFieldFormat eFormat, const OUString& rText, int nCursor, const LocaleDataWrapper& rLocaleDataWrapper);

    virtual                 ~DateFormatter() override;

    virtual void            Reformat() override;
    virtual void            ReformatAll() override;

    void                    SetExtDateFormat( ExtDateFieldFormat eFormat );
    ExtDateFieldFormat      GetExtDateFormat( bool bResolveSystemFormat = false ) const;

    void                    SetMin( const Date& rNewMin );
    const Date&             GetMin() const { return maMin; }

    void                    SetMax( const Date& rNewMax );
    const Date&             GetMax() const { return maMax; }


    // MT: Remove these methods too, ExtDateFormat should be enough!
    //     What should happen if using DDMMYYYY, but ShowCentury=false?

    void                    SetLongFormat( bool bLong );
    bool                    IsLongFormat() const { return mbLongFormat; }
    void                    SetShowDateCentury( bool bShowCentury );
    bool                    IsShowDateCentury() const { return mbShowDateCentury; }


    void                    SetDate( const Date& rNewDate );
    Date                    GetDate() const;
    void                    SetEmptyDate();
    bool                    IsEmptyDate() const;

    void                    ResetLastDate() { maLastDate = Date( Date::EMPTY ); }

    static void             ExpandCentury( Date& rDate );
    static void             ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart );

    /** enables or disables the enforcement of valid values

        If this is set to true (which is the default), then GetDate will always return a valid
        date, no matter whether the current text can really be interpreted as date. (Note: this
        is the compatible behavior).

        If this is set to false, the GetDate will return GetInvalidDate, in case the current text
        cannot be interpreted as date.

        In addition, if this is set to false, the text in the field will \em not be corrected
        when the control loses the focus - instead, the invalid input will be preserved.
    */
    void                    EnforceValidValue( bool _bEnforce ) { mbEnforceValidValue = _bEnforce; }
    bool             IsEnforceValidValue( ) const { return mbEnforceValidValue; }
};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) DateField : public SpinField, public DateFormatter
{
private:
    Date                    maFirst;
    Date                    maLast;

protected:
    SAL_DLLPRIVATE void     ImplDateSpinArea( bool bUp );

public:
    explicit                DateField( vcl::Window* pParent, WinBits nWinStyle );

    virtual bool            PreNotify( NotifyEvent& rNEvt ) override;
    virtual bool            EventNotify( NotifyEvent& rNEvt ) override;
    virtual void            DataChanged( const DataChangedEvent& rDCEvt ) override;

    virtual void            Modify() override;

    virtual void            Up() override;
    virtual void            Down() override;
    virtual void            First() override;
    virtual void            Last() override;

    void                    SetFirst( const Date& rNewFirst )   { maFirst = rNewFirst; }
    const Date&             GetFirst() const                    { return maFirst; }
    void                    SetLast( const Date& rNewLast )     { maLast = rNewLast; }
    const Date&             GetLast() const                     { return maLast; }
    virtual void            dispose() override;
};

class UNLESS_MERGELIBS(VCL_DLLPUBLIC) NumericBox : public ComboBox, public NumericFormatter
{
    SAL_DLLPRIVATE void     ImplNumericReformat( const OUString& rStr, sal_Int64& rValue, OUString& rOutStr );
diff --git a/include/vcl/weldutils.hxx b/include/vcl/weldutils.hxx
index e1944cc..cc2a49d 100644
--- a/include/vcl/weldutils.hxx
+++ b/include/vcl/weldutils.hxx
@@ -19,6 +19,8 @@
#include <vcl/formatter.hxx>
#include <vcl/weld.hxx>

class CalendarWrapper;

namespace weld
{
typedef cppu::WeakComponentImplHelper<css::awt::XWindow> TransportAsXWindow_Base;
@@ -280,6 +282,36 @@ private:
    bool m_bDuration;
};

class VCL_DLLPUBLIC DateFormatter final : public EntryFormatter
{
public:
    DateFormatter(weld::Entry& rEntry);

    void SetMin(const Date& rNewMin);
    void SetMax(const Date& rNewMax);

    void SetDate(const Date& rNewDate);
    Date GetDate();

    void SetExtDateFormat(ExtDateFieldFormat eFormat);
    void SetShowDateCentury(bool bShowCentury);

    virtual ~DateFormatter() override;

private:
    DECL_LINK(FormatOutputHdl, LinkParamNone*, bool);
    DECL_LINK(ParseInputHdl, sal_Int64*, TriState);
    DECL_LINK(CursorChangedHdl, weld::Entry&, void);

    void Init();
    CalendarWrapper& GetCalendarWrapper() const;

    OUString FormatNumber(int nValue) const;

    ExtDateFieldFormat m_eFormat;
    mutable std::unique_ptr<CalendarWrapper> m_xCalendarWrapper;
};

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

diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index ac6e1e2..0708c30 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -7321,7 +7321,6 @@ include/vcl/builder.hxx
include/vcl/builderfactory.hxx
include/vcl/button.hxx
include/vcl/cairo.hxx
include/vcl/calendar.hxx
include/vcl/canvastools.hxx
include/vcl/checksum.hxx
include/vcl/commandevent.hxx
@@ -7439,6 +7438,7 @@ include/vcl/threadex.hxx
include/vcl/timer.hxx
include/vcl/toolbox.hxx
include/vcl/toolkit/button.hxx
include/vcl/toolkit/calendar.hxx
include/vcl/toolkit/combobox.hxx
include/vcl/toolkit/controllayout.hxx
include/vcl/toolkit/dialog.hxx
diff --git a/svtools/source/brwbox/ebbcontrols.cxx b/svtools/source/brwbox/ebbcontrols.cxx
index ba90f7f..3f1c019 100644
--- a/svtools/source/brwbox/ebbcontrols.cxx
+++ b/svtools/source/brwbox/ebbcontrols.cxx
@@ -18,6 +18,7 @@

#include <svtools/editbrowsebox.hxx>
#include <vcl/spinfld.hxx>
#include <vcl/svapp.hxx>
#include <vcl/xtextedt.hxx>
#include <vcl/textview.hxx>
#include <vcl/virdev.hxx>
@@ -467,6 +468,74 @@ namespace svt
        InitFormattedControlBase();
    }

    DateControl::DateControl(BrowserDataWin* pParent, bool bDropDown)
        : FormattedControlBase(pParent, false)
        , m_xMenuButton(m_xBuilder->weld_menu_button("button"))
        , m_xCalendarBuilder(Application::CreateBuilder(m_xMenuButton.get(), "svt/ui/datewindow.ui"))
        , m_xTopLevel(m_xCalendarBuilder->weld_widget("date_popup_window"))
        , m_xCalendar(m_xCalendarBuilder->weld_calendar("date"))
        , m_xTodayBtn(m_xCalendarBuilder->weld_button("today"))
        , m_xNoneBtn(m_xCalendarBuilder->weld_button("none"))
    {
        m_xEntryFormatter.reset(new weld::DateFormatter(*m_xEntry));
        InitFormattedControlBase();

        m_xMenuButton->set_popover(m_xTopLevel.get());
        m_xMenuButton->set_visible(bDropDown);
        m_xMenuButton->connect_toggled(LINK(this, DateControl, ToggleHdl));

        m_xTodayBtn->connect_clicked(LINK(this, DateControl, ImplClickHdl));
        m_xNoneBtn->connect_clicked(LINK(this, DateControl, ImplClickHdl));

        m_xCalendar->connect_activated(LINK(this, DateControl, ActivateHdl));
    }

    IMPL_LINK(DateControl, ImplClickHdl, weld::Button&, rBtn, void)
    {
        m_xMenuButton->set_active(false);
        get_widget().grab_focus();

        if (&rBtn == m_xTodayBtn.get())
        {
            Date aToday(Date::SYSTEM);
            SetDate(aToday);
        }
        else if (&rBtn == m_xNoneBtn.get())
        {
            get_widget().set_text(OUString());
        }
    }

    IMPL_LINK(DateControl, ToggleHdl, weld::ToggleButton&, rButton, void)
    {
        if (rButton.get_active())
            m_xCalendar->set_date(static_cast<weld::DateFormatter&>(get_formatter()).GetDate());
    }

    IMPL_LINK_NOARG(DateControl, ActivateHdl, weld::Calendar&, void)
    {
        if (m_xMenuButton->get_active())
            m_xMenuButton->set_active(false);
        static_cast<weld::DateFormatter&>(get_formatter()).SetDate(m_xCalendar->get_date());
    }

    void DateControl::SetDate(const Date& rDate)
    {
        static_cast<weld::DateFormatter&>(get_formatter()).SetDate(rDate);
        m_xCalendar->set_date(rDate);
    }

    void DateControl::dispose()
    {
        m_xTodayBtn.reset();
        m_xNoneBtn.reset();
        m_xCalendar.reset();
        m_xTopLevel.reset();
        m_xCalendarBuilder.reset();
        m_xMenuButton.reset();
        FormattedControlBase::dispose();
    }

    EditCellController::EditCellController(EditControlBase* pEdit)
        : CellController(pEdit)
        , m_pEditImplementation(new EntryImplementation(*pEdit))
diff --git a/svtools/uiconfig/ui/datewindow.ui b/svtools/uiconfig/ui/datewindow.ui
index bce2ff0..0e7729af 100644
--- a/svtools/uiconfig/ui/datewindow.ui
+++ b/svtools/uiconfig/ui/datewindow.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.36.0 -->
<interface domain="svt">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkPopover" id="date_popup_window">
@@ -26,6 +26,58 @@
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkSeparator">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButtonBox" id="buttonbox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="spacing">6</property>
            <property name="layout_style">spread</property>
            <child>
              <object class="GtkButton" id="today">
                <property name="label" context="calendar|STR_SVT_CALENDAR_TODAY">Today</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="can_default">True</property>
                <property name="receives_default">True</property>
                <property name="use_underline">True</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="none">
                <property name="label" context="calendar|STR_SVT_CALENDAR_NONE">None</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
diff --git a/svtools/uiconfig/ui/thineditcontrol.ui b/svtools/uiconfig/ui/thineditcontrol.ui
index 8fd8f89..d734a8f 100644
--- a/svtools/uiconfig/ui/thineditcontrol.ui
+++ b/svtools/uiconfig/ui/thineditcontrol.ui
@@ -1,42 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<!-- Generated with glade 3.36.0 -->
<interface domain="svt">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkImage" id="image7">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">sc/res/date.png</property>
    <property name="icon_size">2</property>
  </object>
  <object class="GtkBox" id="EditControl">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="hexpand">True</property>
    <property name="vexpand">True</property>
    <property name="orientation">vertical</property>
    <property name="spacing">6</property>
    <child>
      <object class="GtkEntry" id="entry">
        <property name="can_focus">True</property>
        <property name="no_show_all">True</property>
      <object class="GtkGrid">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="hexpand">True</property>
        <property name="vexpand">True</property>
        <property name="has_frame">False</property>
        <property name="activates_default">True</property>
        <property name="width_chars">1</property>
        <child>
          <object class="GtkSpinButton" id="spinbutton">
            <property name="can_focus">True</property>
            <property name="no_show_all">True</property>
            <property name="hexpand">True</property>
            <property name="vexpand">True</property>
            <property name="has_frame">False</property>
          </object>
          <packing>
            <property name="left_attach">0</property>
            <property name="top_attach">1</property>
            <property name="width">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkEntry" id="entry">
            <property name="can_focus">True</property>
            <property name="no_show_all">True</property>
            <property name="hexpand">True</property>
            <property name="vexpand">True</property>
            <property name="has_frame">False</property>
            <property name="activates_default">True</property>
            <property name="width_chars">1</property>
          </object>
          <packing>
            <property name="left_attach">0</property>
            <property name="top_attach">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkMenuButton" id="button">
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="no_show_all">True</property>
            <property name="halign">end</property>
            <property name="image">image7</property>
            <property name="margin_left">1</property>
            <property name="always_show_image">True</property>
            <child internal-child="accessible">
              <object class="AtkObject" id="button-atkobject">
                <property name="AtkObject::accessible-name" translatable="yes" context="thineditcontrol|button">Pick Date</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="left_attach">1</property>
            <property name="top_attach">0</property>
          </packing>
        </child>
      </object>
      <packing>
        <property name="expand">True</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
    <child>
      <object class="GtkSpinButton" id="spinbutton">
        <property name="can_focus">True</property>
        <property name="no_show_all">True</property>
        <property name="hexpand">True</property>
        <property name="vexpand">True</property>
        <property name="has_frame">False</property>
      </object>
      <packing>
        <property name="expand">True</property>
        <property name="fill">True</property>
        <property name="position">1</property>
        <property name="position">2</property>
      </packing>
    </child>
  </object>
diff --git a/svx/source/fmcomp/gridcell.cxx b/svx/source/fmcomp/gridcell.cxx
index 4c1eb32..8e87c2d 100644
--- a/svx/source/fmcomp/gridcell.cxx
+++ b/svx/source/fmcomp/gridcell.cxx
@@ -55,7 +55,6 @@
#include <i18nlangtag/lang.h>

#include <rtl/math.hxx>
#include <vcl/calendar.hxx>
#include <svl/numuno.hxx>
#include <svl/zforlist.hxx>
#include <svx/dialmgr.hxx>
@@ -417,7 +416,6 @@ OUString DbGridColumn::GetCellText(const DbGridRow* pRow, const Reference< XNumb
    return aText;
}


OUString DbGridColumn::GetCellText(const Reference< css::sdb::XColumn >& xField, const Reference< XNumberFormatter >& xFormatter) const
{
    OUString aText;
@@ -432,7 +430,6 @@ OUString DbGridColumn::GetCellText(const Reference< css::sdb::XColumn >& xField,
    return aText;
}


Reference< css::sdb::XColumn >  DbGridColumn::GetCurrentFieldValue() const
{
    Reference< css::sdb::XColumn >  xField;
@@ -1195,7 +1192,6 @@ void DbTextField::updateFromModel( Reference< XPropertySet > _rxModel )
    m_pEdit->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
}


bool DbTextField::commitControl()
{
    OUString aText( m_pEdit->GetText( getModelLineEndSetting( m_rColumn.getModel() ) ) );
@@ -1213,7 +1209,6 @@ bool DbTextField::commitControl()
    return true;
}


void DbTextField::implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen )
{
    if ( m_pEdit )
@@ -1812,7 +1807,6 @@ void DbPatternField::UpdateFromField( const Reference< XColumn >& _rxField, cons
    static_cast< Edit* >( m_pWindow.get() )->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
}


void DbPatternField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbPatternField::updateFromModel: invalid call!" );
@@ -1824,7 +1818,6 @@ void DbPatternField::updateFromModel( Reference< XPropertySet > _rxModel )
    static_cast< Edit* >( m_pWindow.get() )->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
}


bool DbPatternField::commitControl()
{
    OUString aText(m_pWindow->GetText());
@@ -2143,21 +2136,20 @@ DbDateField::DbDateField( DbGridColumn& _rColumn )
    doPropertyListening( FM_PROP_DATE_SHOW_CENTURY );
}

VclPtr<Control> DbDateField::createField(BrowserDataWin* _pParent, bool bSpinButton, const Reference< XPropertySet >& _rxModel  )
VclPtr<Control> DbDateField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& rxModel)
{
    WinBits _nFieldStyle = bSpinButton ? (WB_REPEAT | WB_SPIN) : 0;
    // check if there is a DropDown property set to TRUE
    bool bDropDown =    !hasProperty( FM_PROP_DROPDOWN, _rxModel )
                        ||  getBOOL( _rxModel->getPropertyValue( FM_PROP_DROPDOWN ) );
    if ( bDropDown )
        _nFieldStyle |= WB_DROPDOWN;
    bool bDropDown =    !hasProperty( FM_PROP_DROPDOWN, rxModel )
                        ||  getBOOL( rxModel->getPropertyValue( FM_PROP_DROPDOWN ) );
    // given the apparent inability to set a custom up/down action for a gtk
    // spinbutton to have different up/down dates depending on the zone the
    // mouse is in, show the dropdown calender for both the spin or dropdown case
    return VclPtr<DateControl>::Create(pParent, bSpinButton || bDropDown);
}

    VclPtr<CalendarField> pField = VclPtr<CalendarField>::Create( _pParent, _nFieldStyle );

    pField->EnableToday();
    pField->EnableNone();

    return pField;
CellControllerRef DbDateField::CreateController() const
{
    return new ::svt::FormattedFieldCellController(static_cast<FormattedControlBase*>(m_pWindow.get()));
}

void DbDateField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
@@ -2174,32 +2166,37 @@ void DbDateField::implAdjustGenericFieldSetting( const Reference< XPropertySet >
    OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_DATEMAX ) >>= aMax );
    bool    bStrict     = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());

    FormattedControlBase* pPainter = static_cast<FormattedControlBase*>(m_pPainter.get());
    weld::DateFormatter& rPainterFormatter = static_cast<weld::DateFormatter&>(pPainter->get_formatter());

    Any  aCentury = _rxModel->getPropertyValue( FM_PROP_DATE_SHOW_CENTURY );
    if ( aCentury.getValueType().getTypeClass() != TypeClass_VOID )
    {
        bool bShowDateCentury = getBOOL( aCentury );

        static_cast<DateField*>( m_pWindow.get() )->SetShowDateCentury( bShowDateCentury );
        static_cast<DateField*>( m_pPainter.get() )->SetShowDateCentury( bShowDateCentury );
        rControlFormatter.SetShowDateCentury(bShowDateCentury);
        rPainterFormatter.SetShowDateCentury(bShowDateCentury);
    }

    static_cast< DateField* >( m_pWindow.get() )->SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    static_cast< DateField* >( m_pWindow.get() )->SetMin( aMin );
    static_cast< DateField* >( m_pWindow.get() )->SetMax( aMax );
    static_cast< DateField* >( m_pWindow.get() )->SetStrictFormat( bStrict );
    static_cast< DateField* >( m_pWindow.get() )->EnableEmptyFieldValue( true );
    rControlFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    rControlFormatter.SetMin( aMin );
    rControlFormatter.SetMax( aMax );
    rControlFormatter.SetStrictFormat( bStrict );
    rControlFormatter.EnableEmptyField( true );

    static_cast< DateField* >( m_pPainter.get() )->SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    static_cast< DateField* >( m_pPainter.get() )->SetMin( aMin );
    static_cast< DateField* >( m_pPainter.get() )->SetMax( aMax );
    static_cast< DateField* >( m_pPainter.get() )->SetStrictFormat( bStrict );
    static_cast< DateField* >( m_pPainter.get() )->EnableEmptyFieldValue( true );
    rPainterFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    rPainterFormatter.SetMin( aMin );
    rPainterFormatter.SetMax( aMax );
    rPainterFormatter.SetStrictFormat( bStrict );
    rPainterFormatter.EnableEmptyField( true );
}

namespace
{

    OUString lcl_setFormattedDate_nothrow( DateField& _rField, const Reference< XColumn >& _rxField )
    OUString lcl_setFormattedDate_nothrow(DateControl& _rField, const Reference<XColumn>& _rxField)
    {
        OUString sDate;
        if ( _rxField.is() )
@@ -2207,12 +2204,10 @@ namespace
            try
            {
                css::util::Date aValue = _rxField->getDate();
                if ( _rxField->wasNull() )
                    _rField.SetText( sDate );
                else
                if (!_rxField->wasNull())
                {
                    _rField.SetDate( ::Date( aValue.Day, aValue.Month, aValue.Year ) );
                    sDate = _rField.GetText();
                    _rField.SetDate(::Date(aValue.Day, aValue.Month, aValue.Year));
                    sDate = _rField.get_widget().get_text();
                }
            }
            catch( const Exception& )
@@ -2226,33 +2221,38 @@ namespace

OUString DbDateField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, Color** /*ppColor*/)
{
     return lcl_setFormattedDate_nothrow(dynamic_cast<DateField&>(*m_pPainter), _rxField);
     return lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pPainter.get()), _rxField);
}

void DbDateField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    lcl_setFormattedDate_nothrow(dynamic_cast<DateField&>(*m_pWindow), _rxField);
    lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pWindow.get()), _rxField);
}

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

    DateControl* pControl = static_cast<DateControl*>(m_pWindow.get());

    util::Date aDate;
    if ( _rxModel->getPropertyValue( FM_PROP_DATE ) >>= aDate )
        static_cast< DateField* >( m_pWindow.get() )->SetDate( ::Date( aDate ) );
        pControl->SetDate(::Date(aDate));
    else
        static_cast< DateField* >( m_pWindow.get() )->SetText( OUString() );
        pControl->get_widget().set_text(OUString());
}

bool DbDateField::commitControl()
{
    OUString aText(m_pWindow->GetText());
    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    OUString aText(pControl->get_widget().get_text());
    Any aVal;
    if (!aText.isEmpty())
        aVal <<= static_cast<DateField*>(m_pWindow.get())->GetDate().GetUNODate();
    else
        aVal.clear();

    if (!aText.isEmpty())   // not empty
    {
        weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());
        aVal <<= rControlFormatter.GetDate().GetUNODate();
    }

    m_rColumn.getModel()->setPropertyValue(FM_PROP_DATE, aVal);
    return true;
@@ -2365,13 +2365,12 @@ bool DbTimeField::commitControl()
    OUString aText(pControl->get_widget().get_text());
    Any aVal;

    fprintf(stderr, "text is %s\n", aText.toUtf8().getStr());

    if (!aText.isEmpty())   // not empty
    {
        weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());
        aVal <<= rControlFormatter.GetTime().GetUNOTime();
    }

    m_rColumn.getModel()->setPropertyValue(FM_PROP_TIME, aVal);
    return true;
}
@@ -3618,7 +3617,6 @@ void SAL_CALL FmXEditCell::insertText(const css::awt::Selection& rSel, const OUS
    }
}


OUString SAL_CALL FmXEditCell::getText()
{
    ::osl::MutexGuard aGuard( m_aMutex );
@@ -4212,43 +4210,36 @@ void SAL_CALL FmXFilterCell::removeTextListener(const Reference< css::awt::XText
    m_aTextListeners.removeInterface( l );
}


void SAL_CALL FmXFilterCell::setText( const OUString& aText )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    static_cast<DbFilterField*>(m_pCellControl.get())->SetText(aText);
}


void SAL_CALL FmXFilterCell::insertText( const css::awt::Selection& /*rSel*/, const OUString& /*aText*/ )
{
}


OUString SAL_CALL FmXFilterCell::getText()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    return static_cast<DbFilterField*>(m_pCellControl.get())->GetText();
}


OUString SAL_CALL FmXFilterCell::getSelectedText()
{
    return getText();
}


void SAL_CALL FmXFilterCell::setSelection( const css::awt::Selection& /*aSelection*/ )
{
}


css::awt::Selection SAL_CALL FmXFilterCell::getSelection()
{
    return css::awt::Selection();
}


sal_Bool SAL_CALL FmXFilterCell::isEditable()
{
    return true;
diff --git a/svx/source/inc/gridcell.hxx b/svx/source/inc/gridcell.hxx
index 0a65995..e4203d31 100644
--- a/svx/source/inc/gridcell.hxx
+++ b/svx/source/inc/gridcell.hxx
@@ -557,6 +557,7 @@ class DbDateField : public DbSpinField
{
public:
    DbDateField(DbGridColumn& _rColumn);
    virtual ::svt::CellControllerRef CreateController() const override;
    virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, Color** ppColor = nullptr) override;
    virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;

diff --git a/toolkit/source/awt/vclxtoolkit.cxx b/toolkit/source/awt/vclxtoolkit.cxx
index 267a9fc..e1faaf2 100644
--- a/toolkit/source/awt/vclxtoolkit.cxx
+++ b/toolkit/source/awt/vclxtoolkit.cxx
@@ -81,7 +81,7 @@
#include <controls/filectrl.hxx>
#include <controls/treecontrolpeer.hxx>
#include <vcl/toolkit/button.hxx>
#include <vcl/calendar.hxx>
#include <vcl/toolkit/calendar.hxx>
#include <vcl/toolkit/combobox.hxx>
#include <vcl/ctrl.hxx>
#include <vcl/toolkit/dialog.hxx>
diff --git a/vcl/source/app/weldutils.cxx b/vcl/source/app/weldutils.cxx
index 9efab32..e245666 100644
--- a/vcl/source/app/weldutils.cxx
+++ b/vcl/source/app/weldutils.cxx
@@ -422,6 +422,30 @@ void TimeFormatter::SetTimeFormat(TimeFieldFormat eTimeFormat)
}

TimeFormatter::~TimeFormatter() = default;

DateFormatter::DateFormatter(weld::Entry& rEntry)
    : EntryFormatter(rEntry)
    , m_eFormat(ExtDateFieldFormat::SystemShort)
{
    Init();
}

void DateFormatter::Init()
{
    SetOutputHdl(LINK(this, DateFormatter, FormatOutputHdl));
    SetInputHdl(LINK(this, DateFormatter, ParseInputHdl));

    SetMin(Date(1, 1, 1900));
    SetMax(Date(31, 12, 2200));
}

void DateFormatter::SetExtDateFormat(ExtDateFieldFormat eFormat)
{
    m_eFormat = eFormat;
    ReFormat();
}

DateFormatter::~DateFormatter() = default;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/control/calendar.cxx b/vcl/source/control/calendar.cxx
index 083bfa6..14fcfe6 100644
--- a/vcl/source/control/calendar.cxx
+++ b/vcl/source/control/calendar.cxx
@@ -22,7 +22,7 @@
#include <vcl/menu.hxx>
#include <vcl/settings.hxx>
#include <vcl/event.hxx>
#include <vcl/calendar.hxx>
#include <vcl/toolkit/calendar.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/dockwin.hxx>
#include <unotools/calendarwrapper.hxx>
diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx
index 2388daa..1cbf4fc 100644
--- a/vcl/source/control/field2.cxx
+++ b/vcl/source/control/field2.cxx
@@ -1003,8 +1003,8 @@ static bool ImplDateProcessKeyInput( const KeyEvent& rKEvt, ExtDateFieldFormat e
             (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat )[0]));
}

static bool ImplDateGetValue( const OUString& rStr, Date& rDate, ExtDateFieldFormat eDateOrder,
                              const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper )
bool DateFormatter::TextToDate(const OUString& rStr, Date& rDate, ExtDateFieldFormat eDateOrder,
                               const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper)
{
    sal_uInt16 nDay = 0;
    sal_uInt16 nMonth = 0;
@@ -1115,7 +1115,7 @@ static bool ImplDateGetValue( const OUString& rStr, Date& rDate, ExtDateFieldFor
void DateFormatter::ImplDateReformat( const OUString& rStr, OUString& rOutStr )
{
    Date aDate( Date::EMPTY );
    if ( !ImplDateGetValue( rStr, aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
    if (!TextToDate(rStr, aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
        return;

    Date aTempDate = aDate;
@@ -1127,10 +1127,34 @@ void DateFormatter::ImplDateReformat( const OUString& rStr, OUString& rOutStr )
    rOutStr = ImplGetDateAsText( aTempDate );
}

OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
namespace
{
    ExtDateFieldFormat ResolveSystemFormat(ExtDateFieldFormat eDateFormat, const LocaleDataWrapper& rLocaleData)
    {
        if (eDateFormat <= ExtDateFieldFormat::SystemShortYYYY)
        {
            bool bShowCentury = (eDateFormat == ExtDateFieldFormat::SystemShortYYYY);
            switch (rLocaleData.getDateOrder())
            {
                case DateOrder::DMY:
                    eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortDDMMYYYY : ExtDateFieldFormat::ShortDDMMYY;
                    break;
                case DateOrder::MDY:
                    eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortMMDDYYYY : ExtDateFieldFormat::ShortMMDDYY;
                    break;
                default:
                    eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortYYYYMMDD : ExtDateFieldFormat::ShortYYMMDD;
            }
        }
        return eDateFormat;
    }
}

OUString DateFormatter::FormatDate(const Date& rDate, ExtDateFieldFormat eExtFormat,
                                   const LocaleDataWrapper& rLocaleData, CalendarWrapper& rCalendarWrapper)
{
    bool bShowCentury = false;
    switch ( GetExtDateFormat() )
    switch (eExtFormat)
    {
        case ExtDateFieldFormat::SystemShortYYYY:
        case ExtDateFieldFormat::SystemLong:
@@ -1162,7 +1186,9 @@ OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
    sal_Unicode aBuf[128];
    sal_Unicode* pBuf = aBuf;

    OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( true ) );
    eExtFormat = ResolveSystemFormat(eExtFormat, rLocaleData);

    OUString aDateSep = ImplGetDateSep( rLocaleData, eExtFormat );
    sal_uInt16 nDay = rDate.GetDay();
    sal_uInt16 nMonth = rDate.GetMonth();
    sal_Int16 nYear = rDate.GetYear();
@@ -1171,11 +1197,11 @@ OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
    if ( !bShowCentury )
        nYear %= 100;

    switch ( GetExtDateFormat( true ) )
    switch (eExtFormat)
    {
        case ExtDateFieldFormat::SystemLong:
        {
            return ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), !bShowCentury );
            return rLocaleData.getLongDate( rDate, rCalendarWrapper, !bShowCentury );
        }
        case ExtDateFieldFormat::ShortDDMMYY:
        case ExtDateFieldFormat::ShortDDMMYYYY:
@@ -1218,6 +1244,11 @@ OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
    return OUString(aBuf, pBuf-aBuf);
}

OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
{
    return DateFormatter::FormatDate(rDate, GetExtDateFormat(), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
}

static void ImplDateIncrementDay( Date& rDate, bool bUp )
{
    DateFormatter::ExpandCentury( rDate );
@@ -1309,6 +1340,36 @@ bool DateFormatter::ImplAllowMalformedInput() const
    return !IsEnforceValidValue();
}

int DateFormatter::GetDateArea(ExtDateFieldFormat eFormat, const OUString& rText, int nCursor, const LocaleDataWrapper& rLocaleDataWrapper)
{
    sal_Int8 nDateArea = 0;

    if ( eFormat == ExtDateFieldFormat::SystemLong )
    {
        eFormat = ImplGetExtFormat(rLocaleDataWrapper.getLongDateOrder());
        nDateArea = 1;
    }
    else
    {
        // search area
        sal_Int32 nPos = 0;
        OUString aDateSep = ImplGetDateSep(rLocaleDataWrapper, eFormat);
        for ( sal_Int8 i = 1; i <= 3; i++ )
        {
            nPos = rText.indexOf( aDateSep, nPos );
            if (nPos < 0 || nPos >= nCursor)
            {
                nDateArea = i;
                break;
            }
            else
                nPos++;
        }
    }

    return nDateArea;
}

void DateField::ImplDateSpinArea( bool bUp )
{
    // increment days if all is selected
@@ -1322,31 +1383,8 @@ void DateField::ImplDateSpinArea( bool bUp )
            ImplDateIncrementDay( aDate, bUp );
        else
        {
            sal_Int8 nDateArea = 0;

            ExtDateFieldFormat eFormat = GetExtDateFormat( true );
            if ( eFormat == ExtDateFieldFormat::SystemLong )
            {
                eFormat = ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateOrder() );
                nDateArea = 1;
            }
            else
            {
                // search area
                sal_Int32 nPos = 0;
                OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat );
                for ( sal_Int8 i = 1; i <= 3; i++ )
                {
                    nPos = aText.indexOf( aDateSep, nPos );
                    if (nPos < 0 || nPos >= static_cast<sal_Int32>(aSelection.Max()))
                    {
                        nDateArea = i;
                        break;
                    }
                    else
                        nPos++;
                }
            }
            sal_Int8 nDateArea = GetDateArea(eFormat, aText, aSelection.Max(), ImplGetLocaleDataWrapper());

            switch( eFormat )
            {
@@ -1436,21 +1474,8 @@ ExtDateFieldFormat DateFormatter::GetExtDateFormat( bool bResolveSystemFormat ) 
{
    ExtDateFieldFormat eDateFormat = mnExtDateFormat;

    if ( bResolveSystemFormat && ( eDateFormat <= ExtDateFieldFormat::SystemShortYYYY ) )
    {
        bool bShowCentury = (eDateFormat == ExtDateFieldFormat::SystemShortYYYY);
        switch ( ImplGetLocaleDataWrapper().getDateOrder() )
        {
            case DateOrder::DMY:
                eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortDDMMYYYY : ExtDateFieldFormat::ShortDDMMYY;
                break;
            case DateOrder::MDY:
                eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortMMDDYYYY : ExtDateFieldFormat::ShortMMDDYY;
                break;
            default:
                eDateFormat = bShowCentury ? ExtDateFieldFormat::ShortYYYYMMDD : ExtDateFieldFormat::ShortYYMMDD;
        }
    }
    if (bResolveSystemFormat)
        eDateFormat = ResolveSystemFormat(eDateFormat, ImplGetLocaleDataWrapper());

    return eDateFormat;
}
@@ -1492,49 +1517,59 @@ void DateFormatter::SetLongFormat( bool bLong )
    ReformatAll();
}

namespace
{
    ExtDateFieldFormat ChangeDateCentury(ExtDateFieldFormat eExtDateFormat, bool bShowDateCentury)
    {
        // #91913# Remove LongFormat and DateShowCentury - redundant
        if (bShowDateCentury)
        {
            switch (eExtDateFormat)
            {
                case ExtDateFieldFormat::SystemShort:
                case ExtDateFieldFormat::SystemShortYY:
                    eExtDateFormat = ExtDateFieldFormat::SystemShortYYYY;  break;
                case ExtDateFieldFormat::ShortDDMMYY:
                    eExtDateFormat = ExtDateFieldFormat::ShortDDMMYYYY;     break;
                case ExtDateFieldFormat::ShortMMDDYY:
                    eExtDateFormat = ExtDateFieldFormat::ShortMMDDYYYY;     break;
                case ExtDateFieldFormat::ShortYYMMDD:
                    eExtDateFormat = ExtDateFieldFormat::ShortYYYYMMDD;     break;
                case ExtDateFieldFormat::ShortYYMMDD_DIN5008:
                    eExtDateFormat = ExtDateFieldFormat::ShortYYYYMMDD_DIN5008; break;
                default:
                    ;
            }
        }
        else
        {
            switch (eExtDateFormat)
            {
                case ExtDateFieldFormat::SystemShort:
                case ExtDateFieldFormat::SystemShortYYYY:
                    eExtDateFormat = ExtDateFieldFormat::SystemShortYY;    break;
                case ExtDateFieldFormat::ShortDDMMYYYY:
                    eExtDateFormat = ExtDateFieldFormat::ShortDDMMYY;       break;
                case ExtDateFieldFormat::ShortMMDDYYYY:
                    eExtDateFormat = ExtDateFieldFormat::ShortMMDDYY;       break;
                case ExtDateFieldFormat::ShortYYYYMMDD:
                    eExtDateFormat = ExtDateFieldFormat::ShortYYMMDD;       break;
                case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008:
                    eExtDateFormat = ExtDateFieldFormat::ShortYYMMDD_DIN5008;  break;
                default:
                    ;
            }
        }

        return eExtDateFormat;
    }
}

void DateFormatter::SetShowDateCentury( bool bShowDateCentury )
{
    mbShowDateCentury = bShowDateCentury;

    // #91913# Remove LongFormat and DateShowCentury - redundant
    if ( bShowDateCentury )
    {
        switch ( GetExtDateFormat() )
        {
            case ExtDateFieldFormat::SystemShort:
            case ExtDateFieldFormat::SystemShortYY:
                SetExtDateFormat( ExtDateFieldFormat::SystemShortYYYY );  break;
            case ExtDateFieldFormat::ShortDDMMYY:
                SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYYYY );     break;
            case ExtDateFieldFormat::ShortMMDDYY:
                SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYYYY );     break;
            case ExtDateFieldFormat::ShortYYMMDD:
                SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD );     break;
            case ExtDateFieldFormat::ShortYYMMDD_DIN5008:
                SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD_DIN5008 ); break;
            default:
                ;
        }
    }
    else
    {
        switch ( GetExtDateFormat() )
        {
            case ExtDateFieldFormat::SystemShort:
            case ExtDateFieldFormat::SystemShortYYYY:
                SetExtDateFormat( ExtDateFieldFormat::SystemShortYY );    break;
            case ExtDateFieldFormat::ShortDDMMYYYY:
                SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYY );       break;
            case ExtDateFieldFormat::ShortMMDDYYYY:
                SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYY );       break;
            case ExtDateFieldFormat::ShortYYYYMMDD:
                SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD );       break;
            case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008:
                SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD_DIN5008 );  break;
            default:
                ;
        }
    }
    SetExtDateFormat(ChangeDateCentury(GetExtDateFormat(), bShowDateCentury));

    ReformatAll();
}
@@ -1594,7 +1629,7 @@ Date DateFormatter::GetDate() const

    if ( GetField() )
    {
        if ( ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
        if (TextToDate(GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
        {
            if ( aDate > maMax )
                aDate = maMax;
@@ -1639,7 +1674,7 @@ bool DateFormatter::IsEmptyDate() const
        else if ( !maLastDate.GetDate() )
        {
            Date aDate( Date::EMPTY );
            bEmpty = !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() );
            bEmpty = !TextToDate(GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
        }
    }
    return bEmpty;
@@ -1659,7 +1694,7 @@ void DateFormatter::Reformat()
    if ( !aStr.isEmpty() )
    {
        ImplSetText( aStr );
        (void)ImplDateGetValue(aStr, maLastDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
        (void)TextToDate(aStr, maLastDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
    }
    else
    {
@@ -1741,7 +1776,7 @@ bool DateField::EventNotify( NotifyEvent& rNEvt )
                else
                {
                    Date aDate( 0, 0, 0 );
                    if ( ImplDateGetValue( GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
                    if (TextToDate(GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
                        // even with strict text analysis, our text is a valid date -> do a complete
                        // reformat
                        Reformat();
@@ -1881,6 +1916,79 @@ void DateBox::ReformatAll()
    SetUpdateMode( true );
}

namespace weld
{
    CalendarWrapper& DateFormatter::GetCalendarWrapper() const
    {
        if (!m_xCalendarWrapper)
        {
            m_xCalendarWrapper.reset(new CalendarWrapper(comphelper::getProcessComponentContext()));
            m_xCalendarWrapper->loadDefaultCalendar(Application::GetSettings().GetLanguageTag().getLocale());
        }
        return *m_xCalendarWrapper;
    }

    void DateFormatter::SetShowDateCentury(bool bShowDateCentury)
    {
        m_eFormat = ChangeDateCentury(m_eFormat, bShowDateCentury);

        ReFormat();
    }

    void DateFormatter::SetDate(const Date& rDate)
    {
        auto nDate = rDate.GetDate();
        bool bForceOutput = GetEntryText().isEmpty() && rDate == GetDate();
        if (bForceOutput)
        {
            ImplSetValue(nDate, true);
            return;
        }
        SetValue(nDate);
    }

    Date DateFormatter::GetDate()
    {
        return Date(GetValue());
    }

    void DateFormatter::SetMin(const Date& rNewMin)
    {
        SetMinValue(rNewMin.GetDate());
    }

    void DateFormatter::SetMax(const Date& rNewMax)
    {
        SetMaxValue(rNewMax.GetDate());
    }

    OUString DateFormatter::FormatNumber(int nValue) const
    {
        const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
        return ::DateFormatter::FormatDate(Date(nValue), m_eFormat, rLocaleData, GetCalendarWrapper());
    }

    IMPL_LINK_NOARG(DateFormatter, FormatOutputHdl, LinkParamNone*, bool)
    {
        OUString sText = FormatNumber(GetValue());
        ImplSetTextImpl(sText, nullptr);
        return true;
    }

    IMPL_LINK(DateFormatter, ParseInputHdl, sal_Int64*, result, TriState)
    {
        const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();

        Date aResult(Date::EMPTY);
        bool bRet = ::DateFormatter::TextToDate(GetEntryText(), aResult, ResolveSystemFormat(m_eFormat, rLocaleDataWrapper),
                                                rLocaleDataWrapper, GetCalendarWrapper());
        if (bRet)
            *result = aResult.GetDate();

        return bRet ? TRISTATE_TRUE : TRISTATE_FALSE;
    }
}

static bool ImplTimeProcessKeyInput( const KeyEvent& rKEvt,
                                     bool bStrictFormat, bool bDuration,
                                     TimeFieldFormat eFormat,
@@ -2722,7 +2830,14 @@ namespace weld

    void TimeFormatter::SetTime(const tools::Time& rTime)
    {
        SetValue(ConvertValue(rTime));
        auto nTime = ConvertValue(rTime);
        bool bForceOutput = GetEntryText().isEmpty() && rTime == GetTime();
        if (bForceOutput)
        {
            ImplSetValue(nTime, true);
            return;
        }
        SetValue(nTime);
    }

    tools::Time TimeFormatter::GetTime()