|
|
1.1 ! root 1: // This is a part of the Microsoft Foundation Classes C++ library. ! 2: // Copyright (C) 1992 Microsoft Corporation ! 3: // All rights reserved. ! 4: ! 5: // This source code is only intended as a supplement to the ! 6: // Microsoft Foundation Classes Reference and Microsoft ! 7: // QuickHelp and/or WinHelp documentation provided with the library. ! 8: // See these sources for detailed information regarding the ! 9: // Microsoft Foundation Classes product. ! 10: ! 11: #include "stdafx.h" ! 12: ! 13: #ifdef AFX_CORE3_SEG ! 14: #pragma code_seg(AFX_CORE3_SEG) ! 15: #endif ! 16: ! 17: #ifdef _DEBUG ! 18: #undef THIS_FILE ! 19: static char BASED_CODE THIS_FILE[] = __FILE__; ! 20: #endif ! 21: ! 22: ///////////////////////////////////////////////////////////////////////////// ! 23: // CDataExchange member functions (contructor is in wincore.cpp for swap tuning) ! 24: ! 25: HWND CDataExchange::PrepareEditCtrl(int nIDC) ! 26: { ! 27: HWND hWndCtrl = PrepareCtrl(nIDC); ! 28: ASSERT(hWndCtrl != NULL); ! 29: m_bEditLastControl = TRUE; ! 30: return hWndCtrl; ! 31: } ! 32: ! 33: HWND CDataExchange::PrepareCtrl(int nIDC) ! 34: { ! 35: ASSERT(nIDC != 0); ! 36: ASSERT(nIDC != -1); // not allowed ! 37: HWND hWndCtrl = ::GetDlgItem(m_pDlgWnd->m_hWnd, nIDC); ! 38: if (hWndCtrl == NULL) ! 39: { ! 40: TRACE1("Error: no data exchange control with ID 0x%04X\n", nIDC); ! 41: ASSERT(FALSE); ! 42: AfxThrowNotSupportedException(); ! 43: } ! 44: m_hWndLastControl = hWndCtrl; ! 45: m_bEditLastControl = FALSE; // not an edit item by default ! 46: ASSERT(hWndCtrl != NULL); // never return NULL handle ! 47: return hWndCtrl; ! 48: } ! 49: ! 50: void CDataExchange::Fail() ! 51: { ! 52: if (!m_bSaveAndValidate) ! 53: { ! 54: TRACE0("Warning: CDataExchange::Fail called when not validating\n"); ! 55: // throw the exception anyway ! 56: } ! 57: else if (m_hWndLastControl != NULL) ! 58: { ! 59: // restore focus and selection to offending field ! 60: ::SetFocus(m_hWndLastControl); ! 61: if (m_bEditLastControl) // select edit item ! 62: ::SendMessage(m_hWndLastControl, EM_SETSEL, 0, -1); ! 63: } ! 64: else ! 65: { ! 66: TRACE0("Error: fail validation with no control to restore focus to\n"); ! 67: // do nothing more ! 68: } ! 69: ! 70: AfxThrowUserException(); ! 71: } ! 72: ! 73: ///////////////////////////////////////////////////////////////////////////// ! 74: // Notes for implementing dialog data exchange and validation procs: ! 75: // * always start with PrepareCtrl or PrepareEditCtrl ! 76: // * always start with 'pDX->m_bSaveAndValidate' check ! 77: // * pDX->Fail() will throw an exception - so be prepared ! 78: // * try to avoid creating temporary HWNDs for dialog controls - i.e. ! 79: // use HWNDs for child elements ! 80: // * validation procs should only act if 'm_bSaveAndValidate' ! 81: // * use the suffices: ! 82: // DDX_ = exchange proc ! 83: // DDV_ = validation proc ! 84: // ! 85: ///////////////////////////////////////////////////////////////////////////// ! 86: ! 87: // only supports '%d', '%u', '%ld' and '%lu' ! 88: static BOOL PASCAL NEAR _AfxSimpleScanf(const char* pszText, ! 89: const char* pszFormat, va_list pData) ! 90: { ! 91: ASSERT(pszText != NULL); ! 92: ASSERT(pszFormat != NULL); ! 93: ! 94: ASSERT(*pszFormat == '%'); ! 95: pszFormat++; // skip '%' ! 96: ! 97: BOOL bLong = FALSE; ! 98: if (*pszFormat == 'l') ! 99: { ! 100: bLong = TRUE; ! 101: pszFormat++; ! 102: } ! 103: ! 104: ASSERT(*pszFormat == 'd' || *pszFormat == 'u'); ! 105: ASSERT(pszFormat[1] == '\0'); ! 106: ! 107: while (*pszText == ' ' || *pszText == '\t') ! 108: pszText++; ! 109: char chFirst = pszText[0]; ! 110: long l, l2; ! 111: if (*pszFormat == 'd') ! 112: { ! 113: // signed ! 114: l = strtol(pszText, (char**)&pszText, 10); ! 115: l2 = (int)l; ! 116: } ! 117: else ! 118: { ! 119: // unsigned ! 120: l = (long)strtoul(pszText, (char**)&pszText, 10); ! 121: l2 = (unsigned int)l; ! 122: } ! 123: if (l == 0 && chFirst != '0') ! 124: return FALSE; // could not convert ! 125: ! 126: while (*pszText == ' ' || *pszText == '\t') ! 127: pszText++; ! 128: if (*pszText != '\0') ! 129: return FALSE; // not terminated properly ! 130: ! 131: if (bLong) ! 132: *va_arg(pData, long*) = l; ! 133: else if (l == l2) ! 134: *va_arg(pData, int*) = (int)l; ! 135: else ! 136: return FALSE; // too big for int ! 137: ! 138: // all ok ! 139: return TRUE; ! 140: } ! 141: ! 142: ! 143: static void PASCAL NEAR DDX_TextWithFormat(CDataExchange* pDX, int nIDC, ! 144: const char* pszFormat, UINT nIDPrompt, ...) ! 145: // only supports windows output formats - no floating point ! 146: { ! 147: va_list pData; ! 148: va_start(pData, nIDPrompt); ! 149: ! 150: HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); ! 151: char szT[64]; ! 152: if (pDX->m_bSaveAndValidate) ! 153: { ! 154: // the following works for %d, %u, %ld, %lu ! 155: ::GetWindowText(hWndCtrl, szT, sizeof(szT)); ! 156: if (!_AfxSimpleScanf(szT, pszFormat, pData)) ! 157: { ! 158: AfxMessageBox(nIDPrompt); ! 159: pDX->Fail(); // throws exception ! 160: } ! 161: } ! 162: else ! 163: { ! 164: wvsprintf(szT, pszFormat, pData); ! 165: // does not support floating point numbers - see dlgfloat.cpp ! 166: _AfxSmartSetWindowText(hWndCtrl, szT); ! 167: } ! 168: ! 169: va_end(pData); ! 170: } ! 171: ! 172: ///////////////////////////////////////////////////////////////////////////// ! 173: // Simple formatting to text item ! 174: ! 175: void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, int& value) ! 176: { ! 177: if (pDX->m_bSaveAndValidate) ! 178: DDX_TextWithFormat(pDX, nIDC, "%d", AFX_IDP_PARSE_INT, &value); ! 179: else ! 180: DDX_TextWithFormat(pDX, nIDC, "%d", AFX_IDP_PARSE_INT, value); ! 181: } ! 182: ! 183: void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, UINT& value) ! 184: { ! 185: if (pDX->m_bSaveAndValidate) ! 186: DDX_TextWithFormat(pDX, nIDC, "%u", AFX_IDP_PARSE_INT, &value); ! 187: else ! 188: DDX_TextWithFormat(pDX, nIDC, "%u", AFX_IDP_PARSE_INT, value); ! 189: } ! 190: ! 191: void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, long& value) ! 192: { ! 193: if (pDX->m_bSaveAndValidate) ! 194: DDX_TextWithFormat(pDX, nIDC, "%ld", AFX_IDP_PARSE_INT, &value); ! 195: else ! 196: DDX_TextWithFormat(pDX, nIDC, "%ld", AFX_IDP_PARSE_INT, value); ! 197: } ! 198: ! 199: void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, DWORD& value) ! 200: { ! 201: if (pDX->m_bSaveAndValidate) ! 202: DDX_TextWithFormat(pDX, nIDC, "%lu", AFX_IDP_PARSE_INT, &value); ! 203: else ! 204: DDX_TextWithFormat(pDX, nIDC, "%lu", AFX_IDP_PARSE_INT, value); ! 205: } ! 206: ! 207: void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value) ! 208: { ! 209: HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); ! 210: if (pDX->m_bSaveAndValidate) ! 211: { ! 212: int nLen = ::GetWindowTextLength(hWndCtrl); ! 213: ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1); ! 214: } ! 215: else ! 216: { ! 217: _AfxSmartSetWindowText(hWndCtrl, value); ! 218: } ! 219: } ! 220: ! 221: ///////////////////////////////////////////////////////////////////////////// ! 222: // Data exchange for special control ! 223: ! 224: void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value) ! 225: { ! 226: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 227: if (pDX->m_bSaveAndValidate) ! 228: { ! 229: value = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); ! 230: ASSERT(value >= 0 && value <= 2); ! 231: } ! 232: else ! 233: { ! 234: if (value < 0 || value > 2) ! 235: { ! 236: value = 0; // default to off ! 237: TRACE1("Warning: dialog data checkbox value out of range" ! 238: " %d\n", value); ! 239: } ! 240: ::SendMessage(hWndCtrl, BM_SETCHECK, (WPARAM)value, 0L); ! 241: } ! 242: } ! 243: ! 244: void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value) ! 245: // must be first in a group of auto radio buttons ! 246: { ! 247: HWND hWndFirstCtrl = pDX->PrepareCtrl(nIDC); ! 248: ! 249: ASSERT(::GetWindowLong(hWndFirstCtrl, GWL_STYLE) & WS_GROUP); ! 250: ASSERT((::GetWindowLong(hWndFirstCtrl, GWL_STYLE) & 0xf) ! 251: == BS_AUTORADIOBUTTON); ! 252: ! 253: if (pDX->m_bSaveAndValidate) ! 254: value = -1; // value if none found ! 255: ! 256: // walk all children in group ! 257: HWND hWndCtrl = hWndFirstCtrl; ! 258: int iButton = 0; ! 259: do ! 260: { ! 261: if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) ! 262: { ! 263: // control in group is a radio button ! 264: if (pDX->m_bSaveAndValidate) ! 265: { ! 266: if (::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) ! 267: { ! 268: ASSERT(value == -1); // only set once ! 269: value = iButton; ! 270: } ! 271: } ! 272: else ! 273: { ! 274: // select button ! 275: ::SendMessage(hWndCtrl, BM_SETCHECK, (iButton == value), 0L); ! 276: } ! 277: iButton++; ! 278: } ! 279: else ! 280: { ! 281: TRACE0("Warning: skipping non-radio button in group\n"); ! 282: } ! 283: hWndCtrl = ::GetNextDlgGroupItem(pDX->m_pDlgWnd->m_hWnd, ! 284: hWndCtrl, FALSE); // get next ! 285: } while (hWndCtrl != hWndFirstCtrl); ! 286: } ! 287: ! 288: ///////////////////////////////////////////////////////////////////////////// ! 289: // Listboxes, comboboxes ! 290: ! 291: void AFXAPI DDX_LBString(CDataExchange* pDX, int nIDC, CString& value) ! 292: { ! 293: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 294: if (pDX->m_bSaveAndValidate) ! 295: { ! 296: int nIndex = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L); ! 297: if (nIndex != -1) ! 298: { ! 299: int nLen = (int)::SendMessage(hWndCtrl, LB_GETTEXTLEN, nIndex, 0L); ! 300: ::SendMessage(hWndCtrl, LB_GETTEXT, nIndex, ! 301: (LPARAM)(LPSTR)value.GetBufferSetLength(nLen)); ! 302: } ! 303: else ! 304: { ! 305: // no selection ! 306: value.Empty(); ! 307: } ! 308: } ! 309: else ! 310: { ! 311: // set current selection based on data string ! 312: if (::SendMessage(hWndCtrl, LB_SELECTSTRING, (WPARAM)-1, ! 313: (LPARAM)(LPCSTR)value) == LB_ERR) ! 314: { ! 315: // no selection match ! 316: TRACE0("Warning: no listbox item selected\n"); ! 317: } ! 318: } ! 319: } ! 320: ! 321: // Win 3.1 only ! 322: void AFXAPI DDX_LBStringExact(CDataExchange* pDX, int nIDC, CString& value) ! 323: { ! 324: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 325: if (pDX->m_bSaveAndValidate) ! 326: { ! 327: DDX_LBString(pDX, nIDC, value); ! 328: } ! 329: else ! 330: { ! 331: // set current selection based on data string ! 332: int i = (int)::SendMessage(hWndCtrl, LB_FINDSTRINGEXACT, (WPARAM)-1, ! 333: (LPARAM)(LPCSTR)value); ! 334: if (i < 0) ! 335: { ! 336: // no selection match ! 337: TRACE0("Warning: no listbox item selected\n"); ! 338: } ! 339: else ! 340: { ! 341: // select it ! 342: SendMessage(hWndCtrl, LB_SETCURSEL, i, 0L); ! 343: } ! 344: } ! 345: } ! 346: ! 347: void AFXAPI DDX_CBString(CDataExchange* pDX, int nIDC, CString& value) ! 348: { ! 349: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 350: if (pDX->m_bSaveAndValidate) ! 351: { ! 352: // just get current edit item text (or drop list static) ! 353: int nLen = ::GetWindowTextLength(hWndCtrl); ! 354: if (nLen != -1) ! 355: { ! 356: // get known length ! 357: ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1); ! 358: } ! 359: else ! 360: { ! 361: // for drop lists GetWindowTextLength does not work - assume ! 362: // max of 255 characters ! 363: ::GetWindowText(hWndCtrl, value.GetBuffer(255), 255+1); ! 364: value.ReleaseBuffer(); ! 365: } ! 366: } ! 367: else ! 368: { ! 369: // set current selection based on model string ! 370: if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1, ! 371: (LPARAM)(LPCSTR)value) == CB_ERR) ! 372: { ! 373: // just set the edit text (will be ignored if DROPDOWNLIST) ! 374: _AfxSmartSetWindowText(hWndCtrl, value); ! 375: } ! 376: } ! 377: } ! 378: ! 379: // Win 3.1 only ! 380: void AFXAPI DDX_CBStringExact(CDataExchange* pDX, int nIDC, CString& value) ! 381: { ! 382: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 383: if (pDX->m_bSaveAndValidate) ! 384: { ! 385: DDX_CBString(pDX, nIDC, value); ! 386: } ! 387: else ! 388: { ! 389: // set current selection based on data string ! 390: int i = (int)::SendMessage(hWndCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, ! 391: (LPARAM)(LPCSTR)value); ! 392: if (i < 0) ! 393: { ! 394: // no selection match ! 395: TRACE0("Warning: no combobox item selected\n"); ! 396: } ! 397: else ! 398: { ! 399: // select it ! 400: SendMessage(hWndCtrl, CB_SETCURSEL, i, 0L); ! 401: } ! 402: } ! 403: } ! 404: ! 405: void AFXAPI DDX_LBIndex(CDataExchange* pDX, int nIDC, int& index) ! 406: { ! 407: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 408: if (pDX->m_bSaveAndValidate) ! 409: index = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L); ! 410: else ! 411: ::SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)index, 0L); ! 412: } ! 413: ! 414: void AFXAPI DDX_CBIndex(CDataExchange* pDX, int nIDC, int& index) ! 415: { ! 416: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 417: if (pDX->m_bSaveAndValidate) ! 418: index = (int)::SendMessage(hWndCtrl, CB_GETCURSEL, 0, 0L); ! 419: else ! 420: ::SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)index, 0L); ! 421: } ! 422: ! 423: ///////////////////////////////////////////////////////////////////////////// ! 424: // Range Dialog Data Validation ! 425: ! 426: static void NEAR PASCAL FailMinMaxWithFormat(CDataExchange* pDX, ! 427: long minVal, long maxVal, const char* pszFormat, UINT nIDPrompt) ! 428: // error string must have '%1' and '%2' strings for min and max values ! 429: // wsprintf formatting uses long values (format should be '%ld' or '%lu') ! 430: { ! 431: ASSERT(pszFormat != NULL); ! 432: ! 433: if (!pDX->m_bSaveAndValidate) ! 434: { ! 435: TRACE0("Warning: initial dialog data is out of range\n"); ! 436: return; // don't stop now ! 437: } ! 438: char szMin[32]; ! 439: char szMax[32]; ! 440: wsprintf(szMin, pszFormat, minVal); ! 441: wsprintf(szMax, pszFormat, maxVal); ! 442: CString prompt; ! 443: AfxFormatString2(prompt, nIDPrompt, szMin, szMax); ! 444: AfxMessageBox(prompt, MB_ICONEXCLAMATION, nIDPrompt); ! 445: prompt.Empty(); // exception prep ! 446: pDX->Fail(); ! 447: } ! 448: ! 449: //NOTE: don't use overloaded function names to avoid type ambiguities ! 450: void AFXAPI DDV_MinMaxInt(CDataExchange* pDX, int value, int minVal, int maxVal) ! 451: { ! 452: ASSERT(minVal <= maxVal); ! 453: if (value < minVal || value > maxVal) ! 454: FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, "%ld", ! 455: AFX_IDP_PARSE_INT_RANGE); ! 456: } ! 457: ! 458: void AFXAPI DDV_MinMaxLong(CDataExchange* pDX, long value, long minVal, long maxVal) ! 459: { ! 460: ASSERT(minVal <= maxVal); ! 461: if (value < minVal || value > maxVal) ! 462: FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, "%ld", ! 463: AFX_IDP_PARSE_INT_RANGE); ! 464: } ! 465: ! 466: void AFXAPI DDV_MinMaxUInt(CDataExchange* pDX, UINT value, UINT minVal, UINT maxVal) ! 467: { ! 468: ASSERT(minVal <= maxVal); ! 469: if (value < minVal || value > maxVal) ! 470: FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, "%lu", ! 471: AFX_IDP_PARSE_INT_RANGE); ! 472: } ! 473: ! 474: void AFXAPI DDV_MinMaxDWord(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal) ! 475: { ! 476: ASSERT(minVal <= maxVal); ! 477: if (value < minVal || value > maxVal) ! 478: FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, "%lu", ! 479: AFX_IDP_PARSE_INT_RANGE); ! 480: } ! 481: ! 482: ///////////////////////////////////////////////////////////////////////////// ! 483: // Max Chars Dialog Data Validation ! 484: ! 485: void AFXAPI DDV_MaxChars(CDataExchange* pDX, CString const& value, int nChars) ! 486: { ! 487: ASSERT(nChars >= 1); // allow them something ! 488: if (pDX->m_bSaveAndValidate && value.GetLength() > nChars) ! 489: { ! 490: char szT[32]; ! 491: wsprintf(szT, "%d", nChars); ! 492: CString prompt; ! 493: AfxFormatString1(prompt, AFX_IDP_PARSE_STRING_SIZE, szT); ! 494: AfxMessageBox(prompt, MB_ICONEXCLAMATION, AFX_IDP_PARSE_STRING_SIZE); ! 495: prompt.Empty(); // exception prep ! 496: pDX->Fail(); ! 497: } ! 498: } ! 499: ! 500: ///////////////////////////////////////////////////////////////////////////// ! 501: // Special DDX_ proc for subclassing controls ! 502: ! 503: void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) ! 504: { ! 505: if (rControl.m_hWnd == NULL) // not subclassed yet ! 506: { ! 507: ASSERT(!pDX->m_bSaveAndValidate); ! 508: HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ! 509: if (!rControl.SubclassWindow(hWndCtrl)) ! 510: { ! 511: ASSERT(FALSE); // possibly trying to subclass twice ? ! 512: AfxThrowNotSupportedException(); ! 513: } ! 514: } ! 515: } ! 516: ! 517: /////////////////////////////////////////////////////////////////////////////
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.