]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datectlg.cpp
Forgot to free string after usage.
[wxWidgets.git] / src / generic / datectlg.cpp
CommitLineData
39df3acd 1/////////////////////////////////////////////////////////////////////////////
d5ae99f5 2// Name: generic/datectlg.cpp
39df3acd
VZ
3// Purpose: generic wxDatePickerCtrl 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
a962d4e0
KH
26#ifndef WX_PRECOMP
27 #include "wx/bmpbuttn.h"
28 #include "wx/dialog.h"
29 #include "wx/dcmemory.h"
30 #include "wx/panel.h"
31 #include "wx/textctrl.h"
32 #include "wx/valtext.h"
33#endif
34
91edf16c
VZ
35#define _WX_DEFINE_DATE_EVENTS_
36#include "wx/dateevt.h"
37
39df3acd 38#include "wx/datectrl.h"
4b134bb2 39#include "wx/calctrl.h"
39df3acd
VZ
40
41// ----------------------------------------------------------------------------
42// constants
43// ----------------------------------------------------------------------------
44
45enum
46{
47 CTRLID_TXT = 101,
4b134bb2
VZ
48 CTRLID_CAL,
49 CTRLID_BTN,
39df3acd
VZ
50 CTRLID_PAN
51};
52
53#ifndef DEFAULT_ITEM_WIDTH
54 #define DEFAULT_ITEM_WIDTH 100
55#endif
56
57// ============================================================================
58// wxDatePickerCtrl implementation
59// ============================================================================
60
61BEGIN_EVENT_TABLE(wxDatePickerCtrl, wxDatePickerCtrlBase)
62 EVT_BUTTON(CTRLID_BTN, wxDatePickerCtrl::OnClick)
63 EVT_TEXT(CTRLID_TXT, wxDatePickerCtrl::OnText)
64 EVT_CHILD_FOCUS(wxDatePickerCtrl::OnChildSetFocus)
65END_EVENT_TABLE()
66
67IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxDatePickerCtrlBase)
68
69// ----------------------------------------------------------------------------
70// creation
71// ----------------------------------------------------------------------------
72
73wxDatePickerCtrl::wxDatePickerCtrl(wxWindow *parent,
74 wxWindowID id,
75 const wxDateTime& date,
76 const wxPoint& pos,
77 const wxSize& size,
78 long style,
79 const wxString& name)
80{
81 Init();
82 Create(parent, id, date, pos, size, style, name);
83}
84
85
86bool wxDatePickerCtrl::Create(wxWindow *parent,
87 wxWindowID id,
88 const wxDateTime& date,
89 const wxPoint& pos,
90 const wxSize& size,
91 long style,
92 const wxString& name)
93{
29c86948
VZ
94 wxASSERT_MSG( !(style & wxDP_SPIN),
95 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
96
39df3acd
VZ
97 if ( !wxControl::Create(parent, id, pos, size,
98 style | wxCLIP_CHILDREN | wxWANTS_CHARS,
99 wxDefaultValidator, name) )
100
101 {
102 return false;
103 }
104
105 SetWindowStyle(style | wxWANTS_CHARS);
106 InheritAttributes();
107
108 wxBitmap bmp(8, 4);
109 {
110 wxMemoryDC dc;
111
112 dc.SelectObject(bmp);
113 dc.SetBrush(wxBrush(GetBackgroundColour()));
114 dc.SetPen(wxPen(GetBackgroundColour()));
115 dc.DrawRectangle(0,0, 8,4);
116
117 dc.SetBrush(wxBrush(GetForegroundColour()));
118 dc.SetPen(wxPen(GetForegroundColour()));
119 wxPoint pt[3] = { wxPoint(0,0), wxPoint(6,0), wxPoint(3,3) };
120 dc.DrawPolygon(3, pt);
121 dc.SelectObject(wxNullBitmap);
122 }
123
d5ae99f5 124 m_txt=new wxTextCtrl(this, CTRLID_TXT);
4b134bb2
VZ
125 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
126 (wxObjectEventFunction)&wxDatePickerCtrl::OnEditKey,
127 0, this);
128 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KILL_FOCUS,
129 (wxObjectEventFunction)&wxDatePickerCtrl::OnKillFocus,
130 0, this);
39df3acd
VZ
131
132 m_btn = new wxBitmapButton(this, CTRLID_BTN, bmp);
133
d5ae99f5
VZ
134 m_popup = new wxPopupWindow(this);
135 m_popup->SetFont(GetFont());
39df3acd 136
d5ae99f5 137 wxPanel *panel=new wxPanel(m_popup, CTRLID_PAN,
4b134bb2
VZ
138 wxPoint(0, 0), wxDefaultSize,
139 wxSUNKEN_BORDER);
140 m_cal = new wxCalendarCtrl(panel, CTRLID_CAL, wxDefaultDateTime,
141 wxPoint(0,0), wxDefaultSize,
142 wxCAL_SHOW_HOLIDAYS | wxSUNKEN_BORDER);
143 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_SEL_CHANGED,
144 (wxObjectEventFunction)&wxDatePickerCtrl::OnSelChange,
145 0, this);
146 m_cal->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
147 (wxObjectEventFunction)&wxDatePickerCtrl::OnCalKey,
148 0, this);
149 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DOUBLECLICKED,
150 (wxObjectEventFunction)&wxDatePickerCtrl::OnSelChange,
151 0, this);
152 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DAY_CHANGED,
153 (wxObjectEventFunction)&wxDatePickerCtrl::OnSelChange,
154 0, this);
155 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_MONTH_CHANGED,
156 (wxObjectEventFunction)&wxDatePickerCtrl::OnSelChange,
157 0, this);
158 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_YEAR_CHANGED,
159 (wxObjectEventFunction)&wxDatePickerCtrl::OnSelChange,
160 0, this);
39df3acd
VZ
161
162 wxWindow *yearControl = m_cal->GetYearControl();
163
4b134bb2
VZ
164 Connect(wxID_ANY, wxID_ANY, wxEVT_SET_FOCUS,
165 (wxObjectEventFunction)&wxDatePickerCtrl::OnSetFocus);
39df3acd
VZ
166
167 wxClientDC dc(yearControl);
168 dc.SetFont(m_font);
169 wxCoord width, dummy;
170 dc.GetTextExtent(wxT("2000"), &width, &dummy);
171 width += ConvertDialogToPixels(wxSize(20,0)).x;
172
173 wxSize calSize = m_cal->GetBestSize();
174 wxSize yearSize = yearControl->GetSize();
175 yearSize.x = width;
176
177 wxPoint yearPosition = yearControl->GetPosition();
178
d5ae99f5
VZ
179 SetFormat(wxT("%x"));
180
181 if (date.IsValid())
182 m_txt->SetValue(date.Format(m_format));
183
184
39df3acd
VZ
185#ifdef __WXMSW__
186#define CALBORDER 0
187#else
188#define CALBORDER 4
189#endif
190
191 width = yearPosition.x + yearSize.x+2+CALBORDER/2;
192 if (width < calSize.x-4)
193 width = calSize.x-4;
194
195 int calPos = (width-calSize.x)/2;
196 if (calPos == -1)
197 {
198 calPos = 0;
199 width += 2;
200 }
201 m_cal->SetSize(calPos, 0, calSize.x, calSize.y);
4b134bb2
VZ
202 yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y,
203 yearSize.x, yearSize.y);
39df3acd
VZ
204 m_cal->GetMonthControl()->Move(0, 0);
205
206
207
208 panel->SetClientSize(width+CALBORDER/2, calSize.y-2+CALBORDER);
d5ae99f5
VZ
209 m_popup->SetClientSize(panel->GetSize());
210 m_popup->Hide();
39df3acd
VZ
211
212 return TRUE;
213}
214
215
216void wxDatePickerCtrl::Init()
217{
d5ae99f5 218 m_popup = NULL;
39df3acd
VZ
219 m_txt = NULL;
220 m_cal = NULL;
221 m_btn = NULL;
222
223 m_dropped = false;
224 m_ignoreDrop = false;
225}
226
227
228bool wxDatePickerCtrl::Destroy()
229{
230 if (m_cal)
231 m_cal->Destroy();
d5ae99f5
VZ
232 if (m_popup)
233 m_popup->Destroy();
39df3acd
VZ
234 if (m_txt)
235 m_txt->Destroy();
236 if (m_btn)
237 m_btn->Destroy();
238
d5ae99f5 239 m_popup = NULL;
39df3acd
VZ
240 m_txt = NULL;
241 m_cal = NULL;
242 m_btn = NULL;
243
244 return wxControl::Destroy();
245}
246
247// ----------------------------------------------------------------------------
248// overridden base class methods
249// ----------------------------------------------------------------------------
250
251void wxDatePickerCtrl::DoMoveWindow(int x, int y, int w, int h)
252{
253 wxControl::DoMoveWindow(x, y, w, h);
254 wxSize bs=m_btn->GetBestSize();
255 int eh=m_txt->GetBestSize().y;
256
257 m_txt->SetSize(0, 0, w-bs.x-1, h > eh ? eh : h);
258 m_btn->SetSize(w - bs.x, 0, bs.x, h > bs.y ? bs.y : h);
259
260 if (m_dropped)
261 DropDown();
262}
263
264wxSize wxDatePickerCtrl::DoGetBestSize() const
265{
266 int bh=m_btn->GetBestSize().y;
267 int eh=m_txt->GetBestSize().y;
268 return wxSize(DEFAULT_ITEM_WIDTH, bh > eh ? bh : eh);
269}
270
271
272bool wxDatePickerCtrl::Show(bool show)
273{
274 if ( !wxControl::Show(show) )
275 {
276 return FALSE;
277 }
278
279 if (!show)
280 {
d5ae99f5 281 if (m_popup)
39df3acd 282 {
d5ae99f5 283 m_popup->Hide();
39df3acd
VZ
284 m_dropped = false;
285 }
286 }
287
288 return TRUE;
289}
290
291
292bool wxDatePickerCtrl::Enable(bool enable)
293{
294 if ( !wxControl::Enable(enable) )
295 {
296 return FALSE;
297 }
298
299 if (!enable)
300 {
301 if (m_cal)
302 m_cal->Hide();
303 }
304 if (m_btn)
305 m_btn->Enable(enable);
306 return TRUE;
307}
308
309// ----------------------------------------------------------------------------
310// wxDatePickerCtrl API
311// ----------------------------------------------------------------------------
312
4b134bb2
VZ
313bool
314wxDatePickerCtrl::SetDateRange(const wxDateTime& lowerdate,
315 const wxDateTime& upperdate)
316{
317 return m_cal->SetDateRange(lowerdate, upperdate);
318}
319
39df3acd
VZ
320bool wxDatePickerCtrl::SetFormat(const wxChar *fmt)
321{
d5ae99f5
VZ
322 wxString currentText;
323 wxDateTime currentDate;
324 if (m_txt)
325 {
326 currentText = m_txt->GetValue();
327 if (!currentText.IsEmpty())
328 currentDate.ParseFormat(currentText, m_format);
329 }
39df3acd
VZ
330 wxDateTime dt;
331 dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
332 wxString str=dt.Format(fmt);
333 wxChar *p=(wxChar*)str.c_str();
334
335 m_format=wxEmptyString;
336
337 while (*p)
338 {
339 int n=wxAtoi(p);
340 if (n == dt.GetDay())
341 {
342 m_format.Append(wxT("%d"));
343 p += 2;
344 }
345 else if (n == (int)dt.GetMonth()+1)
346 {
347 m_format.Append(wxT("%m"));
348 p += 2;
349 }
350 else if (n == dt.GetYear())
351 {
352 m_format.Append(wxT("%Y"));
353 p += 4;
354 }
d5ae99f5
VZ
355 else if (n == (dt.GetYear() % 100))
356 {
357 m_format.Append(wxT("%y"));
358 p += 2;
359 }
39df3acd
VZ
360 else
361 m_format.Append(*p++);
362 }
363
364 if (m_txt)
365 {
366 wxStringList valList;
367 wxChar c;
368 for (c='0'; c <= '9'; c++)
369 valList.Add(wxString(c, 1));
370 wxChar *p=(wxChar*)m_format.c_str();
371 while (*p)
372 {
373 if (*p == '%')
374 p += 2;
375 else
376 valList.Add(wxString(*p++, 1));
377 }
378 wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
379 tv.SetIncludeList(valList);
380
381 m_txt->SetValidator(tv);
d5ae99f5
VZ
382
383 if (!currentText.IsEmpty())
384 m_txt->SetValue(currentDate.Format(m_format));
39df3acd
VZ
385 }
386 return true;
387}
388
389
390wxDateTime wxDatePickerCtrl::GetValue() const
391{
392 wxDateTime dt;
393 wxString txt=m_txt->GetValue();
394
395 if (!txt.IsEmpty())
396 dt.ParseFormat(txt, m_format);
397
398 return dt;
399}
400
401
402void wxDatePickerCtrl::SetValue(const wxDateTime& date)
403{
404 if (m_cal)
405 {
406 if (date.IsValid())
d5ae99f5 407 m_txt->SetValue(date.Format(m_format));
39df3acd
VZ
408 else
409 m_txt->SetValue(wxEmptyString);
410 }
411}
412
413
414bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
415{
416 if (dt1)
4b134bb2 417 *dt1 = m_cal->GetLowerDateLimit();
39df3acd 418 if (dt1)
4b134bb2 419 *dt2 = m_cal->GetUpperDateLimit();
39df3acd
VZ
420 return true;
421}
422
423
424void wxDatePickerCtrl::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
425{
4b134bb2 426 m_cal->SetDateRange(dt1, dt2);
39df3acd
VZ
427}
428
429// ----------------------------------------------------------------------------
430// event handlers
431// ----------------------------------------------------------------------------
432
433void wxDatePickerCtrl::DropDown(bool down)
434{
d5ae99f5 435 if (m_popup)
39df3acd
VZ
436 {
437 if (down)
438 {
d5ae99f5
VZ
439 wxDateTime dt;
440 if (!m_txt->GetValue().IsEmpty())
39df3acd 441 dt.ParseFormat(m_txt->GetValue(), m_format);
d5ae99f5
VZ
442
443 if (dt.IsValid())
39df3acd 444 m_cal->SetDate(dt);
d5ae99f5
VZ
445 else
446 m_cal->SetDate(wxDateTime::Today());
39df3acd 447
d5ae99f5
VZ
448 wxPoint pos=GetParent()->ClientToScreen(GetPosition());
449 m_popup->Move(pos.x, pos.y + GetSize().y);
450 m_popup->Show();
39df3acd
VZ
451 m_dropped = true;
452 }
453 else
454 {
455 if (m_dropped)
d5ae99f5 456 m_popup->Hide();
39df3acd
VZ
457 m_dropped = false;
458 }
459 }
460}
461
462
463void wxDatePickerCtrl::OnChildSetFocus(wxChildFocusEvent &ev)
464{
465 ev.Skip();
466 m_ignoreDrop = false;
467
468 wxWindow *w=(wxWindow*)ev.GetEventObject();
469 while (w)
470 {
d5ae99f5 471 if (w == m_popup)
39df3acd
VZ
472 return;
473 w = w->GetParent();
474 }
475
476 if (m_dropped)
477 {
478 DropDown(false);
479 if (ev.GetEventObject() == m_btn)
480 m_ignoreDrop = true;
481 }
482}
483
484
485void wxDatePickerCtrl::OnClick(wxCommandEvent& event)
486{
487 if (m_ignoreDrop)
488 {
489 m_ignoreDrop = false;
490 m_txt->SetFocus();
491 }
492 else
493 {
494 DropDown();
495 m_cal->SetFocus();
496 }
497}
498
499
500void wxDatePickerCtrl::OnSetFocus(wxFocusEvent &ev)
501{
502 if (m_txt)
503 {
504 m_txt->SetFocus();
505 m_txt->SetSelection(0, 100);
506 }
507}
508
509
510void wxDatePickerCtrl::OnKillFocus(wxFocusEvent &ev)
511{
512 ev.Skip();
513
514 wxDateTime dt;
515 dt.ParseFormat(m_txt->GetValue(), m_format);
516 if (!dt.IsValid())
517 m_txt->SetValue(wxEmptyString);
518 else
519 m_txt->SetValue(dt.Format(m_format));
520}
521
522
523void wxDatePickerCtrl::OnSelChange(wxCalendarEvent &ev)
524{
525 if (m_cal)
526 {
d5ae99f5 527 m_txt->SetValue(m_cal->GetDate().Format(m_format));
39df3acd
VZ
528 if (ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED)
529 {
530 DropDown(false);
531 m_txt->SetFocus();
532 }
533 }
534 ev.SetEventObject(this);
535 ev.SetId(GetId());
536 GetParent()->ProcessEvent(ev);
537}
538
539
540void wxDatePickerCtrl::OnText(wxCommandEvent &ev)
541{
542 ev.SetEventObject(this);
543 ev.SetId(GetId());
544 GetParent()->ProcessEvent(ev);
545
546 // We'll create an additional event if the date is valid.
547 // If the date isn't valid, the user's probable in the middle of typing
548 wxString txt=m_txt->GetValue();
549 wxDateTime dt;
550 if (!txt.IsEmpty())
551 {
552 dt.ParseFormat(txt, m_format);
553 if (!dt.IsValid())
554 return;
555 }
556
557 wxCalendarEvent cev(m_cal, wxEVT_CALENDAR_SEL_CHANGED);
558 cev.SetEventObject(this);
559 cev.SetId(GetId());
560 cev.SetDate(dt);
561
562 GetParent()->ProcessEvent(cev);
563}
564
565
566void wxDatePickerCtrl::OnEditKey(wxKeyEvent & ev)
567{
568 if (ev.GetKeyCode() == WXK_DOWN && !ev.HasModifiers())
569 DropDown();
570 else
571 ev.Skip();
572}
573
574
575void wxDatePickerCtrl::OnCalKey(wxKeyEvent & ev)
576{
577 if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
578 DropDown(false);
579 else
580 ev.Skip();
581}
582