]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datectlg.cpp
don't call OnData() if OnEnter() rejected the drag (#9634)
[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,
6c70323f 75 wxCAL_SEQUENTIAL_MONTH_SELECTION
c245a012 76 | wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) )
85fa9d60 77 return false;
caad7637 78
6c70323f 79 SetFormat(GetLocaleDateFormat());
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;
6c70323f 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
6c70323f 195 bool HasDPFlag(int flag) const
caad7637 196 {
85fa9d60 197 return m_combo->GetParent()->HasFlag(flag);
caad7637 198 }
caad7637 199
6c70323f
VZ
200 // it expands "%x" format and changes %y to %Y if wxDP_SHOWCENTURY flag
201 // is given. If the locale format can't be easily analyzed (e.g. when
202 // the month is given as a name, not number), "%x" is returned
203 wxString GetLocaleDateFormat() const
85fa9d60 204 {
6c70323f
VZ
205 wxString x_format(wxT("%x"));
206 wxString fmt;
207 int year_cnt = 0, month_cnt = 0, day_cnt = 0;
caad7637 208
85fa9d60 209 wxDateTime dt;
6c70323f
VZ
210 dt.ParseFormat(wxT("2003-10-17"), wxT("%Y-%m-%d"));
211 wxString str(dt.Format(x_format));
1721a8c0 212
85fa9d60
VZ
213 const wxChar *p = str.c_str();
214 while ( *p )
215 {
6c70323f 216 if (wxIsdigit(*p))
85fa9d60 217 {
6c70323f
VZ
218 int n=wxAtoi(p);
219 if (n == dt.GetDay())
220 {
221 fmt.Append(wxT("%d"));
222 day_cnt++;
223 p += 2;
224 }
225 else if (n == (int)dt.GetMonth()+1)
226 {
227 fmt.Append(wxT("%m"));
228 month_cnt++;
229 p += 2;
230 }
231 else if (n == dt.GetYear())
232 {
233 fmt.Append(wxT("%Y"));
234 year_cnt++;
235 p += 4;
236 }
237 else if (n == (dt.GetYear() % 100))
238 {
239 if ( HasDPFlag(wxDP_SHOWCENTURY) )
240 fmt.Append(wxT("%Y"));
241 else
242 fmt.Append(wxT("%y"));
243 year_cnt++;
244 p += 2;
245 }
85fa9d60 246 else
6c70323f
VZ
247 // this shouldn't happen
248 return x_format;
249 }
250 else {
251 fmt.Append(*p);
252 p++;
85fa9d60 253 }
85fa9d60 254 }
1721a8c0 255
6c70323f
VZ
256 if (year_cnt == 1 && month_cnt == 1 && day_cnt == 1)
257 return fmt;
258 else
259 return x_format;
260 }
261
262 bool SetFormat(const wxString& fmt)
263 {
264 m_format = fmt;
265
85fa9d60
VZ
266 if ( m_combo )
267 {
268 wxArrayString allowedChars;
269 for ( wxChar c = _T('0'); c <= _T('9'); c++ )
270 allowedChars.Add(wxString(c, 1));
271
272 const wxChar *p2 = m_format.c_str();
273 while ( *p2 )
274 {
275 if ( *p2 == '%')
276 p2 += 2;
277 else
278 allowedChars.Add(wxString(*p2++, 1));
279 }
280
281 #if wxUSE_VALIDATORS
282 wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
283 tv.SetIncludes(allowedChars);
284 m_combo->SetValidator(tv);
285 #endif
286
2fda1fe5
VZ
287 if ( GetDate().IsValid() )
288 m_combo->SetText(GetDate().Format(m_format));
85fa9d60 289 }
1721a8c0 290
85fa9d60 291 return true;
1721a8c0
VZ
292 }
293
85fa9d60 294 virtual void SetStringValue(const wxString& s)
1721a8c0 295 {
85fa9d60 296 wxDateTime dt;
d6781628 297 if ( !s.empty() && ParseDateTime(s, &dt) )
2fda1fe5 298 SetDate(dt);
d6781628 299 //else: keep the old value
1721a8c0 300 }
1721a8c0 301
85fa9d60 302 virtual wxString GetStringValue() const
1721a8c0 303 {
2fda1fe5 304 return GetStringValueFor(GetDate());
1721a8c0
VZ
305 }
306
85fa9d60 307private:
2fda1fe5
VZ
308 // returns either the given date representation using the current format or
309 // an empty string if it's invalid
310 wxString GetStringValueFor(const wxDateTime& dt) const
311 {
312 wxString val;
313 if ( dt.IsValid() )
314 val = dt.Format(m_format);
315
316 return val;
317 }
85fa9d60
VZ
318
319 wxSize m_useSize;
320 wxString m_format;
85fa9d60
VZ
321
322 DECLARE_EVENT_TABLE()
1721a8c0
VZ
323};
324
85fa9d60 325
c245a012 326BEGIN_EVENT_TABLE(wxCalendarComboPopup, wxCalendarCtrl)
85fa9d60
VZ
327 EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey)
328 EVT_CALENDAR_SEL_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange)
628e155d 329 EVT_CALENDAR_PAGE_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange)
85fa9d60
VZ
330 EVT_CALENDAR(wxID_ANY, wxCalendarComboPopup::OnSelChange)
331END_EVENT_TABLE()
332
1721a8c0 333
39df3acd 334// ============================================================================
7ae712f5 335// wxDatePickerCtrlGeneric implementation
39df3acd
VZ
336// ============================================================================
337
7ae712f5 338BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase)
85fa9d60 339 EVT_TEXT(wxID_ANY, wxDatePickerCtrlGeneric::OnText)
caad7637 340 EVT_SIZE(wxDatePickerCtrlGeneric::OnSize)
4427c0a3 341 EVT_SET_FOCUS(wxDatePickerCtrlGeneric::OnFocus)
39df3acd
VZ
342END_EVENT_TABLE()
343
b6292ff0 344#ifndef wxHAS_NATIVE_DATEPICKCTRL
94ab4d92 345 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
b6292ff0 346#endif
39df3acd
VZ
347
348// ----------------------------------------------------------------------------
349// creation
350// ----------------------------------------------------------------------------
351
7ae712f5
VZ
352bool wxDatePickerCtrlGeneric::Create(wxWindow *parent,
353 wxWindowID id,
354 const wxDateTime& date,
355 const wxPoint& pos,
356 const wxSize& size,
357 long style,
807f5038 358 const wxValidator& validator,
7ae712f5 359 const wxString& name)
39df3acd 360{
29c86948
VZ
361 wxASSERT_MSG( !(style & wxDP_SPIN),
362 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
363
39df3acd 364 if ( !wxControl::Create(parent, id, pos, size,
85fa9d60 365 style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxBORDER_NONE,
807f5038 366 validator, name) )
39df3acd
VZ
367 {
368 return false;
369 }
370
39df3acd
VZ
371 InheritAttributes();
372
85fa9d60
VZ
373 m_combo = new wxComboCtrl(this, -1, wxEmptyString,
374 wxDefaultPosition, wxDefaultSize);
39df3acd 375
4427c0a3
RR
376 m_combo->SetCtrlMainWnd(this);
377
85fa9d60 378 m_popup = new wxCalendarComboPopup();
39df3acd 379
06077aaf
VZ
380#if defined(__WXMSW__)
381 // without this keyboard navigation in month control doesn't work
382 m_combo->UseAltPopupWindow();
383#endif
85fa9d60 384 m_combo->SetPopupControl(m_popup);
39df3acd 385
85fa9d60 386 m_popup->SetDateValue(date.IsValid() ? date : wxDateTime::Today());
1721a8c0 387
170acdc9 388 SetInitialSize(size);
930fb29e 389
3a0c6181 390 return true;
39df3acd
VZ
391}
392
393
7ae712f5 394void wxDatePickerCtrlGeneric::Init()
39df3acd 395{
85fa9d60 396 m_combo = NULL;
85fa9d60 397 m_popup = NULL;
39df3acd
VZ
398}
399
a9d13e15
JS
400wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric()
401{
a9d13e15 402}
39df3acd 403
7ae712f5 404bool wxDatePickerCtrlGeneric::Destroy()
39df3acd 405{
85fa9d60
VZ
406 if ( m_combo )
407 m_combo->Destroy();
39df3acd 408
85fa9d60 409 m_combo = NULL;
85fa9d60 410 m_popup = NULL;
39df3acd
VZ
411
412 return wxControl::Destroy();
413}
414
415// ----------------------------------------------------------------------------
416// overridden base class methods
417// ----------------------------------------------------------------------------
418
7ae712f5 419wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const
39df3acd 420{
85fa9d60 421 return m_combo->GetBestSize();
39df3acd
VZ
422}
423
424// ----------------------------------------------------------------------------
7ae712f5 425// wxDatePickerCtrlGeneric API
39df3acd
VZ
426// ----------------------------------------------------------------------------
427
4b134bb2 428bool
7ae712f5
VZ
429wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate,
430 const wxDateTime& upperdate)
4b134bb2 431{
2fda1fe5 432 return m_popup->SetDateRange(lowerdate, upperdate);
4b134bb2
VZ
433}
434
39df3acd 435
7ae712f5 436wxDateTime wxDatePickerCtrlGeneric::GetValue() const
39df3acd 437{
2fda1fe5 438 return m_popup->GetDate();
39df3acd
VZ
439}
440
441
7ae712f5 442void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date)
39df3acd 443{
85fa9d60 444 m_popup->SetDateValue(date);
39df3acd
VZ
445}
446
447
7ae712f5 448bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
39df3acd 449{
c245a012 450 return m_popup->GetDateRange(dt1, dt2);
39df3acd
VZ
451}
452
453
7ae712f5
VZ
454void
455wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
39df3acd 456{
2fda1fe5
VZ
457 m_popup->SetDateRange(dt1, dt2);
458}
459
c245a012 460wxCalendarCtrl *wxDatePickerCtrlGeneric::GetCalendar() const
2fda1fe5
VZ
461{
462 return m_popup;
39df3acd
VZ
463}
464
465// ----------------------------------------------------------------------------
466// event handlers
467// ----------------------------------------------------------------------------
468
39df3acd 469
caad7637
JS
470void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent& event)
471{
85fa9d60
VZ
472 if ( m_combo )
473 m_combo->SetSize(GetClientSize());
caad7637
JS
474
475 event.Skip();
476}
477
478
7ae712f5 479void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev)
39df3acd
VZ
480{
481 ev.SetEventObject(this);
482 ev.SetId(GetId());
eafd76b0 483 GetParent()->GetEventHandler()->ProcessEvent(ev);
39df3acd
VZ
484
485 // We'll create an additional event if the date is valid.
1721a8c0 486 // If the date isn't valid, the user's probably in the middle of typing
39df3acd 487 wxDateTime dt;
b0fb790b 488 if ( !m_popup || !m_popup->ParseDateTime(m_combo->GetValue(), &dt) )
85fa9d60 489 return;
39df3acd 490
85fa9d60 491 m_popup->SendDateEvent(dt);
39df3acd
VZ
492}
493
494
4427c0a3
RR
495void wxDatePickerCtrlGeneric::OnFocus(wxFocusEvent& WXUNUSED(event))
496{
497 m_combo->SetFocus();
498}
499
500
7ae712f5 501#endif // wxUSE_DATEPICKCTRL
85fa9d60 502