]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datectlg.cpp
remove empty dirs
[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
15c86b39 28#include "wx/datectrl.h"
7ae712f5
VZ
29
30// use this version if we're explicitly requested to do it or if it's the only
31// one we have
2a5e6376
VZ
32#if !defined(wxHAS_NATIVE_DATEPICKCTRL) || \
33 (defined(wxUSE_DATEPICKCTRL_GENERIC) && wxUSE_DATEPICKCTRL_GENERIC)
7ae712f5 34
a962d4e0 35#ifndef WX_PRECOMP
a962d4e0
KH
36 #include "wx/dialog.h"
37 #include "wx/dcmemory.h"
38 #include "wx/panel.h"
39 #include "wx/textctrl.h"
40 #include "wx/valtext.h"
41#endif
42
1721a8c0
VZ
43#ifdef wxHAS_NATIVE_DATEPICKCTRL
44 // this header is not included from wx/datectrl.h if we have a native
45 // version, but we do need it here
46 #include "wx/generic/datectrl.h"
930fb29e
VZ
47#else
48 // we need to define _WX_DEFINE_DATE_EVENTS_ before including wx/dateevt.h to
49 // define the event types we use if we're the only date picker control version
50 // being compiled -- otherwise it's defined in the native version implementation
7ae712f5
VZ
51 #define _WX_DEFINE_DATE_EVENTS_
52#endif
53
91edf16c
VZ
54#include "wx/dateevt.h"
55
4b134bb2 56#include "wx/calctrl.h"
85fa9d60 57#include "wx/combo.h"
39df3acd
VZ
58
59// ----------------------------------------------------------------------------
60// constants
61// ----------------------------------------------------------------------------
62
caad7637 63#if defined(__WXMSW__)
930fb29e 64 #define CALBORDER 0
930fb29e 65#else
930fb29e 66 #define CALBORDER 4
930fb29e
VZ
67#endif
68
aa74ad5b
VZ
69// ----------------------------------------------------------------------------
70// global variables
71// ----------------------------------------------------------------------------
72
73// this should have been a flag in wxDatePickerCtrlGeneric itself but adding it
74// there now would break backwards compatibility, so put it here as a global:
75// this shouldn't be a big problem as only one (GUI) thread normally can call
76// wxDatePickerCtrlGeneric::SetValue() and so it can be only ever used for one
77// control at a time
78//
79// if the value is not NULL, it points to the control which is inside SetValue()
80static wxDatePickerCtrlGeneric *gs_inSetValue = NULL;
930fb29e 81
1721a8c0
VZ
82// ----------------------------------------------------------------------------
83// local classes
84// ----------------------------------------------------------------------------
85
85fa9d60
VZ
86class wxCalendarComboPopup : public wxCalendarCtrl,
87 public wxComboPopup
38511687
VZ
88{
89public:
38511687 90
85fa9d60
VZ
91 wxCalendarComboPopup() : wxCalendarCtrl(),
92 wxComboPopup()
caad7637 93 {
caad7637
JS
94 }
95
85fa9d60
VZ
96 virtual void Init()
97 {
98 }
caad7637 99
85fa9d60
VZ
100 // NB: Don't create lazily since it didn't work that way before
101 // wxComboCtrl was used, and changing behaviour would almost
102 // certainly introduce new bugs.
103 virtual bool Create(wxWindow* parent)
104 {
105 if ( !wxCalendarCtrl::Create(parent, wxID_ANY, wxDefaultDateTime,
106 wxPoint(0, 0), wxDefaultSize,
107 wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) )
108 return false;
caad7637 109
85fa9d60 110 wxWindow *yearControl = wxCalendarCtrl::GetYearControl();
caad7637 111
85fa9d60
VZ
112 wxClientDC dc(yearControl);
113 dc.SetFont(yearControl->GetFont());
114 wxCoord width, dummy;
115 dc.GetTextExtent(wxT("2000"), &width, &dummy);
116 width += ConvertDialogToPixels(wxSize(20, 0)).x;
caad7637 117
85fa9d60
VZ
118 wxSize calSize = wxCalendarCtrl::GetBestSize();
119 wxSize yearSize = yearControl->GetSize();
120 yearSize.x = width;
caad7637 121
85fa9d60 122 wxPoint yearPosition = yearControl->GetPosition();
caad7637 123
85fa9d60 124 SetFormat(wxT("%x"));
caad7637 125
85fa9d60
VZ
126 width = yearPosition.x + yearSize.x+2+CALBORDER/2;
127 if (width < calSize.x-4)
128 width = calSize.x-4;
caad7637 129
85fa9d60
VZ
130 int calPos = (width-calSize.x)/2;
131 if (calPos == -1)
132 {
133 calPos = 0;
134 width += 2;
135 }
136 wxCalendarCtrl::SetSize(calPos, 0, calSize.x, calSize.y);
137 yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y,
138 yearSize.x, yearSize.y);
139 wxCalendarCtrl::GetMonthControl()->Move(0, 0);
caad7637 140
85fa9d60
VZ
141 m_useSize.x = width+CALBORDER/2;
142 m_useSize.y = calSize.y-2+CALBORDER;
caad7637 143
85fa9d60
VZ
144 wxWindow* tx = m_combo->GetTextCtrl();
145 if ( !tx )
146 tx = m_combo;
caad7637 147
85fa9d60
VZ
148 tx->Connect(wxEVT_KILL_FOCUS,
149 wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus),
150 NULL, this);
caad7637 151
85fa9d60
VZ
152 return true;
153 }
38511687 154
85fa9d60
VZ
155 virtual wxSize GetAdjustedSize(int WXUNUSED(minWidth),
156 int WXUNUSED(prefHeight),
157 int WXUNUSED(maxHeight))
158 {
159 return m_useSize;
160 }
38511687 161
85fa9d60 162 virtual wxWindow *GetControl() { return this; }
930fb29e 163
85fa9d60
VZ
164 void SetDateValue(const wxDateTime& date)
165 {
166 if ( date.IsValid() )
167 {
168 m_combo->SetText(date.Format(m_format));
169 }
170 else // invalid date
171 {
172 wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE),
173 _T("this control must have a valid date") );
caad7637 174
85fa9d60
VZ
175 m_combo->SetText(wxEmptyString);
176 }
38511687 177
85fa9d60
VZ
178 m_currentDate = date;
179 }
38511687 180
85fa9d60
VZ
181 const wxDateTime& GetDateValue() const
182 {
183 return m_currentDate;
184 }
94ab4d92 185
85fa9d60
VZ
186 bool ParseDateTime(const wxString& s, wxDateTime* pDt)
187 {
188 wxASSERT(pDt);
38511687 189
85fa9d60
VZ
190 if ( !s.empty() )
191 {
192 pDt->ParseFormat(s, m_format);
193 if ( !pDt->IsValid() )
194 return false;
195 }
38511687 196
85fa9d60
VZ
197 return true;
198 }
38511687 199
85fa9d60
VZ
200 void SendDateEvent(const wxDateTime& dt)
201 {
202 //
203 // Sends both wxCalendarEvent and wxDateEvent
204 wxWindow* datePicker = m_combo->GetParent();
38511687 205
85fa9d60
VZ
206 wxCalendarEvent cev((wxCalendarCtrl*) this, wxEVT_CALENDAR_SEL_CHANGED);
207 cev.SetEventObject(datePicker);
208 cev.SetId(datePicker->GetId());
209 cev.SetDate(dt);
210 GetParent()->ProcessEvent(cev);
38511687 211
85fa9d60
VZ
212 wxDateEvent event(datePicker, dt, wxEVT_DATE_CHANGED);
213 datePicker->GetParent()->ProcessEvent(event);
214 }
caad7637 215
85fa9d60 216private:
caad7637 217
85fa9d60 218 void OnCalKey(wxKeyEvent & ev)
caad7637 219 {
85fa9d60
VZ
220 if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
221 Dismiss();
222 else
223 ev.Skip();
caad7637 224 }
caad7637 225
85fa9d60
VZ
226 void OnSelChange(wxCalendarEvent &ev)
227 {
228 m_currentDate = wxCalendarCtrl::GetDate();
229 m_combo->SetText(m_currentDate.Format(m_format));
caad7637 230
85fa9d60
VZ
231 if ( ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED )
232 {
233 Dismiss();
234 }
caad7637 235
85fa9d60 236 SendDateEvent(m_currentDate);
38511687
VZ
237 }
238
85fa9d60
VZ
239 void OnKillTextFocus(wxFocusEvent &ev)
240 {
241 ev.Skip();
caad7637 242
85fa9d60
VZ
243 wxDateTime dt;
244 wxString value = m_combo->GetValue();
245 if ( !ParseDateTime(value, &dt) )
246 {
247 if ( !HasDPFlag(wxDP_ALLOWNONE) )
248 dt = m_currentDate;
249 }
caad7637 250
85fa9d60
VZ
251 if ( dt.IsValid() )
252 m_combo->SetText(dt.Format(m_format));
253 else
254 m_combo->SetText(wxEmptyString);
38511687 255
85fa9d60
VZ
256 // notify that we had to change the date after validation
257 if ( (dt.IsValid() && (!m_currentDate.IsValid() || m_currentDate != dt)) ||
258 (!dt.IsValid() && m_currentDate.IsValid()) )
259 {
260 m_currentDate = dt;
261 SendDateEvent(dt);
262 }
263 }
38511687 264
85fa9d60 265 bool HasDPFlag(int flag)
caad7637 266 {
85fa9d60 267 return m_combo->GetParent()->HasFlag(flag);
caad7637 268 }
caad7637 269
85fa9d60
VZ
270 bool SetFormat(const wxChar *fmt)
271 {
272 m_format.clear();
caad7637 273
85fa9d60
VZ
274 wxDateTime dt;
275 dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
276 wxString str(dt.Format(fmt));
1721a8c0 277
85fa9d60
VZ
278 const wxChar *p = str.c_str();
279 while ( *p )
280 {
281 int n=wxAtoi(p);
282 if (n == dt.GetDay())
283 {
284 m_format.Append(wxT("%d"));
285 p += 2;
286 }
287 else if (n == (int)dt.GetMonth()+1)
288 {
289 m_format.Append(wxT("%m"));
290 p += 2;
291 }
292 else if (n == dt.GetYear())
293 {
294 m_format.Append(wxT("%Y"));
295 p += 4;
296 }
297 else if (n == (dt.GetYear() % 100))
298 {
299 if ( HasDPFlag(wxDP_SHOWCENTURY) )
300 m_format.Append(wxT("%Y"));
301 else
302 m_format.Append(wxT("%y"));
303 p += 2;
304 }
305 else
306 m_format.Append(*p++);
307 }
1721a8c0 308
85fa9d60
VZ
309 if ( m_combo )
310 {
311 wxArrayString allowedChars;
312 for ( wxChar c = _T('0'); c <= _T('9'); c++ )
313 allowedChars.Add(wxString(c, 1));
314
315 const wxChar *p2 = m_format.c_str();
316 while ( *p2 )
317 {
318 if ( *p2 == '%')
319 p2 += 2;
320 else
321 allowedChars.Add(wxString(*p2++, 1));
322 }
323
324 #if wxUSE_VALIDATORS
325 wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
326 tv.SetIncludes(allowedChars);
327 m_combo->SetValidator(tv);
328 #endif
329
330 if (m_currentDate.IsValid())
331 m_combo->SetText(m_currentDate.Format(m_format));
332 }
1721a8c0 333
85fa9d60 334 return true;
1721a8c0
VZ
335 }
336
85fa9d60 337 virtual void SetStringValue(const wxString& s)
1721a8c0 338 {
85fa9d60
VZ
339 wxDateTime dt;
340 if ( ParseDateTime(s, &dt) )
341 m_currentDate = dt;
342 else if ( HasDPFlag(wxDP_ALLOWNONE) )
343 m_currentDate = dt;
1721a8c0 344 }
1721a8c0 345
85fa9d60 346 virtual wxString GetStringValue() const
1721a8c0 347 {
85fa9d60
VZ
348 if ( !m_currentDate.IsValid() )
349 return wxEmptyString;
1721a8c0 350
85fa9d60 351 return m_currentDate.Format(m_format);
1721a8c0
VZ
352 }
353
85fa9d60
VZ
354private:
355
356 wxSize m_useSize;
357 wxString m_format;
358 wxDateTime m_currentDate;
359
360 DECLARE_EVENT_TABLE()
1721a8c0
VZ
361};
362
85fa9d60
VZ
363
364BEGIN_EVENT_TABLE(wxCalendarComboPopup, wxCalendarCtrl)
365 EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey)
366 EVT_CALENDAR_SEL_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange)
367 EVT_CALENDAR_DAY(wxID_ANY, wxCalendarComboPopup::OnSelChange)
368 EVT_CALENDAR_MONTH(wxID_ANY, wxCalendarComboPopup::OnSelChange)
369 EVT_CALENDAR_YEAR(wxID_ANY, wxCalendarComboPopup::OnSelChange)
370 EVT_CALENDAR(wxID_ANY, wxCalendarComboPopup::OnSelChange)
371END_EVENT_TABLE()
372
1721a8c0 373
39df3acd 374// ============================================================================
7ae712f5 375// wxDatePickerCtrlGeneric implementation
39df3acd
VZ
376// ============================================================================
377
7ae712f5 378BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase)
85fa9d60 379 EVT_TEXT(wxID_ANY, wxDatePickerCtrlGeneric::OnText)
caad7637 380 EVT_SIZE(wxDatePickerCtrlGeneric::OnSize)
39df3acd
VZ
381END_EVENT_TABLE()
382
b6292ff0 383#ifndef wxHAS_NATIVE_DATEPICKCTRL
94ab4d92 384 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
b6292ff0 385#endif
39df3acd
VZ
386
387// ----------------------------------------------------------------------------
388// creation
389// ----------------------------------------------------------------------------
390
7ae712f5
VZ
391bool wxDatePickerCtrlGeneric::Create(wxWindow *parent,
392 wxWindowID id,
393 const wxDateTime& date,
394 const wxPoint& pos,
395 const wxSize& size,
396 long style,
807f5038 397 const wxValidator& validator,
7ae712f5 398 const wxString& name)
39df3acd 399{
29c86948
VZ
400 wxASSERT_MSG( !(style & wxDP_SPIN),
401 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
402
39df3acd 403 if ( !wxControl::Create(parent, id, pos, size,
85fa9d60 404 style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxBORDER_NONE,
807f5038 405 validator, name) )
39df3acd
VZ
406 {
407 return false;
408 }
409
39df3acd
VZ
410 InheritAttributes();
411
85fa9d60
VZ
412 m_combo = new wxComboCtrl(this, -1, wxEmptyString,
413 wxDefaultPosition, wxDefaultSize);
39df3acd 414
85fa9d60 415 m_popup = new wxCalendarComboPopup();
39df3acd 416
85fa9d60 417 m_combo->SetPopupControl(m_popup);
39df3acd 418
85fa9d60 419 m_cal = m_popup;
39df3acd 420
85fa9d60 421 m_popup->SetDateValue(date.IsValid() ? date : wxDateTime::Today());
1721a8c0 422
d8b49350 423 SetBestFittingSize(size);
930fb29e 424
3a0c6181 425 return true;
39df3acd
VZ
426}
427
428
7ae712f5 429void wxDatePickerCtrlGeneric::Init()
39df3acd 430{
85fa9d60 431 m_combo = NULL;
39df3acd 432 m_cal = NULL;
85fa9d60 433 m_popup = NULL;
39df3acd
VZ
434}
435
a9d13e15
JS
436wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric()
437{
a9d13e15 438}
39df3acd 439
7ae712f5 440bool wxDatePickerCtrlGeneric::Destroy()
39df3acd 441{
85fa9d60
VZ
442 if ( m_combo )
443 m_combo->Destroy();
39df3acd 444
85fa9d60 445 m_combo = NULL;
39df3acd 446 m_cal = NULL;
85fa9d60 447 m_popup = NULL;
39df3acd
VZ
448
449 return wxControl::Destroy();
450}
451
452// ----------------------------------------------------------------------------
453// overridden base class methods
454// ----------------------------------------------------------------------------
455
7ae712f5 456wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const
39df3acd 457{
85fa9d60 458 return m_combo->GetBestSize();
39df3acd
VZ
459}
460
461// ----------------------------------------------------------------------------
7ae712f5 462// wxDatePickerCtrlGeneric API
39df3acd
VZ
463// ----------------------------------------------------------------------------
464
4b134bb2 465bool
7ae712f5
VZ
466wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate,
467 const wxDateTime& upperdate)
4b134bb2
VZ
468{
469 return m_cal->SetDateRange(lowerdate, upperdate);
470}
471
39df3acd 472
7ae712f5 473wxDateTime wxDatePickerCtrlGeneric::GetValue() const
39df3acd 474{
85fa9d60 475 return m_popup->GetDateValue();
39df3acd
VZ
476}
477
478
7ae712f5 479void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date)
39df3acd 480{
85fa9d60 481 m_popup->SetDateValue(date);
39df3acd
VZ
482}
483
484
7ae712f5 485bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
39df3acd
VZ
486{
487 if (dt1)
4b134bb2 488 *dt1 = m_cal->GetLowerDateLimit();
40a33c46 489 if (dt2)
4b134bb2 490 *dt2 = m_cal->GetUpperDateLimit();
39df3acd
VZ
491 return true;
492}
493
494
7ae712f5
VZ
495void
496wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
39df3acd 497{
4b134bb2 498 m_cal->SetDateRange(dt1, dt2);
39df3acd
VZ
499}
500
501// ----------------------------------------------------------------------------
502// event handlers
503// ----------------------------------------------------------------------------
504
39df3acd 505
caad7637
JS
506void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent& event)
507{
85fa9d60
VZ
508 if ( m_combo )
509 m_combo->SetSize(GetClientSize());
caad7637
JS
510
511 event.Skip();
512}
513
514
7ae712f5 515void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev)
39df3acd
VZ
516{
517 ev.SetEventObject(this);
518 ev.SetId(GetId());
519 GetParent()->ProcessEvent(ev);
520
521 // We'll create an additional event if the date is valid.
1721a8c0 522 // If the date isn't valid, the user's probably in the middle of typing
39df3acd 523 wxDateTime dt;
85fa9d60
VZ
524 if ( !m_popup->ParseDateTime(m_combo->GetValue(), &dt) )
525 return;
39df3acd 526
85fa9d60 527 m_popup->SendDateEvent(dt);
39df3acd
VZ
528}
529
530
7ae712f5
VZ
531#endif // wxUSE_DATEPICKCTRL_GENERIC
532
533#endif // wxUSE_DATEPICKCTRL
85fa9d60 534