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