+public:
+
+ wxCalendarComboPopup() : wxCalendarCtrl(),
+ wxComboPopup()
+ {
+ }
+
+ virtual void Init()
+ {
+ }
+
+ // NB: Don't create lazily since it didn't work that way before
+ // wxComboCtrl was used, and changing behaviour would almost
+ // certainly introduce new bugs.
+ virtual bool Create(wxWindow* parent)
+ {
+ if ( !wxCalendarCtrl::Create(parent, wxID_ANY, wxDefaultDateTime,
+ wxPoint(0, 0), wxDefaultSize,
+ wxCAL_SEQUENTIAL_MONTH_SELECTION
+ | wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) )
+ return false;
+
+ SetFormat(GetLocaleDateFormat());
+
+ m_useSize = wxCalendarCtrl::GetBestSize();
+
+ wxWindow* tx = m_combo->GetTextCtrl();
+ if ( !tx )
+ tx = m_combo;
+
+ tx->Connect(wxEVT_KILL_FOCUS,
+ wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus),
+ NULL, this);
+
+ return true;
+ }
+
+ virtual wxSize GetAdjustedSize(int WXUNUSED(minWidth),
+ int WXUNUSED(prefHeight),
+ int WXUNUSED(maxHeight))
+ {
+ return m_useSize;
+ }
+
+ virtual wxWindow *GetControl() { return this; }
+
+ void SetDateValue(const wxDateTime& date)
+ {
+ if ( date.IsValid() )
+ {
+ m_combo->SetText(date.Format(m_format));
+ SetDate(date);
+ }
+ else // invalid date
+ {
+ wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE),
+ wxT("this control must have a valid date") );
+
+ m_combo->SetText(wxEmptyString);
+ }
+ }
+
+ bool IsTextEmpty() const
+ {
+ return m_combo->GetTextCtrl()->IsEmpty();
+ }
+
+ bool ParseDateTime(const wxString& s, wxDateTime* pDt)
+ {
+ wxASSERT(pDt);
+
+ if ( !s.empty() )
+ {
+ pDt->ParseFormat(s, m_format);
+ if ( !pDt->IsValid() )
+ return false;
+ }
+
+ return true;
+ }
+
+ void SendDateEvent(const wxDateTime& dt)
+ {
+ // Sends both wxCalendarEvent and wxDateEvent
+ wxWindow* datePicker = m_combo->GetParent();
+
+ wxCalendarEvent cev(datePicker, dt, wxEVT_CALENDAR_SEL_CHANGED);
+ datePicker->GetEventHandler()->ProcessEvent(cev);
+
+ wxDateEvent event(datePicker, dt, wxEVT_DATE_CHANGED);
+ datePicker->GetEventHandler()->ProcessEvent(event);
+ }
+
+private:
+
+ void OnCalKey(wxKeyEvent & ev)
+ {
+ if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
+ Dismiss();
+ else
+ ev.Skip();
+ }
+
+ void OnSelChange(wxCalendarEvent &ev)
+ {
+ m_combo->SetText(GetDate().Format(m_format));
+
+ if ( ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED )
+ {
+ Dismiss();
+ }
+
+ SendDateEvent(GetDate());
+ }
+
+ void OnKillTextFocus(wxFocusEvent &ev)
+ {
+ ev.Skip();
+
+ const wxDateTime& dtOld = GetDate();
+
+ wxDateTime dt;
+ wxString value = m_combo->GetValue();
+ if ( !ParseDateTime(value, &dt) )
+ {
+ if ( !HasDPFlag(wxDP_ALLOWNONE) )
+ dt = dtOld;
+ }
+
+ m_combo->SetText(GetStringValueFor(dt));
+
+ if ( !dt.IsValid() && HasDPFlag(wxDP_ALLOWNONE) )
+ return;
+
+ // notify that we had to change the date after validation
+ if ( (dt.IsValid() && (!dtOld.IsValid() || dt != dtOld)) ||
+ (!dt.IsValid() && dtOld.IsValid()) )
+ {
+ SetDate(dt);
+ SendDateEvent(dt);
+ }
+ }
+
+ bool HasDPFlag(int flag) const
+ {
+ return m_combo->GetParent()->HasFlag(flag);
+ }
+
+ // Return the format to be used for the dates shown by the control. This
+ // functions honours wxDP_SHOWCENTURY flag.
+ wxString GetLocaleDateFormat() const
+ {
+#if wxUSE_INTL
+ wxString fmt = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT);
+ if ( HasDPFlag(wxDP_SHOWCENTURY) )
+ fmt.Replace("%y", "%Y");
+
+ return fmt;
+#else // !wxUSE_INTL
+ return wxT("x");
+#endif // wxUSE_INTL/!wxUSE_INTL
+ }
+
+ bool SetFormat(const wxString& fmt)
+ {
+ m_format = fmt;
+
+ if ( m_combo )
+ {
+ wxArrayString allowedChars;
+ for ( wxChar c = wxT('0'); c <= wxT('9'); c++ )
+ allowedChars.Add(wxString(c, 1));
+
+ const wxChar *p2 = m_format.c_str();
+ while ( *p2 )
+ {
+ if ( *p2 == '%')
+ p2 += 2;
+ else
+ allowedChars.Add(wxString(*p2++, 1));
+ }
+
+ #if wxUSE_VALIDATORS
+ wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
+ tv.SetIncludes(allowedChars);
+ m_combo->SetValidator(tv);
+ #endif
+
+ if ( GetDate().IsValid() )
+ m_combo->SetText(GetDate().Format(m_format));
+ }
+
+ return true;
+ }
+
+ virtual void SetStringValue(const wxString& s)
+ {
+ wxDateTime dt;
+ if ( !s.empty() && ParseDateTime(s, &dt) )
+ SetDate(dt);
+ //else: keep the old value
+ }
+
+ virtual wxString GetStringValue() const
+ {
+ return GetStringValueFor(GetDate());
+ }
+
+private:
+ // returns either the given date representation using the current format or
+ // an empty string if it's invalid
+ wxString GetStringValueFor(const wxDateTime& dt) const
+ {
+ wxString val;
+ if ( dt.IsValid() )
+ val = dt.Format(m_format);
+
+ return val;
+ }
+
+ wxSize m_useSize;
+ wxString m_format;
+
+ DECLARE_EVENT_TABLE()