]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datectlg.cpp
allow creating items without parent menus (#3425)
[wxWidgets.git] / src / generic / datectlg.cpp
CommitLineData
39df3acd 1/////////////////////////////////////////////////////////////////////////////
68f2155b 2// Name: src/generic/datectlg.cpp
7ae712f5 3// Purpose: generic wxDatePickerCtrlGeneric implementation
39df3acd
VZ
4// Author: Andreas Pflug
5// Modified by:
6// Created: 2005-01-19
7// RCS-ID: $Id$
8// Copyright: (c) 2005 Andreas Pflug <pgadmin@pse-consulting.de>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
7ae712f5
VZ
26#if wxUSE_DATEPICKCTRL
27
a962d4e0 28#ifndef WX_PRECOMP
a962d4e0
KH
29 #include "wx/dialog.h"
30 #include "wx/dcmemory.h"
31 #include "wx/panel.h"
32 #include "wx/textctrl.h"
33 #include "wx/valtext.h"
34#endif
35
c245a012
VZ
36#include "wx/datectrl.h"
37#include "wx/generic/datectrl.h"
91edf16c 38
39df3acd
VZ
39
40// ----------------------------------------------------------------------------
41// constants
42// ----------------------------------------------------------------------------
43
930fb29e 44
aa74ad5b
VZ
45// ----------------------------------------------------------------------------
46// global variables
47// ----------------------------------------------------------------------------
48
930fb29e 49
1721a8c0
VZ
50// ----------------------------------------------------------------------------
51// local classes
52// ----------------------------------------------------------------------------
53
c245a012 54class wxCalendarComboPopup : public wxCalendarCtrl,
85fa9d60 55 public wxComboPopup
38511687
VZ
56{
57public:
38511687 58
c245a012 59 wxCalendarComboPopup() : wxCalendarCtrl(),
85fa9d60 60 wxComboPopup()
caad7637 61 {
caad7637
JS
62 }
63
85fa9d60
VZ
64 virtual void Init()
65 {
66 }
caad7637 67
85fa9d60
VZ
68 // NB: Don't create lazily since it didn't work that way before
69 // wxComboCtrl was used, and changing behaviour would almost
70 // certainly introduce new bugs.
71 virtual bool Create(wxWindow* parent)
72 {
c245a012 73 if ( !wxCalendarCtrl::Create(parent, wxID_ANY, wxDefaultDateTime,
85fa9d60 74 wxPoint(0, 0), wxDefaultSize,
c245a012
VZ
75 wxCAL_SEQUENTIAL_MONTH_SELECTION
76 | wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) )
85fa9d60 77 return false;
caad7637 78
330e8ab9 79 SetFormat("%x");
caad7637 80
c245a012 81 m_useSize = wxCalendarCtrl::GetBestSize();
caad7637 82
85fa9d60
VZ
83 wxWindow* tx = m_combo->GetTextCtrl();
84 if ( !tx )
85 tx = m_combo;
caad7637 86
85fa9d60
VZ
87 tx->Connect(wxEVT_KILL_FOCUS,
88 wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus),
89 NULL, this);
caad7637 90
85fa9d60
VZ
91 return true;
92 }
38511687 93
85fa9d60
VZ
94 virtual wxSize GetAdjustedSize(int WXUNUSED(minWidth),
95 int WXUNUSED(prefHeight),
96 int WXUNUSED(maxHeight))
97 {
98 return m_useSize;
99 }
38511687 100
85fa9d60 101 virtual wxWindow *GetControl() { return this; }
930fb29e 102
85fa9d60
VZ
103 void SetDateValue(const wxDateTime& date)
104 {
105 if ( date.IsValid() )
106 {
107 m_combo->SetText(date.Format(m_format));
d6781628 108 SetDate(date);
85fa9d60
VZ
109 }
110 else // invalid date
111 {
112 wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE),
113 _T("this control must have a valid date") );
caad7637 114
85fa9d60
VZ
115 m_combo->SetText(wxEmptyString);
116 }
85fa9d60 117 }
94ab4d92 118
85fa9d60
VZ
119 bool ParseDateTime(const wxString& s, wxDateTime* pDt)
120 {
121 wxASSERT(pDt);
38511687 122
85fa9d60
VZ
123 if ( !s.empty() )
124 {
e0a050e3 125 pDt->ParseFormat(s.c_str(), m_format);
85fa9d60
VZ
126 if ( !pDt->IsValid() )
127 return false;
128 }
38511687 129
85fa9d60
VZ
130 return true;
131 }
38511687 132
85fa9d60
VZ
133 void SendDateEvent(const wxDateTime& dt)
134 {
85fa9d60
VZ
135 // Sends both wxCalendarEvent and wxDateEvent
136 wxWindow* datePicker = m_combo->GetParent();
38511687 137
628e155d 138 wxCalendarEvent cev(datePicker, dt, wxEVT_CALENDAR_SEL_CHANGED);
d1b736b7 139 datePicker->GetEventHandler()->ProcessEvent(cev);
38511687 140
85fa9d60 141 wxDateEvent event(datePicker, dt, wxEVT_DATE_CHANGED);
d1b736b7 142 datePicker->GetEventHandler()->ProcessEvent(event);
85fa9d60 143 }
caad7637 144
85fa9d60 145private:
caad7637 146
85fa9d60 147 void OnCalKey(wxKeyEvent & ev)
caad7637 148 {
85fa9d60
VZ
149 if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
150 Dismiss();
151 else
152 ev.Skip();
caad7637 153 }
caad7637 154
85fa9d60
VZ
155 void OnSelChange(wxCalendarEvent &ev)
156 {
2fda1fe5 157 m_combo->SetText(GetDate().Format(m_format));
caad7637 158
85fa9d60
VZ
159 if ( ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED )
160 {
161 Dismiss();
162 }
caad7637 163
2fda1fe5 164 SendDateEvent(GetDate());
38511687
VZ
165 }
166
85fa9d60
VZ
167 void OnKillTextFocus(wxFocusEvent &ev)
168 {
169 ev.Skip();
caad7637 170
2fda1fe5
VZ
171 const wxDateTime& dtOld = GetDate();
172
85fa9d60
VZ
173 wxDateTime dt;
174 wxString value = m_combo->GetValue();
175 if ( !ParseDateTime(value, &dt) )
176 {
177 if ( !HasDPFlag(wxDP_ALLOWNONE) )
2fda1fe5 178 dt = dtOld;
85fa9d60 179 }
caad7637 180
2fda1fe5 181 m_combo->SetText(GetStringValueFor(dt));
38511687 182
d6781628
RD
183 if ( !dt.IsValid() && HasDPFlag(wxDP_ALLOWNONE) )
184 return;
185
85fa9d60 186 // notify that we had to change the date after validation
2fda1fe5
VZ
187 if ( (dt.IsValid() && (!dtOld.IsValid() || dt != dtOld)) ||
188 (!dt.IsValid() && dtOld.IsValid()) )
85fa9d60 189 {
2fda1fe5 190 SetDate(dt);
85fa9d60
VZ
191 SendDateEvent(dt);
192 }
193 }
38511687 194
85fa9d60 195 bool HasDPFlag(int flag)
caad7637 196 {
85fa9d60 197 return m_combo->GetParent()->HasFlag(flag);
caad7637 198 }
caad7637 199
330e8ab9 200 bool SetFormat(const wxString& fmt)
85fa9d60
VZ
201 {
202 m_format.clear();
caad7637 203
85fa9d60
VZ
204 wxDateTime dt;
205 dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
206 wxString str(dt.Format(fmt));
1721a8c0 207
85fa9d60
VZ
208 const wxChar *p = str.c_str();
209 while ( *p )
210 {
211 int n=wxAtoi(p);
212 if (n == dt.GetDay())
213 {
214 m_format.Append(wxT("%d"));
215 p += 2;
216 }
217 else if (n == (int)dt.GetMonth()+1)
218 {
219 m_format.Append(wxT("%m"));
220 p += 2;
221 }
222 else if (n == dt.GetYear())
223 {
224 m_format.Append(wxT("%Y"));
225 p += 4;
226 }
227 else if (n == (dt.GetYear() % 100))
228 {
229 if ( HasDPFlag(wxDP_SHOWCENTURY) )
230 m_format.Append(wxT("%Y"));
231 else
232 m_format.Append(wxT("%y"));
233 p += 2;
234 }
235 else
236 m_format.Append(*p++);
237 }
1721a8c0 238
85fa9d60
VZ
239 if ( m_combo )
240 {
241 wxArrayString allowedChars;
242 for ( wxChar c = _T('0'); c <= _T('9'); c++ )
243 allowedChars.Add(wxString(c, 1));
244
245 const wxChar *p2 = m_format.c_str();
246 while ( *p2 )
247 {
248 if ( *p2 == '%')
249 p2 += 2;
250 else
251 allowedChars.Add(wxString(*p2++, 1));
252 }
253
254 #if wxUSE_VALIDATORS
255 wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
256 tv.SetIncludes(allowedChars);
257 m_combo->SetValidator(tv);
258 #endif
259
2fda1fe5
VZ
260 if ( GetDate().IsValid() )
261 m_combo->SetText(GetDate().Format(m_format));
85fa9d60 262 }
1721a8c0 263
85fa9d60 264 return true;
1721a8c0
VZ
265 }
266
85fa9d60 267 virtual void SetStringValue(const wxString& s)
1721a8c0 268 {
85fa9d60 269 wxDateTime dt;
d6781628 270 if ( !s.empty() && ParseDateTime(s, &dt) )
2fda1fe5 271 SetDate(dt);
d6781628 272 //else: keep the old value
1721a8c0 273 }
1721a8c0 274
85fa9d60 275 virtual wxString GetStringValue() const
1721a8c0 276 {
2fda1fe5 277 return GetStringValueFor(GetDate());
1721a8c0
VZ
278 }
279
85fa9d60 280private:
2fda1fe5
VZ
281 // returns either the given date representation using the current format or
282 // an empty string if it's invalid
283 wxString GetStringValueFor(const wxDateTime& dt) const
284 {
285 wxString val;
286 if ( dt.IsValid() )
287 val = dt.Format(m_format);
288
289 return val;
290 }
85fa9d60
VZ
291
292 wxSize m_useSize;
293 wxString m_format;
85fa9d60
VZ
294
295 DECLARE_EVENT_TABLE()
1721a8c0
VZ
296};
297
85fa9d60 298
c245a012 299BEGIN_EVENT_TABLE(wxCalendarComboPopup, wxCalendarCtrl)
85fa9d60
VZ
300 EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey)
301 EVT_CALENDAR_SEL_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange)
628e155d 302 EVT_CALENDAR_PAGE_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange)
85fa9d60
VZ
303 EVT_CALENDAR(wxID_ANY, wxCalendarComboPopup::OnSelChange)
304END_EVENT_TABLE()
305
1721a8c0 306
39df3acd 307// ============================================================================
7ae712f5 308// wxDatePickerCtrlGeneric implementation
39df3acd
VZ
309// ============================================================================
310
7ae712f5 311BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase)
85fa9d60 312 EVT_TEXT(wxID_ANY, wxDatePickerCtrlGeneric::OnText)
caad7637 313 EVT_SIZE(wxDatePickerCtrlGeneric::OnSize)
4427c0a3 314 EVT_SET_FOCUS(wxDatePickerCtrlGeneric::OnFocus)
39df3acd
VZ
315END_EVENT_TABLE()
316
b6292ff0 317#ifndef wxHAS_NATIVE_DATEPICKCTRL
94ab4d92 318 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
b6292ff0 319#endif
39df3acd
VZ
320
321// ----------------------------------------------------------------------------
322// creation
323// ----------------------------------------------------------------------------
324
7ae712f5
VZ
325bool wxDatePickerCtrlGeneric::Create(wxWindow *parent,
326 wxWindowID id,
327 const wxDateTime& date,
328 const wxPoint& pos,
329 const wxSize& size,
330 long style,
807f5038 331 const wxValidator& validator,
7ae712f5 332 const wxString& name)
39df3acd 333{
29c86948
VZ
334 wxASSERT_MSG( !(style & wxDP_SPIN),
335 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
336
39df3acd 337 if ( !wxControl::Create(parent, id, pos, size,
85fa9d60 338 style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxBORDER_NONE,
807f5038 339 validator, name) )
39df3acd
VZ
340 {
341 return false;
342 }
343
39df3acd
VZ
344 InheritAttributes();
345
85fa9d60
VZ
346 m_combo = new wxComboCtrl(this, -1, wxEmptyString,
347 wxDefaultPosition, wxDefaultSize);
39df3acd 348
4427c0a3
RR
349 m_combo->SetCtrlMainWnd(this);
350
85fa9d60 351 m_popup = new wxCalendarComboPopup();
39df3acd 352
06077aaf
VZ
353#if defined(__WXMSW__)
354 // without this keyboard navigation in month control doesn't work
355 m_combo->UseAltPopupWindow();
356#endif
85fa9d60 357 m_combo->SetPopupControl(m_popup);
39df3acd 358
85fa9d60 359 m_popup->SetDateValue(date.IsValid() ? date : wxDateTime::Today());
1721a8c0 360
170acdc9 361 SetInitialSize(size);
930fb29e 362
3a0c6181 363 return true;
39df3acd
VZ
364}
365
366
7ae712f5 367void wxDatePickerCtrlGeneric::Init()
39df3acd 368{
85fa9d60 369 m_combo = NULL;
85fa9d60 370 m_popup = NULL;
39df3acd
VZ
371}
372
a9d13e15
JS
373wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric()
374{
a9d13e15 375}
39df3acd 376
7ae712f5 377bool wxDatePickerCtrlGeneric::Destroy()
39df3acd 378{
85fa9d60
VZ
379 if ( m_combo )
380 m_combo->Destroy();
39df3acd 381
85fa9d60 382 m_combo = NULL;
85fa9d60 383 m_popup = NULL;
39df3acd
VZ
384
385 return wxControl::Destroy();
386}
387
388// ----------------------------------------------------------------------------
389// overridden base class methods
390// ----------------------------------------------------------------------------
391
7ae712f5 392wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const
39df3acd 393{
85fa9d60 394 return m_combo->GetBestSize();
39df3acd
VZ
395}
396
397// ----------------------------------------------------------------------------
7ae712f5 398// wxDatePickerCtrlGeneric API
39df3acd
VZ
399// ----------------------------------------------------------------------------
400
4b134bb2 401bool
7ae712f5
VZ
402wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate,
403 const wxDateTime& upperdate)
4b134bb2 404{
2fda1fe5 405 return m_popup->SetDateRange(lowerdate, upperdate);
4b134bb2
VZ
406}
407
39df3acd 408
7ae712f5 409wxDateTime wxDatePickerCtrlGeneric::GetValue() const
39df3acd 410{
2fda1fe5 411 return m_popup->GetDate();
39df3acd
VZ
412}
413
414
7ae712f5 415void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date)
39df3acd 416{
85fa9d60 417 m_popup->SetDateValue(date);
39df3acd
VZ
418}
419
420
7ae712f5 421bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
39df3acd 422{
c245a012 423 return m_popup->GetDateRange(dt1, dt2);
39df3acd
VZ
424}
425
426
7ae712f5
VZ
427void
428wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
39df3acd 429{
2fda1fe5
VZ
430 m_popup->SetDateRange(dt1, dt2);
431}
432
c245a012 433wxCalendarCtrl *wxDatePickerCtrlGeneric::GetCalendar() const
2fda1fe5
VZ
434{
435 return m_popup;
39df3acd
VZ
436}
437
438// ----------------------------------------------------------------------------
439// event handlers
440// ----------------------------------------------------------------------------
441
39df3acd 442
caad7637
JS
443void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent& event)
444{
85fa9d60
VZ
445 if ( m_combo )
446 m_combo->SetSize(GetClientSize());
caad7637
JS
447
448 event.Skip();
449}
450
451
7ae712f5 452void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev)
39df3acd
VZ
453{
454 ev.SetEventObject(this);
455 ev.SetId(GetId());
eafd76b0 456 GetParent()->GetEventHandler()->ProcessEvent(ev);
39df3acd
VZ
457
458 // We'll create an additional event if the date is valid.
1721a8c0 459 // If the date isn't valid, the user's probably in the middle of typing
39df3acd 460 wxDateTime dt;
b0fb790b 461 if ( !m_popup || !m_popup->ParseDateTime(m_combo->GetValue(), &dt) )
85fa9d60 462 return;
39df3acd 463
85fa9d60 464 m_popup->SendDateEvent(dt);
39df3acd
VZ
465}
466
467
4427c0a3
RR
468void wxDatePickerCtrlGeneric::OnFocus(wxFocusEvent& WXUNUSED(event))
469{
470 m_combo->SetFocus();
471}
472
473
7ae712f5 474#endif // wxUSE_DATEPICKCTRL
85fa9d60 475