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.
 
 
 
 
 
 

1264 lines
39 KiB

/****************************************************************************
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 <strsafe.h>
#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; i<ARRAYSIZE(aData); i++)
{
psp.pszTemplate = MAKEINTRESOURCE(aData[i].iDlgID);
psp.pfnDlgProc = aData[i].pfnDlgProc;
psp.lParam = aData[i].lParam;
hpsp[i] = CreatePropertySheetPage( &psp );
}
PropertySheet( &psh );
return m_bWasApplied?PSN_APPLY:PSN_RESET;
}
// ********************************************************************
//
// GENERAL page
//
// ********************************************************************
INT_PTR CALLBACK CCallingCardPropSheet::General_DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CCallingCardPropSheet* pthis = (CCallingCardPropSheet*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
switch(uMsg)
{
case WM_INITDIALOG:
pthis = (CCallingCardPropSheet*)(((PROPSHEETPAGE*)lParam)->lParam);
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; i<iRes; i++)
{
wszRule[i] = L',';
}
wszRule[i] = NULL;
lvi.lParam = (LPARAM)ClientAllocString(wszRule);
break;
}
}
else
{
return 0;
}
}
break;
case IDC_SPECIFYDIGITS:
{
CEditDialog ed;
WCHAR *pwcSrc, *pwcDest;
INT_PTR iRes = ed.DoModal(hwndParent, IDS_SPECIFYDIGITS, IDS_TYPEDIGITS, IDS_DIGITS,
LIF_ALLOWNUMBER|LIF_ALLOWPOUND|LIF_ALLOWSTAR|LIF_ALLOWSPACE|LIF_ALLOWCOMMA|LIF_ALLOWPLUS|LIF_ALLOWBANG|LIF_ALLOWATOD);
if (iRes == (INT_PTR)IDOK)
{
SHTCharToUnicode(ed.GetString(), wszRule, ARRAYSIZE(wszRule));
// Strip the spaces
pwcSrc = wszRule;
pwcDest = wszRule;
do
{
if(*pwcSrc != TEXT(' ')) // including the NULL
*pwcDest++ = *pwcSrc;
} while(*pwcSrc++);
if (!wszRule[0])
return 0;
lvi.lParam = (LPARAM)ClientAllocString(wszRule);
}
else
{
return 0;
}
}
break;
}
if (NULL != lvi.lParam)
{
GetDescriptionForRule((PWSTR)lvi.lParam, szText, ARRAYSIZE(szText));
iItem = ListView_InsertItem(hwndList, &lvi);
ListView_EnsureVisible(hwndList, iItem, FALSE);
}
// a new rule was added, update the "has rule" state
switch (iPage)
{
case 0:
m_bHasLongDistance = TRUE;
break;
case 1:
m_bHasInternational = TRUE;
break;
case 2:
m_bHasLocal = TRUE;
break;
}
// update the property sheet state
SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0);
}
break;
default:
break;
}
return 0;
}
void CCallingCardPropSheet::SetButtonStates(HWND hwndDlg, int iItem)
{
EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEUP), iItem>0);
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; i<iItems && SUCCEEDED(hr); i++)
{
lvi.iItem = i;
ListView_GetItem(hwnd, &lvi);
hr = StringCchCatExW(pwsz, 1024, (PWSTR)lvi.lParam, NULL, NULL, STRSAFE_NO_TRUNCATION);
LOG((TL_INFO, "UpdateRule\tRule %d: %ls %s", i, lvi.lParam, FAILED(hr)?"FAILED":"SUCCEEDED"));
}
int iDlgItem;
switch(iPage)
{
case 0:
m_pCard->SetLongDistanceRule(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<iItems; i++)
{
lvi.iItem = i;
ListView_GetItem(hwnd, &lvi);
ClientFree((PWSTR)lvi.lParam);
}
return TRUE;
}
BOOL HasOnlyCommasW(PWSTR pwszStr)
{
while(*pwszStr)
if(*pwszStr++ != L',')
return FALSE;
return TRUE;
}