1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/datectrl.cpp
3 // Purpose: wxDatePickerCtrl implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2005-01-09
7 // Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
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/msw/wrapwin.h"
29 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
30 #include "wx/app.h"
31 #include "wx/intl.h"
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
34 #include "wx/msw/private.h"
35 #endif
36
37 #include "wx/datectrl.h"
38 #include "wx/dateevt.h"
39
IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl,wxControl)40 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
41
42 // ============================================================================
43 // implementation
44 // ============================================================================
45
46 // ----------------------------------------------------------------------------
47 // wxDatePickerCtrl creation
48 // ----------------------------------------------------------------------------
49
50 bool
51 wxDatePickerCtrl::Create(wxWindow *parent,
52 wxWindowID id,
53 const wxDateTime& dt,
54 const wxPoint& pos,
55 const wxSize& size,
56 long style,
57 const wxValidator& validator,
58 const wxString& name)
59 {
60 // use wxDP_SPIN if wxDP_DEFAULT (0) was given as style
61 if ( !(style & wxDP_DROPDOWN) )
62 style |= wxDP_SPIN;
63
64 return MSWCreateDateTimePicker(parent, id, dt,
65 pos, size, style,
66 validator, name);
67 }
68
MSWGetStyle(long style,WXDWORD * exstyle) const69 WXDWORD wxDatePickerCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
70 {
71 WXDWORD styleMSW = wxDatePickerCtrlBase::MSWGetStyle(style, exstyle);
72
73 // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with
74 // comctl32.dll 4.72
75 if ( wxApp::GetComCtl32Version() > 472 && (style & wxDP_SPIN) )
76 styleMSW |= DTS_UPDOWN;
77 //else: drop down by default
78
79 #ifdef DTS_SHORTDATECENTURYFORMAT
80 if ( style & wxDP_SHOWCENTURY )
81 styleMSW |= DTS_SHORTDATECENTURYFORMAT;
82 else
83 #endif // DTS_SHORTDATECENTURYFORMAT
84 styleMSW |= DTS_SHORTDATEFORMAT;
85
86 if ( style & wxDP_ALLOWNONE )
87 styleMSW |= DTS_SHOWNONE;
88
89 return styleMSW;
90 }
91
92 // TODO: handle WM_WININICHANGE
93
94 #if wxUSE_INTL
95
MSWGetFormat() const96 wxLocaleInfo wxDatePickerCtrl::MSWGetFormat() const
97 {
98 return wxLOCALE_SHORT_DATE_FMT;
99 }
100
101 #endif // wxUSE_INTL
102
103 // ----------------------------------------------------------------------------
104 // wxDatePickerCtrl operations
105 // ----------------------------------------------------------------------------
106
SetValue(const wxDateTime & dt)107 void wxDatePickerCtrl::SetValue(const wxDateTime& dt)
108 {
109 if ( dt.IsValid() )
110 {
111 // Don't try setting the date if it's out of range: calendar control
112 // under XP (and presumably all the other pre-Vista Windows versions)
113 // doesn't return false from DateTime_SetSystemtime() in this case but
114 // doesn't actually change the date, so we can't update our m_date
115 // unconditionally and would need to check whether it was changed
116 // before doing it. It looks simpler to just check whether it's in
117 // range here instead.
118 //
119 // If we ever drop support for XP we could rely on the return value of
120 // DateTime_SetSystemtime() but this probably won't happen in near
121 // future.
122 wxDateTime dtStart, dtEnd;
123 GetRange(&dtStart, &dtEnd);
124 if ( (dtStart.IsValid() && dt < dtStart) ||
125 (dtEnd.IsValid() && dt > dtEnd) )
126 {
127 // Fail silently, some existing code relies on SetValue() with an
128 // out of range value simply doing nothing -- so don't.
129 return;
130 }
131 }
132
133 wxDateTimePickerCtrl::SetValue(dt);
134
135 // we need to keep only the date part, times don't make sense for this
136 // control (in particular, comparisons with other dates would fail)
137 if ( m_date.IsValid() )
138 m_date.ResetTime();
139 }
140
GetValue() const141 wxDateTime wxDatePickerCtrl::GetValue() const
142 {
143 #if wxDEBUG_LEVEL
144 wxDateTime dt;
145 SYSTEMTIME st;
146 if ( DateTime_GetSystemtime(GetHwnd(), &st) == GDT_VALID )
147 {
148 dt.SetFromMSWSysDate(st);
149 }
150
151 wxASSERT_MSG( m_date.IsValid() == dt.IsValid() &&
152 (!dt.IsValid() || dt == m_date),
153 wxT("bug in wxDateTimePickerCtrl: m_date not in sync") );
154 #endif // wxDEBUG_LEVEL
155
156 return wxDateTimePickerCtrl::GetValue();
157 }
158
SetRange(const wxDateTime & dt1,const wxDateTime & dt2)159 void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2)
160 {
161 SYSTEMTIME st[2];
162
163 DWORD flags = 0;
164 if ( dt1.IsValid() )
165 {
166 dt1.GetAsMSWSysTime(st + 0);
167 flags |= GDTR_MIN;
168 }
169
170 if ( dt2.IsValid() )
171 {
172 dt2.GetAsMSWSysTime(st + 1);
173 flags |= GDTR_MAX;
174 }
175
176 if ( !DateTime_SetRange(GetHwnd(), flags, st) )
177 {
178 wxLogDebug(wxT("DateTime_SetRange() failed"));
179 }
180 }
181
GetRange(wxDateTime * dt1,wxDateTime * dt2) const182 bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
183 {
184 SYSTEMTIME st[2];
185
186 DWORD flags = DateTime_GetRange(GetHwnd(), st);
187 if ( dt1 )
188 {
189 if ( flags & GDTR_MIN )
190 dt1->SetFromMSWSysDate(st[0]);
191 else
192 *dt1 = wxDefaultDateTime;
193 }
194
195 if ( dt2 )
196 {
197 if ( flags & GDTR_MAX )
198 dt2->SetFromMSWSysDate(st[1]);
199 else
200 *dt2 = wxDefaultDateTime;
201 }
202
203 return flags != 0;
204 }
205
206 // ----------------------------------------------------------------------------
207 // wxDatePickerCtrl events
208 // ----------------------------------------------------------------------------
209
MSWOnDateTimeChange(const NMDATETIMECHANGE & dtch)210 bool wxDatePickerCtrl::MSWOnDateTimeChange(const NMDATETIMECHANGE& dtch)
211 {
212 wxDateTime dt;
213 if ( dtch.dwFlags == GDT_VALID )
214 dt.SetFromMSWSysDate(dtch.st);
215
216 // filter out duplicate DTN_DATETIMECHANGE events which the native
217 // control sends us when using wxDP_DROPDOWN style
218 if ( (m_date.IsValid() == dt.IsValid()) &&
219 (!m_date.IsValid() || dt == m_date) )
220 return false;
221
222 m_date = dt;
223 wxDateEvent event(this, dt, wxEVT_DATE_CHANGED);
224 return HandleWindowEvent(event);
225 }
226
227 #endif // wxUSE_DATEPICKCTRL
228