Applied patch [ 1184295 ] wxDateTimePickerCtrl Create() fix for wxDP_ALLOWNONE
[wxWidgets.git] / src / msw / datectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/datectrl.cpp
3 // Purpose: wxDatePickerCtrl implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2005-01-09
7 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
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 #ifndef WX_PRECOMP
27 #endif
28
29 #if wxUSE_DATEPICKCTRL
30
31 #include "wx/datectrl.h"
32 #include "wx/app.h"
33 #include "wx/intl.h"
34 #include "wx/dynlib.h"
35
36 #define _WX_DEFINE_DATE_EVENTS_
37 #include "wx/dateevt.h"
38
39 #include "wx/msw/wrapwin.h"
40 #include "wx/msw/wrapcctl.h"
41 #include "wx/msw/private.h"
42
43 // apparently some versions of mingw define these macros erroneously
44 #ifndef DateTime_GetSystemtime
45 #define DateTime_GetSystemtime DateTime_GetSystemTime
46 #endif
47
48 #ifndef DateTime_SetSystemtime
49 #define DateTime_SetSystemtime DateTime_SetSystemTime
50 #endif
51
52 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
53
54 // ============================================================================
55 // implementation
56 // ============================================================================
57
58 // ----------------------------------------------------------------------------
59 // helpers for wxDateTime <-> SYSTEMTIME conversion
60 // ----------------------------------------------------------------------------
61
62 static inline void wxFromSystemTime(wxDateTime *dt, const SYSTEMTIME& st)
63 {
64 dt->Set(st.wDay,
65 wx_static_cast(wxDateTime::Month, wxDateTime::Jan + st.wMonth - 1),
66 st.wYear,
67 0, 0, 0);
68 }
69
70 static inline void wxToSystemTime(SYSTEMTIME *st, const wxDateTime& dt)
71 {
72 const wxDateTime::Tm tm(dt.GetTm());
73
74 st->wYear = (WXWORD)tm.year;
75 st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
76 st->wDay = tm.mday;
77
78 st->wDayOfWeek =
79 st->wHour =
80 st->wMinute =
81 st->wSecond =
82 st->wMilliseconds = 0;
83 }
84
85 // ----------------------------------------------------------------------------
86 // wxDatePickerCtrl creation
87 // ----------------------------------------------------------------------------
88
89 bool
90 wxDatePickerCtrl::Create(wxWindow *parent,
91 wxWindowID id,
92 const wxDateTime& dt,
93 const wxPoint& pos,
94 const wxSize& size,
95 long style,
96 const wxValidator& validator,
97 const wxString& name)
98 {
99 // although we already call InitCommonControls() in app.cpp which is
100 // supposed to initialize all common controls, in comctl32.dll 4.72 (and
101 // presumably earlier versions 4.70 and 4.71, date time picker not being
102 // supported in < 4.70 anyhow) it does not do it and we have to initialize
103 // it explicitely
104 static bool s_initDone = false; // MT-ok: used from GUI thread only
105 if ( !s_initDone )
106 {
107 if ( wxApp::GetComCtl32Version() < 470 )
108 {
109 wxLogError(_("This system doesn't support date picker control, please upgrade your version of comctl32.dll"));
110
111 return false;
112 }
113
114 INITCOMMONCONTROLSEX icex;
115 icex.dwSize = sizeof(icex);
116 icex.dwICC = ICC_DATE_CLASSES;
117
118 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
119
120 typedef BOOL (WINAPI *ICCEx_t)(INITCOMMONCONTROLSEX *);
121 wxDYNLIB_FUNCTION( ICCEx_t, InitCommonControlsEx, dllComCtl32 );
122
123 if ( pfnInitCommonControlsEx )
124 {
125 (*pfnInitCommonControlsEx)(&icex);
126 }
127
128 s_initDone = true;
129 }
130
131
132 // use wxDP_SPIN if wxDP_DEFAULT (0) was given as style
133 if ( !(style & wxDP_DROPDOWN) )
134 style |= wxDP_SPIN;
135
136 // initialize the base class
137 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
138 return false;
139
140 // create the native control
141 if ( !MSWCreateControl(DATETIMEPICK_CLASS, wxEmptyString, pos, size) )
142 return false;
143
144 if ( dt.IsValid() || (style & wxDP_ALLOWNONE) )
145 SetValue(dt);
146
147 return true;
148 }
149
150 WXDWORD wxDatePickerCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
151 {
152 WXDWORD styleMSW = wxDatePickerCtrlBase::MSWGetStyle(style, exstyle);
153
154 // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with
155 // comctl32.dll 4.72
156 if ( wxApp::GetComCtl32Version() > 472 && (style & wxDP_SPIN) )
157 styleMSW |= DTS_UPDOWN;
158 //else: drop down by default
159
160 #ifdef DTS_SHORTDATECENTURYFORMAT
161 if ( style & wxDP_SHOWCENTURY )
162 styleMSW |= DTS_SHORTDATECENTURYFORMAT;
163 else
164 #endif // DTS_SHORTDATECENTURYFORMAT
165 styleMSW |= DTS_SHORTDATEFORMAT;
166
167 if ( style & wxDP_ALLOWNONE )
168 styleMSW |= DTS_SHOWNONE;
169
170 return styleMSW;
171 }
172
173 // TODO: handle WM_WININICHANGE
174
175 // ----------------------------------------------------------------------------
176 // wxDatePickerCtrl geometry
177 // ----------------------------------------------------------------------------
178
179 wxSize wxDatePickerCtrl::DoGetBestSize() const
180 {
181 const int y = GetCharHeight();
182
183 return wxSize(DEFAULT_ITEM_WIDTH, EDIT_HEIGHT_FROM_CHAR_HEIGHT(y));
184 }
185
186 // ----------------------------------------------------------------------------
187 // wxDatePickerCtrl operations
188 // ----------------------------------------------------------------------------
189
190 void wxDatePickerCtrl::SetValue(const wxDateTime& dt)
191 {
192 wxCHECK_RET( dt.IsValid() || HasFlag(wxDP_ALLOWNONE),
193 _T("this control requires a valid date") );
194
195 SYSTEMTIME st;
196 if ( dt.IsValid() )
197 wxToSystemTime(&st, dt);
198 if ( !DateTime_SetSystemtime(GetHwnd(),
199 dt.IsValid() ? GDT_VALID : GDT_NONE,
200 &st) )
201 {
202 wxLogDebug(_T("DateTime_SetSystemtime() failed"));
203 }
204 }
205
206 wxDateTime wxDatePickerCtrl::GetValue() const
207 {
208 wxDateTime dt;
209 SYSTEMTIME st;
210 if ( DateTime_GetSystemtime(GetHwnd(), &st) == GDT_VALID )
211 {
212 wxFromSystemTime(&dt, st);
213 }
214
215 return dt;
216 }
217
218 void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2)
219 {
220 SYSTEMTIME st[2];
221
222 DWORD flags = 0;
223 if ( dt1.IsValid() )
224 {
225 wxToSystemTime(&st[0], dt1);
226 flags |= GDTR_MIN;
227 }
228
229 if ( dt2.IsValid() )
230 {
231 wxToSystemTime(&st[1], dt2);
232 flags |= GDTR_MAX;
233 }
234
235 if ( !DateTime_SetRange(GetHwnd(), flags, st) )
236 {
237 wxLogDebug(_T("DateTime_SetRange() failed"));
238 }
239 }
240
241 bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
242 {
243 SYSTEMTIME st[2];
244
245 DWORD flags = DateTime_GetRange(GetHwnd(), st);
246 if ( dt1 )
247 {
248 if ( flags & GDTR_MIN )
249 wxFromSystemTime(dt1, st[0]);
250 else
251 *dt1 = wxDefaultDateTime;
252 }
253
254 if ( dt2 )
255 {
256 if ( flags & GDTR_MAX )
257 wxFromSystemTime(dt2, st[1]);
258 else
259 *dt2 = wxDefaultDateTime;
260 }
261
262 return flags != 0;
263 }
264
265 // ----------------------------------------------------------------------------
266 // wxDatePickerCtrl events
267 // ----------------------------------------------------------------------------
268
269 bool
270 wxDatePickerCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
271 {
272 NMHDR* hdr = (NMHDR *)lParam;
273 switch ( hdr->code )
274 {
275 case DTN_DATETIMECHANGE:
276 NMDATETIMECHANGE *dtch = (NMDATETIMECHANGE *)hdr;
277 wxDateTime dt;
278 if ( dtch->dwFlags == GDT_VALID )
279 wxFromSystemTime(&dt, dtch->st);
280
281 wxDateEvent event(this, dt, wxEVT_DATE_CHANGED);
282 if ( GetEventHandler()->ProcessEvent(event) )
283 {
284 *result = 0;
285 return true;
286 }
287 }
288
289 return wxDatePickerCtrlBase::MSWOnNotify(idCtrl, lParam, result);
290 }
291
292 #endif // wxUSE_DATEPICKCTRL
293