+ wxWindow *yearControl = wxGenericCalendarCtrl::GetYearControl();
+
+ wxClientDC dc(yearControl);
+ dc.SetFont(yearControl->GetFont());
+ wxCoord width, dummy;
+ dc.GetTextExtent(wxT("2000"), &width, &dummy);
+ width += ConvertDialogToPixels(wxSize(20, 0)).x;
+
+ wxSize calSize = wxGenericCalendarCtrl::GetBestSize();
+ wxSize yearSize = yearControl->GetSize();
+ yearSize.x = width;
+
+ wxPoint yearPosition = yearControl->GetPosition();
+
+ SetFormat("%x");
+
+ width = yearPosition.x + yearSize.x+2+CALBORDER/2;
+ if (width < calSize.x-4)
+ width = calSize.x-4;
+
+ int calPos = (width-calSize.x)/2;
+ if (calPos == -1)
+ {
+ calPos = 0;
+ width += 2;
+ }
+ wxGenericCalendarCtrl::SetSize(calPos, 0, calSize.x, calSize.y);
+ yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y,
+ yearSize.x, yearSize.y);
+ wxGenericCalendarCtrl::GetMonthControl()->Move(0, 0);
+
+ m_useSize.x = width+CALBORDER/2;
+ m_useSize.y = calSize.y-2+CALBORDER;
+
+ 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));
+ }
+ else // invalid date
+ {
+ wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE),
+ _T("this control must have a valid date") );
+
+ m_combo->SetText(wxEmptyString);
+ }
+
+ SetDate(date);
+ }
+
+ bool ParseDateTime(const wxString& s, wxDateTime* pDt)
+ {
+ wxASSERT(pDt);
+
+ if ( !s.empty() )
+ {
+ pDt->ParseFormat(s.c_str(), 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));
+
+ // 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)
+ {
+ return m_combo->GetParent()->HasFlag(flag);
+ }
+
+ bool SetFormat(const wxString& fmt)
+ {
+ m_format.clear();
+
+ wxDateTime dt;
+ dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
+ wxString str(dt.Format(fmt));
+
+ const wxChar *p = str.c_str();
+ while ( *p )
+ {
+ int n=wxAtoi(p);
+ if (n == dt.GetDay())
+ {
+ m_format.Append(wxT("%d"));
+ p += 2;
+ }
+ else if (n == (int)dt.GetMonth()+1)
+ {
+ m_format.Append(wxT("%m"));
+ p += 2;
+ }
+ else if (n == dt.GetYear())
+ {
+ m_format.Append(wxT("%Y"));
+ p += 4;
+ }
+ else if (n == (dt.GetYear() % 100))
+ {
+ if ( HasDPFlag(wxDP_SHOWCENTURY) )
+ m_format.Append(wxT("%Y"));
+ else
+ m_format.Append(wxT("%y"));
+ p += 2;
+ }
+ else
+ m_format.Append(*p++);
+ }
+
+ if ( m_combo )
+ {
+ wxArrayString allowedChars;
+ for ( wxChar c = _T('0'); c <= _T('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)