Annotation of mstools/mfc/src/dlgdata.cpp, revision 1.1.1.1

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: /////////////////////////////////////////////////////////////////////////////

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.