[Libreoffice-commits] core.git: include/svtools include/vcl solenv/clang-format svtools/source svtools/uiconfig svx/source toolkit/source vcl/source

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Tue Jul 21 08:26:28 UTC 2020


 include/svtools/editbrowsebox.hxx      |   21 ++
 include/vcl/field.hxx                  |  107 ------------
 include/vcl/toolkit/calendar.hxx       |    6 
 include/vcl/toolkit/field.hxx          |  111 ++++++++++++
 include/vcl/weldutils.hxx              |   32 +++
 solenv/clang-format/excludelist        |    2 
 svtools/source/brwbox/ebbcontrols.cxx  |   69 +++++++
 svtools/uiconfig/ui/datewindow.ui      |   54 ++++++
 svtools/uiconfig/ui/thineditcontrol.ui |   83 ++++++---
 svx/source/fmcomp/gridcell.cxx         |  105 +++++------
 svx/source/inc/gridcell.hxx            |    1 
 toolkit/source/awt/vclxtoolkit.cxx     |    2 
 vcl/source/app/weldutils.cxx           |   24 ++
 vcl/source/control/calendar.cxx        |    2 
 vcl/source/control/field2.cxx          |  291 +++++++++++++++++++++++----------
 15 files changed, 630 insertions(+), 280 deletions(-)

New commits:
commit 6e7e19d9c300dbdd279789b09f94781e946fad52
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Wed Jul 15 12:10:32 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Tue Jul 21 10:25:42 2020 +0200

    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 at redhat.com>

diff --git a/include/svtools/editbrowsebox.hxx b/include/svtools/editbrowsebox.hxx
index b5ffad460555..4dc3381d5aaa 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 1cb4974bfd08..36a786061bdb 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 a88105e29e59..a1a1cd90105a 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 6b994b02baea..6316c5698933 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 e1944cc41ee8..cc2a49d4d881 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 ac6e1e28bdee..0708c30817f7 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 ba90f7f5a3a2..3f1c0196e838 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 bce2ff038a94..0e7729afe74e 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 8fd8f891d778..d734a8f269b8 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>
-        <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="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>
+      <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>
+        <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">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 4c1eb3211412..8e87c2dabfc6 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;
-
-    VclPtr<CalendarField> pField = VclPtr<CalendarField>::Create( _pParent, _nFieldStyle );
-
-    pField->EnableToday();
-    pField->EnableNone();
+    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);
+}
 
-    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 0a65995c9435..e4203d31819a 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 267a9fced788..e1faaf2f31ca 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 9efab321e91d..e24566675123 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 083bfa6d34d6..14fcfe62f797 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 2388daa6bfb7..1cbf4fcf9e92 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();
 }
 
-void DateFormatter::SetShowDateCentury( bool bShowDateCentury )
+namespace
 {
-    mbShowDateCentury = bShowDateCentury;
-
-    // #91913# Remove LongFormat and DateShowCentury - redundant
-    if ( bShowDateCentury )
+    ExtDateFieldFormat ChangeDateCentury(ExtDateFieldFormat eExtDateFormat, bool bShowDateCentury)
     {
-        switch ( GetExtDateFormat() )
+        // #91913# Remove LongFormat and DateShowCentury - redundant
+        if (bShowDateCentury)
         {
-            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:
-                ;
+            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 ( GetExtDateFormat() )
+        else
         {
-            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:
-                ;
+            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;
+
+    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()


More information about the Libreoffice-commits mailing list