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