1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/datectlg.cpp
3 // Purpose: generic wxDatePickerCtrlGeneric implementation
4 // Author: Andreas Pflug
8 // Copyright: (c) 2005 Andreas Pflug <pgadmin@pse-consulting.de>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
26 #if wxUSE_DATEPICKCTRL
29 #include "wx/dialog.h"
30 #include "wx/dcmemory.h"
33 #include "wx/textctrl.h"
34 #include "wx/valtext.h"
37 #include "wx/datectrl.h"
38 #include "wx/generic/datectrl.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 class wxCalendarComboPopup
: public wxCalendarCtrl
,
60 wxCalendarComboPopup() : wxCalendarCtrl(),
69 // NB: Don't create lazily since it didn't work that way before
70 // wxComboCtrl was used, and changing behaviour would almost
71 // certainly introduce new bugs.
72 virtual bool Create(wxWindow
* parent
)
74 if ( !wxCalendarCtrl::Create(parent
, wxID_ANY
, wxDefaultDateTime
,
75 wxPoint(0, 0), wxDefaultSize
,
76 wxCAL_SEQUENTIAL_MONTH_SELECTION
77 | wxCAL_SHOW_HOLIDAYS
| wxBORDER_SUNKEN
) )
80 SetFormat(GetLocaleDateFormat());
82 m_useSize
= wxCalendarCtrl::GetBestSize();
84 wxWindow
* tx
= m_combo
->GetTextCtrl();
88 tx
->Connect(wxEVT_KILL_FOCUS
,
89 wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus
),
95 virtual wxSize
GetAdjustedSize(int WXUNUSED(minWidth
),
96 int WXUNUSED(prefHeight
),
97 int WXUNUSED(maxHeight
))
102 virtual wxWindow
*GetControl() { return this; }
104 void SetDateValue(const wxDateTime
& date
)
106 if ( date
.IsValid() )
108 m_combo
->SetText(date
.Format(m_format
));
113 wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE
),
114 wxT("this control must have a valid date") );
116 m_combo
->SetText(wxEmptyString
);
120 bool IsTextEmpty() const
122 return m_combo
->GetTextCtrl()->IsEmpty();
125 bool ParseDateTime(const wxString
& s
, wxDateTime
* pDt
)
131 pDt
->ParseFormat(s
.c_str(), m_format
);
132 if ( !pDt
->IsValid() )
139 void SendDateEvent(const wxDateTime
& dt
)
141 // Sends both wxCalendarEvent and wxDateEvent
142 wxWindow
* datePicker
= m_combo
->GetParent();
144 wxCalendarEvent
cev(datePicker
, dt
, wxEVT_CALENDAR_SEL_CHANGED
);
145 datePicker
->GetEventHandler()->ProcessEvent(cev
);
147 wxDateEvent
event(datePicker
, dt
, wxEVT_DATE_CHANGED
);
148 datePicker
->GetEventHandler()->ProcessEvent(event
);
153 void OnCalKey(wxKeyEvent
& ev
)
155 if (ev
.GetKeyCode() == WXK_ESCAPE
&& !ev
.HasModifiers())
161 void OnSelChange(wxCalendarEvent
&ev
)
163 m_combo
->SetText(GetDate().Format(m_format
));
165 if ( ev
.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED
)
170 SendDateEvent(GetDate());
173 void OnKillTextFocus(wxFocusEvent
&ev
)
177 const wxDateTime
& dtOld
= GetDate();
180 wxString value
= m_combo
->GetValue();
181 if ( !ParseDateTime(value
, &dt
) )
183 if ( !HasDPFlag(wxDP_ALLOWNONE
) )
187 m_combo
->SetText(GetStringValueFor(dt
));
189 if ( !dt
.IsValid() && HasDPFlag(wxDP_ALLOWNONE
) )
192 // notify that we had to change the date after validation
193 if ( (dt
.IsValid() && (!dtOld
.IsValid() || dt
!= dtOld
)) ||
194 (!dt
.IsValid() && dtOld
.IsValid()) )
201 bool HasDPFlag(int flag
) const
203 return m_combo
->GetParent()->HasFlag(flag
);
206 // Return the format to be used for the dates shown by the control. This
207 // functions honours wxDP_SHOWCENTURY flag.
208 wxString
GetLocaleDateFormat() const
210 wxString fmt
= wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT
);
211 if ( HasDPFlag(wxDP_SHOWCENTURY
) )
212 fmt
.Replace("%y", "%Y");
217 bool SetFormat(const wxString
& fmt
)
223 wxArrayString allowedChars
;
224 for ( wxChar c
= wxT('0'); c
<= wxT('9'); c
++ )
225 allowedChars
.Add(wxString(c
, 1));
227 const wxChar
*p2
= m_format
.c_str();
233 allowedChars
.Add(wxString(*p2
++, 1));
237 wxTextValidator
tv(wxFILTER_INCLUDE_CHAR_LIST
);
238 tv
.SetIncludes(allowedChars
);
239 m_combo
->SetValidator(tv
);
242 if ( GetDate().IsValid() )
243 m_combo
->SetText(GetDate().Format(m_format
));
249 virtual void SetStringValue(const wxString
& s
)
252 if ( !s
.empty() && ParseDateTime(s
, &dt
) )
254 //else: keep the old value
257 virtual wxString
GetStringValue() const
259 return GetStringValueFor(GetDate());
263 // returns either the given date representation using the current format or
264 // an empty string if it's invalid
265 wxString
GetStringValueFor(const wxDateTime
& dt
) const
269 val
= dt
.Format(m_format
);
277 DECLARE_EVENT_TABLE()
281 BEGIN_EVENT_TABLE(wxCalendarComboPopup
, wxCalendarCtrl
)
282 EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey
)
283 EVT_CALENDAR_SEL_CHANGED(wxID_ANY
, wxCalendarComboPopup::OnSelChange
)
284 EVT_CALENDAR_PAGE_CHANGED(wxID_ANY
, wxCalendarComboPopup::OnSelChange
)
285 EVT_CALENDAR(wxID_ANY
, wxCalendarComboPopup::OnSelChange
)
289 // ============================================================================
290 // wxDatePickerCtrlGeneric implementation
291 // ============================================================================
293 BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric
, wxDatePickerCtrlBase
)
294 EVT_TEXT(wxID_ANY
, wxDatePickerCtrlGeneric::OnText
)
295 EVT_SIZE(wxDatePickerCtrlGeneric::OnSize
)
296 EVT_SET_FOCUS(wxDatePickerCtrlGeneric::OnFocus
)
299 #ifndef wxHAS_NATIVE_DATEPICKCTRL
300 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl
, wxControl
)
303 // ----------------------------------------------------------------------------
305 // ----------------------------------------------------------------------------
307 bool wxDatePickerCtrlGeneric::Create(wxWindow
*parent
,
309 const wxDateTime
& date
,
313 const wxValidator
& validator
,
314 const wxString
& name
)
316 wxASSERT_MSG( !(style
& wxDP_SPIN
),
317 wxT("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
319 if ( !wxControl::Create(parent
, id
, pos
, size
,
320 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
| wxBORDER_NONE
,
328 m_combo
= new wxComboCtrl(this, -1, wxEmptyString
,
329 wxDefaultPosition
, wxDefaultSize
);
331 m_combo
->SetCtrlMainWnd(this);
333 m_popup
= new wxCalendarComboPopup();
335 #if defined(__WXMSW__)
336 // without this keyboard navigation in month control doesn't work
337 m_combo
->UseAltPopupWindow();
339 m_combo
->SetPopupControl(m_popup
);
341 m_popup
->SetDateValue(date
.IsValid() ? date
: wxDateTime::Today());
343 SetInitialSize(size
);
349 void wxDatePickerCtrlGeneric::Init()
355 wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric()
359 bool wxDatePickerCtrlGeneric::Destroy()
367 return wxControl::Destroy();
370 // ----------------------------------------------------------------------------
371 // overridden base class methods
372 // ----------------------------------------------------------------------------
374 wxSize
wxDatePickerCtrlGeneric::DoGetBestSize() const
376 return m_combo
->GetBestSize();
379 // ----------------------------------------------------------------------------
380 // wxDatePickerCtrlGeneric API
381 // ----------------------------------------------------------------------------
384 wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime
& lowerdate
,
385 const wxDateTime
& upperdate
)
387 return m_popup
->SetDateRange(lowerdate
, upperdate
);
391 wxDateTime
wxDatePickerCtrlGeneric::GetValue() const
393 if ( HasFlag(wxDP_ALLOWNONE
) && m_popup
->IsTextEmpty() )
394 return wxInvalidDateTime
;
395 return m_popup
->GetDate();
399 void wxDatePickerCtrlGeneric::SetValue(const wxDateTime
& date
)
401 m_popup
->SetDateValue(date
);
405 bool wxDatePickerCtrlGeneric::GetRange(wxDateTime
*dt1
, wxDateTime
*dt2
) const
407 return m_popup
->GetDateRange(dt1
, dt2
);
412 wxDatePickerCtrlGeneric::SetRange(const wxDateTime
&dt1
, const wxDateTime
&dt2
)
414 m_popup
->SetDateRange(dt1
, dt2
);
417 wxCalendarCtrl
*wxDatePickerCtrlGeneric::GetCalendar() const
422 // ----------------------------------------------------------------------------
424 // ----------------------------------------------------------------------------
427 void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent
& event
)
430 m_combo
->SetSize(GetClientSize());
436 void wxDatePickerCtrlGeneric::OnText(wxCommandEvent
&ev
)
438 ev
.SetEventObject(this);
440 GetParent()->GetEventHandler()->ProcessEvent(ev
);
442 // We'll create an additional event if the date is valid.
443 // If the date isn't valid, the user's probably in the middle of typing
445 if ( !m_popup
|| !m_popup
->ParseDateTime(m_combo
->GetValue(), &dt
) )
448 m_popup
->SendDateEvent(dt
);
452 void wxDatePickerCtrlGeneric::OnFocus(wxFocusEvent
& WXUNUSED(event
))
458 #endif // wxUSE_DATEPICKCTRL