Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

565 lines
13 KiB

  1. // WTL Version 3.1
  2. // Copyright (C) 1997-2000 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. #ifndef __ATLDDX_H__
  9. #define __ATLDDX_H__
  10. #pragma once
  11. #if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
  12. #error Cannot use floating point DDX with _ATL_MIN_CRT defined
  13. #endif //defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
  14. #ifdef _ATL_USE_DDX_FLOAT
  15. #include <float.h>
  16. #ifndef _DEBUG
  17. #include <stdio.h>
  18. #endif //!_DEBUG
  19. #endif //_ATL_USE_DDX_FLOAT
  20. namespace WTL
  21. {
  22. // Constants
  23. #define DDX_LOAD FALSE
  24. #define DDX_SAVE TRUE
  25. // DDX map macros
  26. #define BEGIN_DDX_MAP(thisClass) \
  27. BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \
  28. { \
  29. bSaveAndValidate; \
  30. nCtlID;
  31. #define DDX_TEXT(nID, var) \
  32. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  33. { \
  34. if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
  35. return FALSE; \
  36. }
  37. #define DDX_TEXT_LEN(nID, var, len) \
  38. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  39. { \
  40. if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
  41. return FALSE; \
  42. }
  43. #define DDX_INT(nID, var) \
  44. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  45. { \
  46. if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \
  47. return FALSE; \
  48. }
  49. #define DDX_INT_RANGE(nID, var, min, max) \
  50. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  51. { \
  52. if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \
  53. return FALSE; \
  54. }
  55. #define DDX_UINT(nID, var) \
  56. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  57. { \
  58. if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \
  59. return FALSE; \
  60. }
  61. #define DDX_UINT_RANGE(nID, var, min, max) \
  62. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  63. { \
  64. if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \
  65. return FALSE; \
  66. }
  67. #ifdef _ATL_USE_DDX_FLOAT
  68. #define DDX_FLOAT(nID, var) \
  69. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  70. { \
  71. if(!DDX_Float(nID, var, bSaveAndValidate)) \
  72. return FALSE; \
  73. }
  74. #define DDX_FLOAT_RANGE(nID, var, min, max) \
  75. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  76. { \
  77. if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \
  78. return FALSE; \
  79. }
  80. #endif //_ATL_USE_DDX_FLOAT
  81. #define DDX_CONTROL(nID, obj) \
  82. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  83. DDX_Control(nID, obj, bSaveAndValidate);
  84. #define DDX_CHECK(nID, var) \
  85. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  86. DDX_Check(nID, var, bSaveAndValidate);
  87. #define DDX_RADIO(nID, var) \
  88. if(nCtlID == (UINT)-1 || nCtlID == nID) \
  89. DDX_Radio(nID, var, bSaveAndValidate);
  90. #define END_DDX_MAP() \
  91. return TRUE; \
  92. }
  93. /////////////////////////////////////////////////////////////////////////////
  94. // CWinDataExchange - provides support for DDX
  95. template <class T>
  96. class CWinDataExchange
  97. {
  98. public:
  99. // Data exchange method - override in your derived class
  100. BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
  101. {
  102. // this one should never be called, override it in
  103. // your derived class by implementing DDX map
  104. ATLASSERT(FALSE);
  105. return FALSE;
  106. }
  107. // Helpers for validation error reporting
  108. enum _XDataType
  109. {
  110. ddxDataNull = 0,
  111. ddxDataText = 1,
  112. ddxDataInt = 2,
  113. ddxDataFloat = 3,
  114. ddxDataDouble = 4
  115. };
  116. struct _XTextData
  117. {
  118. int nLength;
  119. int nMaxLength;
  120. };
  121. struct _XIntData
  122. {
  123. long nVal;
  124. long nMin;
  125. long nMax;
  126. };
  127. struct _XFloatData
  128. {
  129. double nVal;
  130. double nMin;
  131. double nMax;
  132. };
  133. struct _XData
  134. {
  135. _XDataType nDataType;
  136. union
  137. {
  138. _XTextData textData;
  139. _XIntData intData;
  140. _XFloatData floatData;
  141. };
  142. };
  143. // Text exchange
  144. BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int nSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
  145. {
  146. T* pT = static_cast<T*>(this);
  147. BOOL bSuccess = TRUE;
  148. if(bSave)
  149. {
  150. HWND hWndCtrl = pT->GetDlgItem(nID);
  151. int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, nSize);
  152. if(nRetLen < ::GetWindowTextLength(hWndCtrl))
  153. bSuccess = FALSE;
  154. }
  155. else
  156. {
  157. ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
  158. bSuccess = pT->SetDlgItemText(nID, lpstrText);
  159. }
  160. if(!bSuccess)
  161. {
  162. pT->OnDataExchangeError(nID, bSave);
  163. }
  164. else if(bSave && bValidate) // validation
  165. {
  166. ATLASSERT(nLength > 0);
  167. if(lstrlen(lpstrText) > nLength)
  168. {
  169. _XData data;
  170. data.nDataType = ddxDataText;
  171. data.textData.nLength = lstrlen(lpstrText);
  172. data.textData.nMaxLength = nLength;
  173. pT->OnDataValidateError(nID, bSave, data);
  174. bSuccess = FALSE;
  175. }
  176. }
  177. return bSuccess;
  178. }
  179. BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*nSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
  180. {
  181. T* pT = static_cast<T*>(this);
  182. BOOL bSuccess = TRUE;
  183. if(bSave)
  184. {
  185. bSuccess = pT->GetDlgItemText(nID, bstrText);
  186. }
  187. else
  188. {
  189. USES_CONVERSION;
  190. LPTSTR lpstrText = OLE2T(bstrText);
  191. ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
  192. bSuccess = pT->SetDlgItemText(nID, lpstrText);
  193. }
  194. if(!bSuccess)
  195. {
  196. pT->OnDataExchangeError(nID, bSave);
  197. }
  198. else if(bSave && bValidate) // validation
  199. {
  200. ATLASSERT(nLength > 0);
  201. if((int)::SysStringLen(bstrText) > nLength)
  202. {
  203. _XData data;
  204. data.nDataType = ddxDataText;
  205. data.textData.nLength = (int)::SysStringLen(bstrText);
  206. data.textData.nMaxLength = nLength;
  207. pT->OnDataValidateError(nID, bSave, data);
  208. bSuccess = FALSE;
  209. }
  210. }
  211. return bSuccess;
  212. }
  213. BOOL DDX_Text(UINT nID, CComBSTR& bstrText, int /*nSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
  214. {
  215. T* pT = static_cast<T*>(this);
  216. BOOL bSuccess = TRUE;
  217. if(bSave)
  218. {
  219. bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);
  220. }
  221. else
  222. {
  223. USES_CONVERSION;
  224. LPTSTR lpstrText = OLE2T(bstrText);
  225. ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
  226. bSuccess = pT->SetDlgItemText(nID, lpstrText);
  227. }
  228. if(!bSuccess)
  229. {
  230. pT->OnDataExchangeError(nID, bSave);
  231. }
  232. else if(bSave && bValidate) // validation
  233. {
  234. ATLASSERT(nLength > 0);
  235. if((int)bstrText.Length() > nLength)
  236. {
  237. _XData data;
  238. data.nDataType = ddxDataText;
  239. data.textData.nLength = (int)bstrText.Length();
  240. data.textData.nMaxLength = nLength;
  241. pT->OnDataValidateError(nID, bSave, data);
  242. bSuccess = FALSE;
  243. }
  244. }
  245. return bSuccess;
  246. }
  247. #ifdef __ATLSTR_H__
  248. BOOL DDX_Text(UINT nID, CString& strText, int /*nSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
  249. {
  250. T* pT = static_cast<T*>(this);
  251. BOOL bSuccess = TRUE;
  252. if(bSave)
  253. {
  254. HWND hWndCtrl = pT->GetDlgItem(nID);
  255. int nLen = ::GetWindowTextLength(hWndCtrl);
  256. int nRetLen = ::GetWindowText(hWndCtrl, strText.GetBufferSetLength(nLen), nLen + 1);
  257. if(nRetLen < nLen)
  258. bSuccess = FALSE;
  259. strText.ReleaseBuffer();
  260. }
  261. else
  262. {
  263. bSuccess = pT->SetDlgItemText(nID, strText);
  264. }
  265. if(!bSuccess)
  266. {
  267. pT->OnDataExchangeError(nID, bSave);
  268. }
  269. else if(bSave && bValidate) // validation
  270. {
  271. ATLASSERT(nLength > 0);
  272. if(strText.GetLength() > nLength)
  273. {
  274. _XData data;
  275. data.nDataType = ddxDataText;
  276. data.textData.nLength = strText.GetLength();
  277. data.textData.nMaxLength = nLength;
  278. pT->OnDataValidateError(nID, bSave, data);
  279. bSuccess = FALSE;
  280. }
  281. }
  282. return bSuccess;
  283. }
  284. #endif //__ATLSTR_H__
  285. // Numeric exchange
  286. template <class Type>
  287. BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)
  288. {
  289. T* pT = static_cast<T*>(this);
  290. BOOL bSuccess = TRUE;
  291. if(bSave)
  292. {
  293. nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);
  294. }
  295. else
  296. {
  297. ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
  298. bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);
  299. }
  300. if(!bSuccess)
  301. {
  302. pT->OnDataExchangeError(nID, bSave);
  303. }
  304. else if(bSave && bValidate) // validation
  305. {
  306. ATLASSERT(nMin != nMax);
  307. if(nVal < nMin || nVal > nMax)
  308. {
  309. _XData data;
  310. data.nDataType = ddxDataInt;
  311. data.intData.nVal = (long)nVal;
  312. data.intData.nMin = (long)nMin;
  313. data.intData.nMax = (long)nMax;
  314. pT->OnDataValidateError(nID, bSave, data);
  315. bSuccess = FALSE;
  316. }
  317. }
  318. return bSuccess;
  319. }
  320. // Float exchange
  321. #ifdef _ATL_USE_DDX_FLOAT
  322. static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)
  323. {
  324. ATLASSERT(lpszText != NULL);
  325. while (*lpszText == ' ' || *lpszText == '\t')
  326. lpszText++;
  327. TCHAR chFirst = lpszText[0];
  328. d = _tcstod(lpszText, (LPTSTR*)&lpszText);
  329. if (d == 0.0 && chFirst != '0')
  330. return FALSE; // could not convert
  331. while (*lpszText == ' ' || *lpszText == '\t')
  332. lpszText++;
  333. if (*lpszText != '\0')
  334. return FALSE; // not terminated properly
  335. return TRUE;
  336. }
  337. BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F)
  338. {
  339. T* pT = static_cast<T*>(this);
  340. BOOL bSuccess = TRUE;
  341. TCHAR szBuff[32];
  342. if(bSave)
  343. {
  344. pT->GetDlgItemText(nID, szBuff, sizeof(szBuff) / sizeof(TCHAR));
  345. double d = 0;
  346. if(_AtlSimpleFloatParse(szBuff, d))
  347. nVal = (float)d;
  348. else
  349. bSuccess = FALSE;
  350. }
  351. else
  352. {
  353. ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
  354. _stprintf(szBuff, _T("%.*g"), FLT_DIG, nVal);
  355. bSuccess = pT->SetDlgItemText(nID, szBuff);
  356. }
  357. if(!bSuccess)
  358. {
  359. pT->OnDataExchangeError(nID, bSave);
  360. }
  361. else if(bSave && bValidate) // validation
  362. {
  363. ATLASSERT(nMin != nMax);
  364. if(nVal < nMin || nVal > nMax)
  365. {
  366. _XData data;
  367. data.nDataType = ddxDataFloat;
  368. data.floatData.nVal = (double)nVal;
  369. data.floatData.nMin = (double)nMin;
  370. data.floatData.nMax = (double)nMax;
  371. pT->OnDataValidateError(nID, bSave, data);
  372. bSuccess = FALSE;
  373. }
  374. }
  375. return bSuccess;
  376. }
  377. BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0.)
  378. {
  379. T* pT = static_cast<T*>(this);
  380. BOOL bSuccess = TRUE;
  381. TCHAR szBuff[32];
  382. if(bSave)
  383. {
  384. pT->GetDlgItemText(nID, szBuff, sizeof(szBuff) / sizeof(TCHAR));
  385. double d = 0;
  386. if(_AtlSimpleFloatParse(szBuff, d))
  387. nVal = d;
  388. else
  389. bSuccess = FALSE;
  390. }
  391. else
  392. {
  393. ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
  394. _stprintf(szBuff, _T("%.*g"), DBL_DIG, nVal);
  395. bSuccess = pT->SetDlgItemText(nID, szBuff);
  396. }
  397. if(!bSuccess)
  398. {
  399. pT->OnDataExchangeError(nID, bSave);
  400. }
  401. else if(bSave && bValidate) // validation
  402. {
  403. ATLASSERT(nMin != nMax);
  404. if(nVal < nMin || nVal > nMax)
  405. {
  406. _XData data;
  407. data.nDataType = ddxDataFloat;
  408. data.floatData.nVal = nVal;
  409. data.floatData.nMin = nMin;
  410. data.floatData.nMax = nMax;
  411. pT->OnDataValidateError(nID, bSave, data);
  412. bSuccess = FALSE;
  413. }
  414. }
  415. return bSuccess;
  416. }
  417. #endif //_ATL_USE_DDX_FLOAT
  418. // Control subclassing
  419. template <class TControl>
  420. void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
  421. {
  422. T* pT = static_cast<T*>(this);
  423. if(!bSave && ctrl.m_hWnd == NULL)
  424. ctrl.SubclassWindow(pT->GetDlgItem(nID));
  425. }
  426. // Control state
  427. void DDX_Check(UINT nID, int& nValue, BOOL bSave)
  428. {
  429. T* pT = static_cast<T*>(this);
  430. HWND hWndCtrl = pT->GetDlgItem(nID);
  431. if(bSave)
  432. {
  433. nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
  434. ATLASSERT(nValue >= 0 && nValue <= 2);
  435. }
  436. else
  437. {
  438. if(nValue < 0 || nValue > 2)
  439. {
  440. ATLTRACE2(atlTraceUI, 0, "ATL: Warning - dialog data checkbox value (%d) out of range.\n", nValue);
  441. nValue = 0; // default to off
  442. }
  443. ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);
  444. }
  445. }
  446. void DDX_Radio(UINT nID, int& nValue, BOOL bSave)
  447. {
  448. T* pT = static_cast<T*>(this);
  449. HWND hWndCtrl = pT->GetDlgItem(nID);
  450. ATLASSERT(hWndCtrl != NULL);
  451. // must be first in a group of auto radio buttons
  452. ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
  453. ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
  454. if(bSave)
  455. nValue = -1; // value if none found
  456. // walk all children in group
  457. int nButton = 0;
  458. do
  459. {
  460. if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
  461. {
  462. // control in group is a radio button
  463. if(bSave)
  464. {
  465. if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
  466. {
  467. ATLASSERT(nValue == -1); // only set once
  468. nValue = nButton;
  469. }
  470. }
  471. else
  472. {
  473. // select button
  474. ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);
  475. }
  476. nButton++;
  477. }
  478. else
  479. {
  480. ATLTRACE2(atlTraceUI, 0, "ATL: Warning - skipping non-radio button in group.\n");
  481. }
  482. hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
  483. }
  484. while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
  485. }
  486. // Overrideables
  487. void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)
  488. {
  489. // Override to display an error message
  490. ::MessageBeep((UINT)-1);
  491. T* pT = static_cast<T*>(this);
  492. ::SetFocus(pT->GetDlgItem(nCtrlID));
  493. }
  494. void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)
  495. {
  496. // Override to display an error message
  497. ::MessageBeep((UINT)-1);
  498. T* pT = static_cast<T*>(this);
  499. ::SetFocus(pT->GetDlgItem(nCtrlID));
  500. }
  501. };
  502. }; //namespace WTL
  503. #endif //__ATLDDX_H__