X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5385747ec611def9aad85cc3d5cdba6605b466bb..12bb29f5432174ecbd65549bda832d70d34a98ae:/src/msw/datectrl.cpp diff --git a/src/msw/datectrl.cpp b/src/msw/datectrl.cpp index 012de2fe24..02de59289b 100644 --- a/src/msw/datectrl.cpp +++ b/src/msw/datectrl.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: msw/datectrl.cpp +// Name: src/msw/datectrl.cpp // Purpose: wxDatePickerCtrl implementation // Author: Vadim Zeitlin // Modified by: @@ -23,51 +23,27 @@ #pragma hdrstop #endif +#if wxUSE_DATEPICKCTRL + #ifndef WX_PRECOMP + #include "wx/msw/wrapwin.h" + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/msw/private.h" #endif -#if wxUSE_DATEPICKCTRL - #include "wx/datectrl.h" - -#define _WX_DEFINE_DATE_EVENTS_ #include "wx/dateevt.h" -#include "wx/msw/wrapwin.h" -#include "wx/msw/wrapcctl.h" -#include "wx/msw/private.h" +IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl) // ============================================================================ // implementation // ============================================================================ -// ---------------------------------------------------------------------------- -// helpers for wxDateTime <-> SYSTEMTIME conversion -// ---------------------------------------------------------------------------- - -static inline void wxFromSystemTime(wxDateTime *dt, const SYSTEMTIME& st) -{ - dt->Set(st.wDay, - wx_static_cast(wxDateTime::Month, wxDateTime::Jan + st.wMonth - 1), - st.wYear, - 0, 0, 0); -} - -static inline void wxToSystemTime(SYSTEMTIME *st, const wxDateTime& dt) -{ - const wxDateTime::Tm tm(dt.GetTm()); - - st->wYear = tm.year; - st->wMonth = tm.mon - wxDateTime::Jan + 1; - st->wDay = tm.mday; - - st->wDayOfWeek = - st->wHour = - st->wMinute = - st->wSecond = - st->wMilliseconds = 0; -} - // ---------------------------------------------------------------------------- // wxDatePickerCtrl creation // ---------------------------------------------------------------------------- @@ -86,44 +62,39 @@ wxDatePickerCtrl::Create(wxWindow *parent, if ( !(style & wxDP_DROPDOWN) ) style |= wxDP_SPIN; - // initialize the base class - if ( !CreateControl(parent, id, pos, size, style, validator, name) ) - return false; - - // create the native control - if ( !MSWCreateControl(DATETIMEPICK_CLASS, _T(""), pos, size) ) - return false; - - if ( dt.IsValid() ) - SetValue(dt); - - return true; + return MSWCreateDateTimePicker(parent, id, dt, + pos, size, style, + validator, name); } WXDWORD wxDatePickerCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const { WXDWORD styleMSW = wxDatePickerCtrlBase::MSWGetStyle(style, exstyle); - if ( style & wxDP_SPIN ) + // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with + // comctl32.dll 4.72 + if ( wxApp::GetComCtl32Version() > 472 && (style & wxDP_SPIN) ) styleMSW |= DTS_UPDOWN; //else: drop down by default - styleMSW |= DTS_SHORTDATEFORMAT; +#ifdef DTS_SHORTDATECENTURYFORMAT + if ( style & wxDP_SHOWCENTURY ) + styleMSW |= DTS_SHORTDATECENTURYFORMAT; + else +#endif // DTS_SHORTDATECENTURYFORMAT + styleMSW |= DTS_SHORTDATEFORMAT; + + if ( style & wxDP_ALLOWNONE ) + styleMSW |= DTS_SHOWNONE; return styleMSW; } // TODO: handle WM_WININICHANGE -// ---------------------------------------------------------------------------- -// wxDatePickerCtrl geometry -// ---------------------------------------------------------------------------- - -wxSize wxDatePickerCtrl::DoGetBestSize() const +wxLocaleInfo wxDatePickerCtrl::MSWGetFormat() const { - const int y = GetCharHeight(); - - return wxSize(DEFAULT_ITEM_WIDTH, EDIT_HEIGHT_FROM_CHAR_HEIGHT(y)); + return wxLOCALE_SHORT_DATE_FMT; } // ---------------------------------------------------------------------------- @@ -132,29 +103,54 @@ wxSize wxDatePickerCtrl::DoGetBestSize() const void wxDatePickerCtrl::SetValue(const wxDateTime& dt) { - // as we don't support DTS_SHOWNONE style so far, we don't allow setting - // the control to an invalid date, but this restriction may be lifted in - // the future - wxCHECK_RET( dt.IsValid(), _T("invalid date") ); - - SYSTEMTIME st; - wxToSystemTime(&st, dt); - if ( !DateTime_SetSystemtime(GetHwnd(), GDT_VALID, &st) ) + if ( dt.IsValid() ) { - wxLogDebug(_T("DateTime_SetSystemtime() failed")); + // Don't try setting the date if it's out of range: calendar control + // under XP (and presumably all the other pre-Vista Windows versions) + // doesn't return false from DateTime_SetSystemtime() in this case but + // doesn't actually change the date, so we can't update our m_date + // unconditionally and would need to check whether it was changed + // before doing it. It looks simpler to just check whether it's in + // range here instead. + // + // If we ever drop support for XP we could rely on the return value of + // DateTime_SetSystemtime() but this probably won't happen in near + // future. + wxDateTime dtStart, dtEnd; + GetRange(&dtStart, &dtEnd); + if ( (dtStart.IsValid() && dt < dtStart) || + (dtEnd.IsValid() && dt > dtEnd) ) + { + // Fail silently, some existing code relies on SetValue() with an + // out of range value simply doing nothing -- so don't. + return; + } } + + wxDateTimePickerCtrl::SetValue(dt); + + // we need to keep only the date part, times don't make sense for this + // control (in particular, comparisons with other dates would fail) + if ( m_date.IsValid() ) + m_date.ResetTime(); } wxDateTime wxDatePickerCtrl::GetValue() const { +#if wxDEBUG_LEVEL wxDateTime dt; SYSTEMTIME st; if ( DateTime_GetSystemtime(GetHwnd(), &st) == GDT_VALID ) { - wxFromSystemTime(&dt, st); + dt.SetFromMSWSysDate(st); } - return dt; + wxASSERT_MSG( m_date.IsValid() == dt.IsValid() && + (!dt.IsValid() || dt == m_date), + wxT("bug in wxDateTimePickerCtrl: m_date not in sync") ); +#endif // wxDEBUG_LEVEL + + return wxDateTimePickerCtrl::GetValue(); } void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2) @@ -164,19 +160,19 @@ void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2) DWORD flags = 0; if ( dt1.IsValid() ) { - wxToSystemTime(&st[0], dt1); + dt1.GetAsMSWSysTime(st + 0); flags |= GDTR_MIN; } if ( dt2.IsValid() ) { - wxToSystemTime(&st[1], dt2); + dt2.GetAsMSWSysTime(st + 1); flags |= GDTR_MAX; } if ( !DateTime_SetRange(GetHwnd(), flags, st) ) { - wxLogDebug(_T("DateTime_SetRange() failed")); + wxLogDebug(wxT("DateTime_SetRange() failed")); } } @@ -188,7 +184,7 @@ bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const if ( dt1 ) { if ( flags & GDTR_MIN ) - wxFromSystemTime(dt1, st[0]); + dt1->SetFromMSWSysDate(st[0]); else *dt1 = wxDefaultDateTime; } @@ -196,7 +192,7 @@ bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const if ( dt2 ) { if ( flags & GDTR_MAX ) - wxFromSystemTime(dt2, st[1]); + dt2->SetFromMSWSysDate(st[1]); else *dt2 = wxDefaultDateTime; } @@ -208,28 +204,21 @@ bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const // wxDatePickerCtrl events // ---------------------------------------------------------------------------- -bool -wxDatePickerCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) +bool wxDatePickerCtrl::MSWOnDateTimeChange(const NMDATETIMECHANGE& dtch) { - NMHDR* hdr = (NMHDR *)lParam; - switch ( hdr->code ) - { - case DTN_DATETIMECHANGE: - NMDATETIMECHANGE *dtch = (NMDATETIMECHANGE *)hdr; - wxDateTime dt; - if ( dtch->dwFlags == GDT_VALID ) - wxFromSystemTime(&dt, dtch->st); - - wxDateEvent event(this, dt, wxEVT_DATE_CHANGED); - if ( GetEventHandler()->ProcessEvent(event) ) - { - *result = 0; - return true; - } - } + wxDateTime dt; + if ( dtch.dwFlags == GDT_VALID ) + dt.SetFromMSWSysDate(dtch.st); - return wxDatePickerCtrlBase::MSWOnNotify(idCtrl, lParam, result); + // filter out duplicate DTN_DATETIMECHANGE events which the native + // control sends us when using wxDP_DROPDOWN style + if ( (m_date.IsValid() == dt.IsValid()) && + (!m_date.IsValid() || dt == m_date) ) + return false; + + m_date = dt; + wxDateEvent event(this, dt, wxEVT_DATE_CHANGED); + return HandleWindowEvent(event); } #endif // wxUSE_DATEPICKCTRL -