Add ICU message format support
[chromium-blink-merge.git] / third_party / wtl / include / atlddx.h
blobdc0f31f210ca53662d2bc2f764376a056df59bfe
1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
9 #ifndef __ATLDDX_H__
10 #define __ATLDDX_H__
12 #pragma once
14 #ifndef __cplusplus
15 #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
18 #ifndef __ATLAPP_H__
19 #error atlddx.h requires atlapp.h to be included first
20 #endif
22 #if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
23 #error Cannot use floating point DDX with _ATL_MIN_CRT defined
24 #endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
26 #ifdef _ATL_USE_DDX_FLOAT
27 #include <float.h>
28 #endif // _ATL_USE_DDX_FLOAT
31 ///////////////////////////////////////////////////////////////////////////////
32 // Classes in this file:
34 // CWinDataExchange<T>
37 namespace WTL
40 // Constants
41 #define DDX_LOAD FALSE
42 #define DDX_SAVE TRUE
44 // DDX map macros
45 #define BEGIN_DDX_MAP(thisClass) \
46 BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \
47 { \
48 bSaveAndValidate; \
49 nCtlID;
51 #define DDX_TEXT(nID, var) \
52 if(nCtlID == (UINT)-1 || nCtlID == nID) \
53 { \
54 if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
55 return FALSE; \
58 #define DDX_TEXT_LEN(nID, var, len) \
59 if(nCtlID == (UINT)-1 || nCtlID == nID) \
60 { \
61 if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
62 return FALSE; \
65 #define DDX_INT(nID, var) \
66 if(nCtlID == (UINT)-1 || nCtlID == nID) \
67 { \
68 if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \
69 return FALSE; \
72 #define DDX_INT_RANGE(nID, var, min, max) \
73 if(nCtlID == (UINT)-1 || nCtlID == nID) \
74 { \
75 if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \
76 return FALSE; \
79 #define DDX_UINT(nID, var) \
80 if(nCtlID == (UINT)-1 || nCtlID == nID) \
81 { \
82 if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \
83 return FALSE; \
86 #define DDX_UINT_RANGE(nID, var, min, max) \
87 if(nCtlID == (UINT)-1 || nCtlID == nID) \
88 { \
89 if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \
90 return FALSE; \
93 #ifdef _ATL_USE_DDX_FLOAT
94 #define DDX_FLOAT(nID, var) \
95 if(nCtlID == (UINT)-1 || nCtlID == nID) \
96 { \
97 if(!DDX_Float(nID, var, bSaveAndValidate)) \
98 return FALSE; \
101 #define DDX_FLOAT_RANGE(nID, var, min, max) \
102 if(nCtlID == (UINT)-1 || nCtlID == nID) \
104 if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \
105 return FALSE; \
107 #define DDX_FLOAT_P(nID, var, precision) \
108 if(nCtlID == (UINT)-1 || nCtlID == nID) \
110 if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \
111 return FALSE; \
114 #define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \
115 if(nCtlID == (UINT)-1 || nCtlID == nID) \
117 if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \
118 return FALSE; \
120 #endif // _ATL_USE_DDX_FLOAT
122 #define DDX_CONTROL(nID, obj) \
123 if(nCtlID == (UINT)-1 || nCtlID == nID) \
124 DDX_Control(nID, obj, bSaveAndValidate);
126 #define DDX_CONTROL_HANDLE(nID, obj) \
127 if(nCtlID == (UINT)-1 || nCtlID == nID) \
128 DDX_Control_Handle(nID, obj, bSaveAndValidate);
130 #define DDX_CHECK(nID, var) \
131 if(nCtlID == (UINT)-1 || nCtlID == nID) \
132 DDX_Check(nID, var, bSaveAndValidate);
134 #define DDX_RADIO(nID, var) \
135 if(nCtlID == (UINT)-1 || nCtlID == nID) \
136 DDX_Radio(nID, var, bSaveAndValidate);
138 #define END_DDX_MAP() \
139 return TRUE; \
143 ///////////////////////////////////////////////////////////////////////////////
144 // CWinDataExchange - provides support for DDX
146 template <class T>
147 class CWinDataExchange
149 public:
150 // Data exchange method - override in your derived class
151 BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
153 // this one should never be called, override it in
154 // your derived class by implementing DDX map
155 ATLASSERT(FALSE);
156 return FALSE;
159 // Helpers for validation error reporting
160 enum _XDataType
162 ddxDataNull = 0,
163 ddxDataText = 1,
164 ddxDataInt = 2,
165 ddxDataFloat = 3,
166 ddxDataDouble = 4
169 struct _XTextData
171 int nLength;
172 int nMaxLength;
175 struct _XIntData
177 long nVal;
178 long nMin;
179 long nMax;
182 struct _XFloatData
184 double nVal;
185 double nMin;
186 double nMax;
189 struct _XData
191 _XDataType nDataType;
192 union
194 _XTextData textData;
195 _XIntData intData;
196 _XFloatData floatData;
200 // Text exchange
201 BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
203 T* pT = static_cast<T*>(this);
204 BOOL bSuccess = TRUE;
206 if(bSave)
208 HWND hWndCtrl = pT->GetDlgItem(nID);
209 int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR));
210 if(nRetLen < ::GetWindowTextLength(hWndCtrl))
211 bSuccess = FALSE;
213 else
215 ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
216 bSuccess = pT->SetDlgItemText(nID, lpstrText);
219 if(!bSuccess)
221 pT->OnDataExchangeError(nID, bSave);
223 else if(bSave && bValidate) // validation
225 ATLASSERT(nLength > 0);
226 if(lstrlen(lpstrText) > nLength)
228 _XData data = { ddxDataText };
229 data.textData.nLength = lstrlen(lpstrText);
230 data.textData.nMaxLength = nLength;
231 pT->OnDataValidateError(nID, bSave, data);
232 bSuccess = FALSE;
235 return bSuccess;
238 BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
240 T* pT = static_cast<T*>(this);
241 BOOL bSuccess = TRUE;
243 if(bSave)
245 bSuccess = pT->GetDlgItemText(nID, bstrText);
247 else
249 USES_CONVERSION;
250 LPTSTR lpstrText = OLE2T(bstrText);
251 ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
252 bSuccess = pT->SetDlgItemText(nID, lpstrText);
255 if(!bSuccess)
257 pT->OnDataExchangeError(nID, bSave);
259 else if(bSave && bValidate) // validation
261 ATLASSERT(nLength > 0);
262 if((int)::SysStringLen(bstrText) > nLength)
264 _XData data = { ddxDataText };
265 data.textData.nLength = (int)::SysStringLen(bstrText);
266 data.textData.nMaxLength = nLength;
267 pT->OnDataValidateError(nID, bSave, data);
268 bSuccess = FALSE;
271 return bSuccess;
274 BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
276 T* pT = static_cast<T*>(this);
277 BOOL bSuccess = TRUE;
279 if(bSave)
281 bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);
283 else
285 USES_CONVERSION;
286 LPTSTR lpstrText = OLE2T(bstrText);
287 ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
288 bSuccess = pT->SetDlgItemText(nID, lpstrText);
291 if(!bSuccess)
293 pT->OnDataExchangeError(nID, bSave);
295 else if(bSave && bValidate) // validation
297 ATLASSERT(nLength > 0);
298 if((int)bstrText.Length() > nLength)
300 _XData data = { ddxDataText };
301 data.textData.nLength = (int)bstrText.Length();
302 data.textData.nMaxLength = nLength;
303 pT->OnDataValidateError(nID, bSave, data);
304 bSuccess = FALSE;
307 return bSuccess;
310 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
311 BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
313 T* pT = static_cast<T*>(this);
314 BOOL bSuccess = TRUE;
316 if(bSave)
318 HWND hWndCtrl = pT->GetDlgItem(nID);
319 int nLen = ::GetWindowTextLength(hWndCtrl);
320 int nRetLen = -1;
321 LPTSTR lpstr = strText.GetBufferSetLength(nLen);
322 if(lpstr != NULL)
324 nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1);
325 strText.ReleaseBuffer();
327 if(nRetLen < nLen)
328 bSuccess = FALSE;
330 else
332 bSuccess = pT->SetDlgItemText(nID, strText);
335 if(!bSuccess)
337 pT->OnDataExchangeError(nID, bSave);
339 else if(bSave && bValidate) // validation
341 ATLASSERT(nLength > 0);
342 if(strText.GetLength() > nLength)
344 _XData data = { ddxDataText };
345 data.textData.nLength = strText.GetLength();
346 data.textData.nMaxLength = nLength;
347 pT->OnDataValidateError(nID, bSave, data);
348 bSuccess = FALSE;
351 return bSuccess;
353 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
355 // Numeric exchange
356 template <class Type>
357 BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)
359 T* pT = static_cast<T*>(this);
360 BOOL bSuccess = TRUE;
362 if(bSave)
364 nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);
366 else
368 ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
369 bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);
372 if(!bSuccess)
374 pT->OnDataExchangeError(nID, bSave);
376 else if(bSave && bValidate) // validation
378 ATLASSERT(nMin != nMax);
379 if(nVal < nMin || nVal > nMax)
381 _XData data = { ddxDataInt };
382 data.intData.nVal = (long)nVal;
383 data.intData.nMin = (long)nMin;
384 data.intData.nMax = (long)nMax;
385 pT->OnDataValidateError(nID, bSave, data);
386 bSuccess = FALSE;
389 return bSuccess;
392 // Float exchange
393 #ifdef _ATL_USE_DDX_FLOAT
394 static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)
396 ATLASSERT(lpszText != NULL);
397 while (*lpszText == _T(' ') || *lpszText == _T('\t'))
398 lpszText++;
400 TCHAR chFirst = lpszText[0];
401 d = _tcstod(lpszText, (LPTSTR*)&lpszText);
402 if (d == 0.0 && chFirst != _T('0'))
403 return FALSE; // could not convert
404 while (*lpszText == _T(' ') || *lpszText == _T('\t'))
405 lpszText++;
407 if (*lpszText != _T('\0'))
408 return FALSE; // not terminated properly
410 return TRUE;
413 BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG)
415 T* pT = static_cast<T*>(this);
416 BOOL bSuccess = TRUE;
417 const int cchBuff = 32;
418 TCHAR szBuff[cchBuff] = { 0 };
420 if(bSave)
422 pT->GetDlgItemText(nID, szBuff, cchBuff);
423 double d = 0;
424 if(_AtlSimpleFloatParse(szBuff, d))
425 nVal = (float)d;
426 else
427 bSuccess = FALSE;
429 else
431 ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
432 SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
433 bSuccess = pT->SetDlgItemText(nID, szBuff);
436 if(!bSuccess)
438 pT->OnDataExchangeError(nID, bSave);
440 else if(bSave && bValidate) // validation
442 ATLASSERT(nMin != nMax);
443 if(nVal < nMin || nVal > nMax)
445 _XData data = { ddxDataFloat };
446 data.floatData.nVal = (double)nVal;
447 data.floatData.nMin = (double)nMin;
448 data.floatData.nMax = (double)nMax;
449 pT->OnDataValidateError(nID, bSave, data);
450 bSuccess = FALSE;
453 return bSuccess;
456 BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG)
458 T* pT = static_cast<T*>(this);
459 BOOL bSuccess = TRUE;
460 const int cchBuff = 32;
461 TCHAR szBuff[cchBuff] = { 0 };
463 if(bSave)
465 pT->GetDlgItemText(nID, szBuff, cchBuff);
466 double d = 0;
467 if(_AtlSimpleFloatParse(szBuff, d))
468 nVal = d;
469 else
470 bSuccess = FALSE;
472 else
474 ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
475 SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
476 bSuccess = pT->SetDlgItemText(nID, szBuff);
479 if(!bSuccess)
481 pT->OnDataExchangeError(nID, bSave);
483 else if(bSave && bValidate) // validation
485 ATLASSERT(nMin != nMax);
486 if(nVal < nMin || nVal > nMax)
488 _XData data = { ddxDataFloat };
489 data.floatData.nVal = nVal;
490 data.floatData.nMin = nMin;
491 data.floatData.nMax = nMax;
492 pT->OnDataValidateError(nID, bSave, data);
493 bSuccess = FALSE;
496 return bSuccess;
498 #endif // _ATL_USE_DDX_FLOAT
500 // Full control subclassing (for CWindowImpl derived controls)
501 template <class TControl>
502 void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
504 if(!bSave && ctrl.m_hWnd == NULL)
506 T* pT = static_cast<T*>(this);
507 ctrl.SubclassWindow(pT->GetDlgItem(nID));
511 // Simple control attaching (for HWND wrapper controls)
512 template <class TControl>
513 void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)
515 if(!bSave && ctrl.m_hWnd == NULL)
517 T* pT = static_cast<T*>(this);
518 ctrl = pT->GetDlgItem(nID);
522 // Control state
523 void DDX_Check(UINT nID, int& nValue, BOOL bSave)
525 T* pT = static_cast<T*>(this);
526 HWND hWndCtrl = pT->GetDlgItem(nID);
527 if(bSave)
529 nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
530 ATLASSERT(nValue >= 0 && nValue <= 2);
532 else
534 if(nValue < 0 || nValue > 2)
536 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue);
537 nValue = 0; // default to off
539 ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);
543 // variant that supports bool (checked/not-checked, no intermediate state)
544 void DDX_Check(UINT nID, bool& bCheck, BOOL bSave)
546 int nValue = bCheck ? 1 : 0;
547 DDX_Check(nID, nValue, bSave);
549 if(bSave)
551 if(nValue == 2)
552 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue);
553 bCheck = (nValue == 1);
557 void DDX_Radio(UINT nID, int& nValue, BOOL bSave)
559 T* pT = static_cast<T*>(this);
560 HWND hWndCtrl = pT->GetDlgItem(nID);
561 ATLASSERT(hWndCtrl != NULL);
563 // must be first in a group of auto radio buttons
564 ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
565 ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
567 if(bSave)
568 nValue = -1; // value if none found
570 // walk all children in group
571 int nButton = 0;
574 if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
576 // control in group is a radio button
577 if(bSave)
579 if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
581 ATLASSERT(nValue == -1); // only set once
582 nValue = nButton;
585 else
587 // select button
588 ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);
590 nButton++;
592 else
594 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n"));
596 hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
598 while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
601 // Overrideables
602 void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)
604 // Override to display an error message
605 ::MessageBeep((UINT)-1);
606 T* pT = static_cast<T*>(this);
607 ::SetFocus(pT->GetDlgItem(nCtrlID));
610 void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)
612 // Override to display an error message
613 ::MessageBeep((UINT)-1);
614 T* pT = static_cast<T*>(this);
615 ::SetFocus(pT->GetDlgItem(nCtrlID));
619 }; // namespace WTL
621 #endif // __ATLDDX_H__