/**************************************************************************** Copyright (c) 1998-1999 Microsoft Corporation Module Name: cplcallingcardps.cpp Author: toddb - 10/06/98 ****************************************************************************/ // Property Sheet stuff for the main page #include "cplPreComp.h" #include "cplCallingCardPS.h" #include "cplSimpleDialogs.h" #include #define MaxCallingCardRuleItems 16 CCallingCardPropSheet::CCallingCardPropSheet(BOOL bNew, BOOL bShowPIN, CCallingCard * pCard, CCallingCards * pCards) { m_bNew = bNew; m_bShowPIN = bShowPIN; m_pCard = pCard; m_pCards = pCards; m_bWasApplied = FALSE; PWSTR pwsz; pwsz = pCard->GetLongDistanceRule(); m_bHasLongDistance = (pwsz && *pwsz); pwsz = pCard->GetInternationalRule(); m_bHasInternational = (pwsz && *pwsz); pwsz = pCard->GetLocalRule(); m_bHasLocal = (pwsz && *pwsz); } CCallingCardPropSheet::~CCallingCardPropSheet() { } LONG CCallingCardPropSheet::DoPropSheet(HWND hwndParent) { CCPAGEDATA aPageData[] = { { this, 0 }, { this, 1 }, { this, 2 }, }; struct { int iDlgID; DLGPROC pfnDlgProc; LPARAM lParam; } aData[] = { { IDD_CARD_GENERAL, CCallingCardPropSheet::General_DialogProc, (LPARAM)this }, { IDD_CARD_LONGDISTANCE, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[0] }, { IDD_CARD_INTERNATIONAL, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[1] }, { IDD_CARD_LOCALCALLS, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[2] }, }; PROPSHEETHEADER psh; PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp[ARRAYSIZE(aData)]; // Initialize the header: psh.dwSize = sizeof(psh); psh.dwFlags = PSH_DEFAULT; psh.hwndParent = hwndParent; psh.hInstance = GetUIInstance(); psh.hIcon = NULL; psh.pszCaption = MAKEINTRESOURCE(m_bNew?IDS_NEWCALLINGCARD:IDS_EDITCALLINGCARD); psh.nPages = ARRAYSIZE(aData); psh.nStartPage = 0; psh.pfnCallback = NULL; psh.phpage = hpsp; // Now setup the Property Sheet Page psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT; psp.hInstance = GetUIInstance(); for (int i=0; ilParam); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pthis); return pthis->General_OnInitDialog(hwndDlg); case WM_COMMAND: pthis->General_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam ); return 1; case WM_NOTIFY: return pthis->General_OnNotify(hwndDlg, (LPNMHDR)lParam); case WM_HELP: // Process clicks on controls after Context Help mode selected WinHelp ((HWND)((LPHELPINFO)lParam)->hItemHandle, gszHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPTSTR) a105HelpIDs); break; case WM_CONTEXTMENU: // Process right-clicks on controls WinHelp ((HWND) wParam, gszHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID) a105HelpIDs); break; } return 0; } BOOL CCallingCardPropSheet::General_OnInitDialog(HWND hwndDlg) { // Set all the edit controls to the inital values HWND hwnd; TCHAR szText[MAX_INPUT]; hwnd = GetDlgItem(hwndDlg,IDC_CARDNAME); SHUnicodeToTChar(m_pCard->GetCardName(), szText, ARRAYSIZE(szText)); SetWindowText(hwnd, szText); SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0); hwnd = GetDlgItem(hwndDlg,IDC_CARDNUMBER); SHUnicodeToTChar(m_pCard->GetAccountNumber(), szText, ARRAYSIZE(szText)); SetWindowText(hwnd, szText); SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0); LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE); hwnd = GetDlgItem(hwndDlg,IDC_PIN); if(m_bShowPIN) { SHUnicodeToTChar(m_pCard->GetPIN(), szText, ARRAYSIZE(szText)); SetWindowText(hwnd, szText); } SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0); LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE); SetTextForRules(hwndDlg); return 1; } void CCallingCardPropSheet::SetTextForRules(HWND hwndDlg) { TCHAR szText[512]; int iDlgID = IDC_CARDUSAGE1; if ( m_bHasLongDistance ) { // load the "dialing long distance calls." string LoadString(GetUIInstance(), IDS_DIALING_LD_CALLS, szText, ARRAYSIZE(szText)); SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText); iDlgID++; } if ( m_bHasInternational ) { // load the "dialing international calls." string LoadString(GetUIInstance(), IDS_DIALING_INT_CALLS, szText, ARRAYSIZE(szText)); SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText); iDlgID++; } if ( m_bHasLocal ) { // load the "dialing local calls." string LoadString(GetUIInstance(), IDS_DIALING_LOC_CALLS, szText, ARRAYSIZE(szText)); SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText); iDlgID++; } if ( IDC_CARDUSAGE1 == iDlgID ) { // load the "there are no rules defined for this card" string LoadString(GetUIInstance(),IDS_NOCCRULES,szText,ARRAYSIZE(szText)); SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText); iDlgID++; } while (iDlgID <= IDC_CARDUSAGE3) { SetWindowText(GetDlgItem(hwndDlg,iDlgID), TEXT("")); iDlgID++; } } BOOL CCallingCardPropSheet::General_OnCommand(HWND hwndParent, int wID, int wNotifyCode, HWND hwndCrl) { switch ( wID ) { case IDC_CARDNAME: case IDC_CARDNUMBER: case IDC_PIN: switch (wNotifyCode) { case EN_CHANGE: SendMessage(GetParent(hwndParent),PSM_CHANGED,(WPARAM)hwndParent,0); break; default: break; } break; default: break; } return 0; } BOOL CCallingCardPropSheet::General_OnNotify(HWND hwndDlg, LPNMHDR pnmhdr) { // The only notifies we should receive are from the property sheet switch (pnmhdr->code) { case PSN_APPLY: // user pressed OK or Apply // update all the strings HideToolTip(); return Gerneral_OnApply(hwndDlg); case PSN_RESET: // user pressed Cancel HideToolTip(); break; case PSN_SETACTIVE: // user is switching pages // the user might have added some rules since switching pages so we // need to update the text fields that show which rules are set. SetTextForRules(hwndDlg); HideToolTip(); break; } return 0; } BOOL CCallingCardPropSheet::Gerneral_OnApply(HWND hwndDlg) { HWND hwnd; DWORD dwStatus; PWSTR pwszOldCardNumber; PWSTR pwszOldPinNumber; WCHAR wsz[MAX_INPUT]; TCHAR szText[MAX_INPUT]; LOG((TL_TRACE, "Gerneral_OnApply: -- enter")); // In order for this to work, I have to first store the new rules into the // m_pCard object. Each page that has been created must be asked to generate // it's rule. We do this in response to the PSM_QUERYSIBLINGS command. // Unfortunately, we have to first store a copy of all the data we're about to // change. That way, if the validation fails we can return the CallingCard // object to it's original value (so if the user then presses cancel it will // be in the correct state). // cache the current values for the rules and access numbers pwszOldCardNumber = ClientAllocString(m_pCard->GetAccountNumber()); pwszOldPinNumber = ClientAllocString(m_pCard->GetPIN()); // now update the object with the value we are about to test. hwnd = GetDlgItem(hwndDlg,IDC_CARDNUMBER); GetWindowText(hwnd, szText, ARRAYSIZE(szText)); SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz)); m_pCard->SetAccountNumber(wsz); hwnd = GetDlgItem(hwndDlg,IDC_PIN); GetWindowText(hwnd, szText, ARRAYSIZE(szText)); SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz)); m_pCard->SetPIN(wsz); // let the other pages update thier values PropSheet_QuerySiblings(GetParent(hwndDlg),0,0); // Now we can validate the card. dwStatus = m_pCard->Validate(); if ( dwStatus ) { int iStrID; int iDlgItem; int iDlgID = 0; // Set the current values for the rules and access numbers to our cached values. // This is required in case the user later decides to cancel instead of appling. m_pCard->SetAccountNumber(pwszOldCardNumber); m_pCard->SetPIN(pwszOldPinNumber); ClientFree( pwszOldCardNumber ); ClientFree( pwszOldPinNumber ); // Something isn't right, figure out what. The order we check these // in depends on which tab the error would need to be fixed from. // First we check the items that get fixed on the general tab. if ( dwStatus & (CCVF_NOCARDNAME|CCVF_NOCARDNUMBER|CCVF_NOPINNUMBER) ) { if ( dwStatus & CCVF_NOCARDNAME ) { iStrID = IDS_MUSTENTERCARDNAME; iDlgItem = IDC_CARDNAME; } else if ( dwStatus & CCVF_NOCARDNUMBER ) { iStrID = IDS_MUSTENTERCARDNUMBER; iDlgItem = IDC_CARDNUMBER; } else { iStrID = IDS_MUSTENTERPINNUMBER; iDlgItem = IDC_PIN; } iDlgID = IDD_CARD_GENERAL; } else if ( dwStatus & CCVF_NOCARDRULES ) { // For this problem we stay on whatever page we are already on // since this problem can be fixed on one of three different pages. iStrID = IDS_NORULESFORTHISCARD; } else if ( dwStatus & CCVF_NOLONGDISTANCEACCESSNUMBER ) { iStrID = IDS_NOLONGDISTANCEACCESSNUMBER; iDlgID = IDD_CARD_LONGDISTANCE; iDlgItem = IDC_LONGDISTANCENUMBER; } else if ( dwStatus & CCVF_NOINTERNATIONALACCESSNUMBER ) { iStrID = IDS_NOINTERNATIONALACCESSNUMBER; iDlgID = IDD_CARD_INTERNATIONAL; iDlgItem = IDC_INTERNATIONALNUMBER; } else if ( dwStatus & CCVF_NOLOCALACCESSNUMBER ) { iStrID = IDS_NOLOCALACCESSNUMBER; iDlgID = IDD_CARD_LOCALCALLS; iDlgItem = IDC_LOCALNUMBER; } hwnd = GetParent(hwndDlg); if ( iDlgID ) { PropSheet_SetCurSelByID(hwnd,iDlgID); hwnd = PropSheet_GetCurrentPageHwnd(hwnd); hwnd = GetDlgItem(hwnd,iDlgItem); } else { hwnd = hwndDlg; } ShowErrorMessage(hwnd, iStrID); SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE); return TRUE; } // Check for the calling card name being unique TCHAR szNone[MAX_INPUT]; LoadString(GetUIInstance(),IDS_NONE, szNone, ARRAYSIZE(szNone)); hwnd = GetDlgItem(hwndDlg,IDC_CARDNAME); GetWindowText(hwnd, szText, ARRAYSIZE(szText)); if ( 0 == StrCmpIW(szText, szNone) ) { goto buggeroff; } SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz)); CCallingCard * pCard; m_pCards->Reset(TRUE); // TRUE means show "hidden" cards, FALSE means hide them while ( S_OK == m_pCards->Next(1,&pCard,NULL) ) { // hidden cards shall remain hidden for ever so we don't check names against those if ( !pCard->IsMarkedHidden() ) { // Card0 is the "None (Direct Dial)" card which we don't want to consider if ( 0 != pCard->GetCardID() ) { // we don't want to consider ourself either if ( pCard->GetCardID() != m_pCard->GetCardID() ) { // see if the names are identical if ( 0 == StrCmpIW(pCard->GetCardName(), wsz) ) { // yes, the name is in conflict buggeroff: // return altered values to original state m_pCard->SetAccountNumber(pwszOldCardNumber); m_pCard->SetPIN(pwszOldPinNumber); ClientFree( pwszOldCardNumber ); ClientFree( pwszOldPinNumber ); // display an error message hwnd = GetParent(hwndDlg); PropSheet_SetCurSelByID(hwnd,IDD_CARD_GENERAL); hwnd = PropSheet_GetCurrentPageHwnd(hwnd); hwnd = GetDlgItem(hwnd,IDC_CARDNAME); ShowErrorMessage(hwnd, IDS_NEEDUNIQUECARDNAME); SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE); return TRUE; } } } } } // card name doesn't conflict, update it. m_pCard->SetCardName(wsz); m_bWasApplied = TRUE; ClientFree( pwszOldCardNumber ); ClientFree( pwszOldPinNumber ); return 0; } // ******************************************************************** // // LONG DISTANCE, INTERNATIONAL, and LOCAL pages // // ******************************************************************** INT_PTR CALLBACK CCallingCardPropSheet::DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CCPAGEDATA * pPageData = (CCPAGEDATA *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch(uMsg) { case WM_INITDIALOG: pPageData = (CCPAGEDATA*)(((PROPSHEETPAGE*)lParam)->lParam); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)pPageData); return pPageData->pthis->OnInitDialog(hwndDlg,pPageData->iWhichPage); case WM_COMMAND: pPageData->pthis->OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam, pPageData->iWhichPage); return 1; case WM_NOTIFY: return pPageData->pthis->OnNotify(hwndDlg, (LPNMHDR)lParam,pPageData->iWhichPage); case PSM_QUERYSIBLINGS: return pPageData->pthis->UpdateRule(hwndDlg,pPageData->iWhichPage); case WM_DESTROY: return pPageData->pthis->OnDestroy(hwndDlg); #define aIDs ((pPageData->iWhichPage==0)?a106HelpIDs:((pPageData->iWhichPage==1)?a107HelpIDs:a108HelpIDs)) case WM_HELP: // Process clicks on controls after Context Help mode selected WinHelp ((HWND)((LPHELPINFO)lParam)->hItemHandle, gszHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPTSTR) aIDs); break; case WM_CONTEXTMENU: // Process right-clicks on controls WinHelp ((HWND) wParam, gszHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID) aIDs); break; #undef aIDs } return 0; } void GetDescriptionForRule(PWSTR pwszRule, PTSTR szText, UINT cchText) { switch (*pwszRule) { case L',': { // Check if all characters are commas. If they are not, fall through to the // "dial the specified digits" case if(HasOnlyCommasW(pwszRule)) { // add a "wait for x seconds" rule. Each consecutive ',' adds two seconds to x. int iSecondsToWait = lstrlenW(pwszRule)*2; TCHAR szFormat[256]; LPTSTR aArgs[] = {(LPTSTR)UIntToPtr(iSecondsToWait)}; LoadString(GetUIInstance(),IDS_WAITFORXSECONDS, szFormat, ARRAYSIZE(szFormat)); FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, szFormat, 0,0, szText, cchText, (va_list *)aArgs ); break; } } // ATTENTION !! // Fall through case L'0': case L'1': case L'2': case L'3': case L'4': case L'5': case L'6': case L'7': case L'8': case L'9': case L'A': case L'a': case L'B': case L'b': case L'C': case L'c': case L'D': case L'd': case L'#': case L'*': case L'+': case L'!': { // Add a "dial the specified digits" rule. The whole sequence of these digits should // be considered to be one rule. TCHAR szRule[MAX_INPUT]; TCHAR szFormat[MAX_INPUT]; TCHAR szTemp[MAX_INPUT*2]; // big enough for the rule and the format LPTSTR aArgs[] = {szRule}; SHUnicodeToTChar(pwszRule, szRule, ARRAYSIZE(szRule)); LoadString(GetUIInstance(),IDS_DIALX, szFormat, ARRAYSIZE(szFormat)); // The formated message might be larger than cchText, in which case we just // want to truncate the result. FormatMessage would simply fail in that case // so we format to a larger buffer and then truncate down. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, szFormat, 0,0, szTemp, ARRAYSIZE(szTemp), (va_list *)aArgs )) { StrCpyN(szText, szTemp, cchText); } else { szText[0] = 0; } } break; default: { int iStrID; switch (*pwszRule) { case L'J': // add a "dial the access number" rule. iStrID = IDS_DIALACCESSNUMBER; break; case L'K': // add a "dial the account number" rule. iStrID = IDS_DIALACOUNTNUMBER; break; case L'H': // add a "dial the pin number" rule. iStrID = IDS_DIALPINNUMBER; break; case L'W': // add a "Wait for dial tone" rule. iStrID = IDS_WAITFORDIALTONE; break; case L'@': // add a "Wait for quiet" rule. iStrID = IDS_WAITFORQUIET; break; case L'E': case L'F': case L'G': // add a "dial the destination number" rule. We look for these three letters together. // Only certain combinations of these letters are valid, as indicated below: if ( 0 == StrCmpW(pwszRule, L"EFG") ) { iStrID = IDS_DIAL_CCpACpNUM; } else if ( 0 == StrCmpW(pwszRule, L"EG") ) { iStrID = IDS_DIAL_CCpNUM; } else if ( 0 == StrCmpW(pwszRule, L"FG") ) { iStrID = IDS_DIAL_ACpNUM; } else if ( 0 == StrCmpW(pwszRule, L"E") ) { iStrID = IDS_DIAL_CC; } else if ( 0 == StrCmpW(pwszRule, L"F") ) { iStrID = IDS_DIAL_AC; } else if ( 0 == StrCmpW(pwszRule, L"G") ) { iStrID = IDS_DIAL_NUM; } break; default: // We shouldn't be able to get here" LOG((TL_ERROR, "Invalid calling card rule")); szText[0] = NULL; return; } LoadString(GetUIInstance(), iStrID, szText, cchText); } break; } } void PopulateStepList(HWND hwndList, PWSTR pwszRuleList) { TCHAR szText[MAX_INPUT]; WCHAR wch; PWSTR pwsz; int i = 0; // Parse the string into a series of rules. There are only types of rules that we should see // in a calling card sting: // J dial the access number // K dial the account number // H dial the pin number // 0-9,#,*,+,!,ABCD Dial the digits directly // W Wait for dial tone // @ Wait for quiet // , Wait for two seconds // E Dial the counrty code // F Dial the area code // G Dial the local number (prefix and root) // We copy the characters for the given rule into a buffer. Then we allocate a heap // buffer into which these characters get copied. Each list view item tracks one of // these character buffers in it's lParam data. LOG((TL_INFO, "Rule to process (%ls)",pwszRuleList)); while ( *pwszRuleList ) { switch (*pwszRuleList) { case L'J': // add a "dial the access number" rule. case L'K': // add a "dial the account number" rule. case L'H': // add a "dial the pin number" rule. case L'W': // add a "Wait for dial tone" rule. case L'@': // add a "Wait for quiet" rule. // These are all the one character rules. pwsz = pwszRuleList+1; LOG((TL_INFO, "JKHW@ case (%ls) <%p>",pwsz,pwsz)); break; case L'E': case L'F': case L'G': // add a "dial the destination number" rule. We look for these three letters together. // If we find a consecutive group of these digits then we treat them as one rule. Only // a few combinations of these letters are actually valid rules. If we find some other // combination then we must treat it as a seperate rule instead of a single rule. We // start by looking for the longest valid rules and then check for the shorter ones. if ( 0 == StrCmpNW(pwszRuleList, L"EFG", 3) ) { pwsz = pwszRuleList+3; } else if ( 0 == StrCmpNW(pwszRuleList, L"EG", 2) ) { pwsz = pwszRuleList+2; } else if ( 0 == StrCmpNW(pwszRuleList, L"FG", 2) ) { pwsz = pwszRuleList+2; } else { pwsz = pwszRuleList+1; } LOG((TL_INFO, "EFG case (%ls)",pwsz)); break; case L',': // add a "wait for x seconds" rule. Each consecutive , adds two seconds to x. pwsz = pwszRuleList+1; while ( *(pwsz) == L',' ) { pwsz++; } break; case L'0': case L'1': case L'2': case L'3': case L'4': case L'5': case L'6': case L'7': case L'8': case L'9': case L'A': case L'a': case L'B': case L'b': case L'C': case L'c': case L'D': case L'd': case L'#': case L'*': case L'+': case L'!': // Add a "dial the specified digits" rule. The whole sequence of these digits should // be considered to be one rule. pwsz = pwszRuleList+1; while ( ((*pwsz >= L'0') && (*pwsz <= L'9')) || ((*pwsz >= L'A') && (*pwsz <= L'D')) || ((*pwsz >= L'a') && (*pwsz <= L'd')) || (*pwsz == L'#') || (*pwsz == L'*') || (*pwsz == L'+') || (*pwsz == L'!') ) { pwsz++; } LOG((TL_INFO, "0-9,A-D,#,*,+,! case (%ls)", pwsz)); break; default: // We shouldn't be able to get here LOG((TL_ERROR, "Invalid calling card rule")); // we just ignore this character and go back to the while loop. Yes, this is a continue // inside a switch inside a while loop. A bit confusing, perhaps, but it's what we want. pwszRuleList++; continue; } // we temporarily stick a NULL into wpszRuleList to seperate out one rule wch = *pwsz; *pwsz = NULL; // for each rule, add a list box entry LVITEM lvi; lvi.mask = LVIF_TEXT|LVIF_PARAM; lvi.iItem = i++; lvi.iSubItem = 0; lvi.pszText = szText; lvi.lParam = (LPARAM)ClientAllocString(pwszRuleList); GetDescriptionForRule(pwszRuleList, szText, ARRAYSIZE(szText)); LOG((TL_INFO, "Description for (%ls) is (%s)", pwszRuleList,szText)); ListView_InsertItem(hwndList, &lvi); // restore pwszRuleList to it's former state before continuing or this is going to be a real short ride. pwsz[0] = wch; // after the above restoration, pwsz points to the head of the next rule (or to a NULL) pwszRuleList = pwsz; } } BOOL CCallingCardPropSheet::OnInitDialog(HWND hwndDlg, int iPage) { LOG((TL_TRACE, "OnInitDialog <%d>",iPage)); PWSTR pwsz; RECT rc; HWND hwnd = GetDlgItem(hwndDlg, IDC_LIST); GetClientRect(hwnd, &rc); LVCOLUMN lvc; lvc.mask = LVCF_SUBITEM | LVCF_WIDTH; lvc.iSubItem = 0; lvc.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL); ListView_InsertColumn( hwnd, 0, &lvc ); ListView_SetExtendedListViewStyleEx(hwnd, LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT, LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT); switch ( iPage ) { case 0: pwsz = m_pCard->GetLongDistanceRule(); break; case 1: pwsz = m_pCard->GetInternationalRule(); break; case 2: pwsz = m_pCard->GetLocalRule(); break; default: LOG((TL_ERROR, "OnInitDialog: Invalid page ID %d, failing.", iPage)); return -1; } PopulateStepList(hwnd, pwsz); int iDlgItem; switch (iPage) { case 0: iDlgItem = IDC_LONGDISTANCENUMBER; pwsz = m_pCard->GetLongDistanceAccessNumber(); break; case 1: iDlgItem = IDC_INTERNATIONALNUMBER; pwsz = m_pCard->GetInternationalAccessNumber(); break; case 2: iDlgItem = IDC_LOCALNUMBER; pwsz = m_pCard->GetLocalAccessNumber(); break; } TCHAR szText[MAX_INPUT]; hwnd = GetDlgItem(hwndDlg,iDlgItem); SHUnicodeToTChar(pwsz, szText, ARRAYSIZE(szText)); SetWindowText(hwnd, szText); SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0); LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE); // disable the buttons since no item is selected by default SetButtonStates(hwndDlg,-1); return 0; } BOOL CCallingCardPropSheet::OnCommand(HWND hwndParent, int wID, int wNotifyCode, HWND hwndCrl, int iPage) { HWND hwndList = GetDlgItem(hwndParent, IDC_LIST); switch ( wID ) { case IDC_LONGDISTANCENUMBER: case IDC_INTERNATIONALNUMBER: case IDC_LOCALNUMBER: if (EN_CHANGE == wNotifyCode) { SendMessage(GetParent(hwndParent),PSM_CHANGED,(WPARAM)hwndParent,0); } break; case IDC_MOVEUP: case IDC_MOVEDOWN: case IDC_REMOVE: { TCHAR szText[MAX_INPUT]; int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); if (-1 != iSelected) { LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = iSelected; lvi.iSubItem = 0; lvi.pszText = szText; lvi.cchTextMax = ARRAYSIZE(szText); ListView_GetItem(hwndList, &lvi); ListView_DeleteItem(hwndList, iSelected); if ( IDC_MOVEDOWN == wID ) { iSelected++; } else { iSelected--; } if ( IDC_REMOVE == wID ) { ClientFree( (PWSTR)lvi.lParam ); if ( ListView_GetItemCount(hwndList) > 0 ) { if (-1 == iSelected) iSelected = 0; ListView_SetItemState(hwndList, iSelected, LVIS_SELECTED, LVIS_SELECTED); } else { // the last rule was deleted, update the "has rule" state switch (iPage) { case 0: m_bHasLongDistance = FALSE; break; case 1: m_bHasInternational = FALSE; break; case 2: m_bHasLocal = FALSE; break; } if ( GetFocus() == hwndCrl ) { HWND hwndDef = GetDlgItem(hwndParent,IDC_ACCESSNUMBER); SendMessage(hwndCrl, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0)); SendMessage(hwndDef, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0)); SetFocus(hwndDef); } EnableWindow(hwndCrl,FALSE); } } else { lvi.mask |= LVIF_STATE; lvi.iItem = iSelected; lvi.state = lvi.stateMask = LVIS_SELECTED; iSelected = ListView_InsertItem(hwndList, &lvi); } ListView_EnsureVisible(hwndList, iSelected, FALSE); } SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0); } break; case IDC_ACCESSNUMBER: case IDC_PIN: case IDC_CARDNUMBER: case IDC_DESTNUMBER: case IDC_WAITFOR: case IDC_SPECIFYDIGITS: { TCHAR szText[MAX_INPUT]; WCHAR wszRule[MAX_INPUT]; int iItem = ListView_GetItemCount(hwndList); LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = iItem; lvi.iSubItem = 0; lvi.pszText = szText; switch ( wID ) { case IDC_ACCESSNUMBER: lvi.lParam = (LPARAM)ClientAllocString(L"J"); break; case IDC_PIN: lvi.lParam = (LPARAM)ClientAllocString(L"H"); break; case IDC_CARDNUMBER: lvi.lParam = (LPARAM)ClientAllocString(L"K"); break; case IDC_DESTNUMBER: { CDestNumDialog dnd(iPage==1, iPage!=2); INT_PTR iRes = dnd.DoModal(hwndParent); if (iRes == (INT_PTR)IDOK) { lvi.lParam = (LPARAM)ClientAllocString(dnd.GetResult()); } else { return 0; } } break; case IDC_WAITFOR: { CWaitForDialog wd; INT_PTR ipRes = wd.DoModal(hwndParent); if (ipRes == (INT_PTR)IDOK) { int iRes; iRes = wd.GetWaitType(); LOG((TL_INFO, "WaitType is %d", iRes)); switch (iRes) { case 0: lvi.lParam = (LPARAM)ClientAllocString(L"W"); break; case 1: lvi.lParam = (LPARAM)ClientAllocString(L"@"); break; default: iRes = iRes/2; if ( ARRAYSIZE(wszRule) <= iRes ) { iRes = ARRAYSIZE(wszRule)-1; } for (int i=0; i0); EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEDOWN), (-1!=iItem) && (ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_LIST))-1)!=iItem); EnableWindow(GetDlgItem(hwndDlg,IDC_REMOVE), -1!=iItem); } BOOL CCallingCardPropSheet::OnNotify(HWND hwndDlg, LPNMHDR pnmhdr, int iPage) { switch ( pnmhdr->idFrom ) { case IDC_LIST: #define pnmlv ((LPNMLISTVIEW)pnmhdr) switch (pnmhdr->code) { case LVN_ITEMCHANGED: if (pnmlv->uChanged & LVIF_STATE) { if (pnmlv->uNewState & LVIS_SELECTED) { SetButtonStates(hwndDlg,pnmlv->iItem); } else { SetButtonStates(hwndDlg,-1); } } break; default: break; } break; #undef pnmlv default: switch (pnmhdr->code) { case PSN_APPLY: // user pressed OK or Apply LOG((TL_INFO, "OnApply <%d>", iPage)); case PSN_RESET: // user pressed Cancel case PSN_KILLACTIVE: // user is switching pages HideToolTip(); break; } break; } return 0; } BOOL CCallingCardPropSheet::UpdateRule(HWND hwndDlg, int iPage) { LOG((TL_TRACE, "UpdateRule <%d>",iPage)); WCHAR wszRule[1024]; PWSTR pwsz = wszRule; HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST); // in case there are no rules, we need to NULL the string wszRule[0] = L'\0'; // add up all the items in the list and set the correct string int iItems = ListView_GetItemCount(hwnd); if (iItems > MaxCallingCardRuleItems) iItems = MaxCallingCardRuleItems; LVITEM lvi; HRESULT hr = S_OK; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (int i=0; iSetLongDistanceRule(wszRule); iDlgItem = IDC_LONGDISTANCENUMBER; break; case 1: m_pCard->SetInternationalRule(wszRule); iDlgItem = IDC_INTERNATIONALNUMBER; break; case 2: m_pCard->SetLocalRule(wszRule); iDlgItem = IDC_LOCALNUMBER; break; } TCHAR szText[MAX_INPUT]; hwnd = GetDlgItem(hwndDlg,iDlgItem); GetWindowText(hwnd, szText, ARRAYSIZE(szText)); SHTCharToUnicode(szText, wszRule, ARRAYSIZE(wszRule)); switch(iPage) { case 0: m_pCard->SetLongDistanceAccessNumber(wszRule); break; case 1: m_pCard->SetInternationalAccessNumber(wszRule); break; case 2: m_pCard->SetLocalAccessNumber(wszRule); break; } return 0; } BOOL CCallingCardPropSheet::OnDestroy(HWND hwndDlg) { HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST); // Free the memory we allocated and track in the list view int iItems = ListView_GetItemCount(hwnd); LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (int i=0; i