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