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