windows-nt/Source/XPSP1/NT/net/rras/ras/ui/rasdlg/alternat.c
2020-09-26 16:20:57 +08:00

1449 lines
34 KiB
C

// Copyright (c) 1997, Microsoft Corporation, all rights reserved
//
// alternat.c
// Remote Access Common Dialog APIs
// Alternate phone number dialogs
//
// 11/06/97 Steve Cobb
#include "rasdlgp.h"
//----------------------------------------------------------------------------
// Help maps
//----------------------------------------------------------------------------
static DWORD g_adwAnHelp[] =
{
CID_AN_ST_Explain, HID_AN_ST_Explain,
CID_AN_ST_Numbers, HID_AN_LV_Numbers,
CID_AN_LV_Numbers, HID_AN_LV_Numbers,
CID_AN_PB_Up, HID_AN_PB_Up,
CID_AN_PB_Down, HID_AN_PB_Down,
CID_AN_PB_Add, HID_AN_PB_Add,
CID_AN_PB_Edit, HID_AN_PB_Edit,
CID_AN_PB_Delete, HID_AN_PB_Delete,
CID_AN_CB_MoveToTop, HID_AN_CB_MoveToTop,
CID_AN_CB_TryNextOnFail, HID_AN_CB_TryNextOnFail,
0, 0
};
static DWORD g_adwCeHelp[] =
{
CID_CE_GB_PhoneNumber, HID_CE_GB_PhoneNumber,
CID_CE_ST_AreaCodes, HID_CE_CLB_AreaCodes,
CID_CE_CLB_AreaCodes, HID_CE_CLB_AreaCodes,
CID_CE_ST_PhoneNumber, HID_CE_EB_PhoneNumber,
CID_CE_EB_PhoneNumber, HID_CE_EB_PhoneNumber,
CID_CE_ST_CountryCodes, HID_CE_LB_CountryCodes,
CID_CE_LB_CountryCodes, HID_CE_LB_CountryCodes,
CID_CE_GB_Comment, HID_CE_GB_Comment,
CID_CE_EB_Comment, HID_CE_EB_Comment,
CID_CE_CB_UseDialingRules, HID_CE_CB_UseDialingRules,
0, 0
};
//----------------------------------------------------------------------------
// Local datatypes
//----------------------------------------------------------------------------
// Alternate Phone Number dialog argument block.
//
typedef struct
_ANARGS
{
DTLNODE* pLinkNode;
DTLLIST* pListAreaCodes;
}
ANARGS;
// Alternate Phone Number dialog context block.
//
typedef struct
_ANINFO
{
// Caller's arguments to the dialog.
//
ANARGS* pArgs;
// Handle of this dialog and some of it's controls.
//
HWND hwndDlg;
HWND hwndLv;
HWND hwndPbUp;
HWND hwndPbDown;
HWND hwndPbAdd;
HWND hwndPbEdit;
HWND hwndPbDelete;
HWND hwndCbTryNext;
HWND hwndCbMoveToTop;
HWND hwndPbOk;
// Up/down arrow icons.
//
HANDLE hiconUpArr;
HANDLE hiconDnArr;
HANDLE hiconUpArrDis;
HANDLE hiconDnArrDis;
// The state to display in the "move to top" checkbox should it be
// enabled.
//
BOOL fMoveToTop;
// Link node containing edited phone number list and check box settings
// and a shortcut to the contained link.
//
DTLNODE* pNode;
PBLINK* pLink;
// List of area codes passed to CuInit plus all strings retrieved with
// CuGetInfo. The list is an editing duplicate of the one in 'pArgs'.
//
DTLLIST* pListAreaCodes;
}
ANINFO;
// Phone number editor dialog argument block
//
typedef struct
_CEARGS
{
DTLNODE* pPhoneNode;
DTLLIST* pListAreaCodes;
DWORD sidTitle;
}
CEARGS;
// Phone number editor dialog context block.
//
typedef struct
_CEINFO
{
// Caller's arguments to the dialog.
//
CEARGS* pArgs;
// Handle of this dialog and some of it's controls.
//
HWND hwndDlg;
HWND hwndStAreaCodes;
HWND hwndClbAreaCodes;
HWND hwndEbPhoneNumber;
HWND hwndLbCountryCodes;
HWND hwndStCountryCodes;
HWND hwndCbUseDialingRules;
HWND hwndEbComment;
// Phone node containing edited phone number settings and a shortcut to
// the contained PBPHONE.
//
DTLNODE* pNode;
PBPHONE* pPhone;
// List of area codes passed to CuInit plus all strings retrieved with
// CuGetInfo. The list is an editing duplicate of the one in 'pArgs'.
//
DTLLIST* pListAreaCodes;
// Area-code and country-code helper context block, and a flag indicating
// if the block has been initialized.
//
CUINFO cuinfo;
BOOL fCuInfoInitialized;
}
CEINFO;
//-----------------------------------------------------------------------------
// Local prototypes (alphabetically)
//-----------------------------------------------------------------------------
VOID
AnAddNumber(
IN ANINFO* pInfo );
BOOL
AnCommand(
IN ANINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
AnDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
VOID
AnDeleteNumber(
IN ANINFO* pInfo );
VOID
AnEditNumber(
IN ANINFO* pInfo );
VOID
AnFillLv(
IN ANINFO* pInfo,
IN DTLNODE* pNodeToSelect );
BOOL
AnInit(
IN HWND hwndDlg,
IN ANARGS* pArgs );
VOID
AnInitLv(
IN ANINFO* pInfo );
VOID
AnListFromLv(
IN ANINFO* pInfo );
LVXDRAWINFO*
AnLvCallback(
IN HWND hwndLv,
IN DWORD dwItem );
VOID
AnMoveNumber(
IN ANINFO* pInfo,
IN BOOL fUp );
BOOL
AnSave(
IN ANINFO* pInfo );
VOID
AnTerm(
IN HWND hwndDlg );
VOID
AnUpdateButtons(
IN ANINFO* pInfo );
VOID
AnUpdateCheckboxes(
IN ANINFO* pInfo );
BOOL
CeCommand(
IN CEINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
CeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
CeInit(
IN HWND hwndDlg,
IN CEARGS* pArgs );
BOOL
CeSave(
IN CEINFO* pInfo );
VOID
CeTerm(
IN HWND hwndDlg );
//----------------------------------------------------------------------------
// Alternate Phone Number dialog routines
// Listed alphabetically following entrypoint and dialog proc
//----------------------------------------------------------------------------
BOOL
AlternatePhoneNumbersDlg(
IN HWND hwndOwner,
IN OUT DTLNODE* pLinkNode,
IN OUT DTLLIST* pListAreaCodes )
// Popup a dialog to edit the phone number list for in 'pLinkNode'.
// 'HwndOwner' is the owning window.
//
// Returns true if user pressed OK and succeeded or false on Cancel or
// error.
//
{
INT_PTR nStatus;
ANARGS args;
TRACE( "AlternatePhoneNumbersDlg" );
args.pLinkNode = pLinkNode;
args.pListAreaCodes = pListAreaCodes;
nStatus =
DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_AN_AlternateNumbers ),
hwndOwner,
AnDlgProc,
(LPARAM )(&args) );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
AnDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Alternate Phone Number dialog. Parameters
// and return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "AnDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
if (ListView_OwnerHandler(
hwnd, unMsg, wparam, lparam, AnLvCallback ))
{
return TRUE;
}
switch (unMsg)
{
case WM_INITDIALOG:
{
return AnInit( hwnd, (ANARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwAnHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
ANINFO* pInfo = (ANINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
return AnCommand(
pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_NOTIFY:
{
switch (((NMHDR* )lparam)->code)
{
case LVN_ITEMCHANGED:
{
NM_LISTVIEW* p;
p = (NM_LISTVIEW* )lparam;
if ((p->uNewState & LVIS_SELECTED)
&& !(p->uOldState & LVIS_SELECTED))
{
ANINFO* pInfo;
// This item was just selected.
//
pInfo = (ANINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
AnUpdateButtons( pInfo );
}
break;
}
}
break;
}
case WM_DESTROY:
{
AnTerm( hwnd );
break;
}
}
return FALSE;
}
BOOL
AnCommand(
IN ANINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
// is the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
TRACE3( "AnCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case CID_AN_PB_Up:
{
AnMoveNumber( pInfo, TRUE );
return TRUE;
}
case CID_AN_PB_Down:
{
AnMoveNumber( pInfo, FALSE );
return TRUE;
}
case CID_AN_PB_Add:
{
AnAddNumber( pInfo );
return TRUE;
}
case CID_AN_PB_Edit:
{
AnEditNumber( pInfo );
return TRUE;
}
case CID_AN_PB_Delete:
{
AnDeleteNumber( pInfo );
return TRUE;
}
case CID_AN_CB_TryNextOnFail:
{
AnUpdateCheckboxes( pInfo );
return TRUE;
}
case IDOK:
{
EndDialog( pInfo->hwndDlg, AnSave( pInfo ) );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( pInfo->hwndDlg, FALSE );
return TRUE;
}
}
return FALSE;
}
VOID
AnAddNumber(
IN ANINFO* pInfo )
// Add a new phone number to the bottom of the ListView, by prompting user
// with dialog. 'PInfo' is the dialog context.
//
{
DTLNODE* pNode;
pNode = CreatePhoneNode();
if (!pNode)
{
return;
}
if (!EditPhoneNumberDlg(
pInfo->hwndDlg,
pNode,
pInfo->pListAreaCodes,
SID_AddAlternateTitle ))
{
DestroyPhoneNode( pNode );
return;
}
AnListFromLv( pInfo );
DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
AnFillLv( pInfo, pNode );
}
VOID
AnDeleteNumber(
IN ANINFO* pInfo )
// Deletes the selected phone number in the ListView. 'PInfo' is the
// dialog context.
//
{
DTLNODE* pNode;
DTLNODE* pSelNode;
pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
if (!pNode)
{
ASSERT( FALSE );
return;
}
AnListFromLv( pInfo );
// The item under the deleted selection gets the selection unless the
// lowest item was deleted. In that case the item above the deleted item
// is selected.
//
pSelNode = DtlGetNextNode( pNode );
if (!pSelNode)
{
pSelNode = DtlGetPrevNode( pNode );
}
DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
DestroyPhoneNode( pNode );
AnFillLv( pInfo, pSelNode );
}
VOID
AnEditNumber(
IN ANINFO* pInfo )
// Edit the selected phone number in the ListView, by prompting user with
// dialog. 'PInfo' is the dialog context.
//
{
DTLNODE* pNode;
pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
if (!pNode)
{
ASSERT( FALSE );
return;
}
if (!EditPhoneNumberDlg(
pInfo->hwndDlg,
pNode,
pInfo->pListAreaCodes,
SID_EditAlternateTitle ))
{
return;
}
AnListFromLv( pInfo );
AnFillLv( pInfo, pNode );
}
VOID
AnFillLv(
IN ANINFO* pInfo,
IN DTLNODE* pNodeToSelect )
// Fill the ListView from the edit node, and select the 'pNodeToSelect'
// node. 'PInfo' is the dialog context.
//
{
INT iItem;
INT iSelItem;
DTLNODE* pNode;
TRACE( "AnFillLv" );
ASSERT( ListView_GetItemCount( pInfo->hwndLv ) == 0 );
// Transfer nodes from the edit node list to the ListView one at a time,
// noticing the item number of the node we'll need to select later.
//
iSelItem = 0;
iItem = 0;
while (pNode = DtlGetFirstNode( pInfo->pLink->pdtllistPhones ))
{
PBPHONE* pPhone;
LV_ITEM item;
TCHAR* psz;
DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
if (PhoneNodeIsBlank( pNode ))
{
// "Blank" numbers are discarded.
//
DestroyPhoneNode( pNode );
continue;
}
pPhone = (PBPHONE* )DtlGetData( pNode );
ASSERT( pPhone );
ZeroMemory( &item, sizeof(item) );
item.mask = LVIF_TEXT | LVIF_PARAM;
item.iItem = iItem;
item.pszText = pPhone->pszPhoneNumber;
item.lParam = (LPARAM )pNode;
ListView_InsertItem( pInfo->hwndLv, &item );
if (pNode == pNodeToSelect)
{
iSelItem = iItem;
}
ListView_SetItemText( pInfo->hwndLv, iItem, 1, pPhone->pszComment );
++iItem;
}
if (ListView_GetItemCount( pInfo->hwndLv ) > 0)
{
// Select the specified node, or if none, the first node which
// triggers updates of the button states.
//
ListView_SetItemState(
pInfo->hwndLv, iSelItem, LVIS_SELECTED, LVIS_SELECTED );
}
else
{
// Trigger the button state update directly when the list is redrawn
// empty.
//
AnUpdateButtons( pInfo );
}
}
BOOL
AnInit(
IN HWND hwndDlg,
IN ANARGS* pArgs )
// Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
// dialog window. 'PArgs' is caller's arguments as passed to the stub
// API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
ANINFO* pInfo;
DTLNODE* pNode;
PBPHONE* pPhone;
TRACE( "AnInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pInfo->hwndLv = GetDlgItem( hwndDlg, CID_AN_LV_Numbers );
ASSERT( pInfo->hwndLv );
pInfo->hwndPbUp = GetDlgItem( hwndDlg, CID_AN_PB_Up );
ASSERT( pInfo->hwndPbUp );
pInfo->hwndPbDown = GetDlgItem( hwndDlg, CID_AN_PB_Down );
ASSERT( pInfo->hwndPbDown );
pInfo->hwndPbAdd = GetDlgItem( hwndDlg, CID_AN_PB_Add );
ASSERT( pInfo->hwndPbAdd );
pInfo->hwndPbEdit = GetDlgItem( hwndDlg, CID_AN_PB_Edit );
ASSERT( pInfo->hwndPbEdit );
pInfo->hwndPbDelete = GetDlgItem( hwndDlg, CID_AN_PB_Delete );
ASSERT( pInfo->hwndPbDelete );
pInfo->hwndCbMoveToTop = GetDlgItem( hwndDlg, CID_AN_CB_MoveToTop );
ASSERT( pInfo->hwndCbMoveToTop );
pInfo->hwndCbTryNext = GetDlgItem( hwndDlg, CID_AN_CB_TryNextOnFail );
ASSERT( pInfo->hwndCbTryNext );
pInfo->hwndPbOk = GetDlgItem( hwndDlg, IDOK );
ASSERT( pInfo->hwndPbOk );
// Load the up and down arrow icons, enabled and disabled versions,
// loading the disabled version into the move up and move down buttons.
// Making a selection in the ListView will trigger the enabled version to
// be loaded if appropriate. From what I can tell tell in MSDN, you don't
// have to close or destroy the icon handle.
//
pInfo->hiconUpArr = LoadImage(
g_hinstDll, MAKEINTRESOURCE( IID_UpArr ), IMAGE_ICON, 0, 0, 0 );
pInfo->hiconDnArr = LoadImage(
g_hinstDll, MAKEINTRESOURCE( IID_DnArr ), IMAGE_ICON, 0, 0, 0 );
pInfo->hiconUpArrDis = LoadImage(
g_hinstDll, MAKEINTRESOURCE( IID_UpArrDis ), IMAGE_ICON, 0, 0, 0 );
pInfo->hiconDnArrDis = LoadImage(
g_hinstDll, MAKEINTRESOURCE( IID_DnArrDis ), IMAGE_ICON, 0, 0, 0 );
// Make a copy of the argument node and list for editing since user can
// Cancel the dialog and discard any edits.
//
pInfo->pNode = CreateLinkNode();
if (!pInfo->pNode)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
CopyLinkPhoneNumberInfo( pInfo->pNode, pInfo->pArgs->pLinkNode );
pInfo->pLink = (PBLINK* )DtlGetData( pInfo->pNode );
ASSERT( pInfo->pLink );
pInfo->pListAreaCodes = DtlDuplicateList(
pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
// Fill the ListView of phone numbers and select the first one.
//
AnInitLv( pInfo );
AnFillLv( pInfo, NULL );
// Initialize the check boxes.
//
Button_SetCheck( pInfo->hwndCbTryNext,
pInfo->pLink->fTryNextAlternateOnFail );
Button_SetCheck( pInfo->hwndCbMoveToTop,
pInfo->pLink->fPromoteAlternates );
pInfo->fMoveToTop = pInfo->pLink->fPromoteAlternates;
AnUpdateCheckboxes( pInfo );
// Center dialog on the owner window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
return TRUE;
}
VOID
AnInitLv(
IN ANINFO* pInfo )
// Fill the ListView with phone numbers and comments. 'PInfo' is the
// dialog context.
//
{
TRACE( "AnInitLv" );
// Add columns.
//
{
LV_COLUMN col;
TCHAR* pszHeader0;
TCHAR* pszHeader1;
pszHeader0 = PszFromId( g_hinstDll, SID_PhoneNumbersColHead );
pszHeader1 = PszFromId( g_hinstDll, SID_CommentColHead );
ZeroMemory( &col, sizeof(col) );
col.mask = LVCF_FMT + LVCF_TEXT;
col.fmt = LVCFMT_LEFT;
col.pszText = (pszHeader0) ? pszHeader0 : TEXT("");
ListView_InsertColumn( pInfo->hwndLv, 0, &col );
ZeroMemory( &col, sizeof(col) );
col.mask = LVCF_FMT + LVCF_SUBITEM + LVCF_TEXT;
col.fmt = LVCFMT_LEFT;
col.pszText = (pszHeader1) ? pszHeader1 : TEXT("");
col.iSubItem = 1;
ListView_InsertColumn( pInfo->hwndLv, 1, &col );
Free0( pszHeader0 );
Free0( pszHeader1 );
}
// Size columns. Gives half for phone number and half for comment.
//
{
RECT rect;
LONG dx;
LONG dxPhone;
LONG dxComment;
// The (2 * 2) is 2 columns of 2-pel column separator which the
// ListView doesn't seem to account for when accepting column widths.
// This gives a full ListView with no horizontal scroll bar.
//
GetWindowRect( pInfo->hwndLv, &rect );
dx = rect.right - rect.left - (2 * 2);
dxPhone = dx / 2;
dxComment = dx - dxPhone;
ListView_SetColumnWidth( pInfo->hwndLv, 0, dxPhone );
ListView_SetColumnWidth( pInfo->hwndLv, 1, dxComment );
}
}
VOID
AnListFromLv(
IN ANINFO* pInfo )
// Rebuild the edit link's PBPHONE list from the ListView. 'PInfo' is the
// dialog context.
//
{
INT i;
i = -1;
while ((i = ListView_GetNextItem( pInfo->hwndLv, i, LVNI_ALL )) >= 0)
{
DTLNODE* pNode;
pNode = (DTLNODE* )ListView_GetParamPtr( pInfo->hwndLv, i );
ASSERT( pNode );
if(NULL == pNode)
{
continue;
}
if (PhoneNodeIsBlank( pNode ))
{
// "Blank" numbers are discarded.
//
DestroyPhoneNode( pNode );
continue;
}
DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
}
ListView_DeleteAllItems( pInfo->hwndLv );
}
LVXDRAWINFO*
AnLvCallback(
IN HWND hwndLv,
IN DWORD dwItem )
// Enhanced list view callback to report drawing information. 'HwndLv' is
// the handle of the list view control. 'DwItem' is the index of the item
// being drawn.
//
// Returns the address of the draw information.
//
{
// Use "full row select" and other recommended options.
//
// Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'.
//
static LVXDRAWINFO info = { 2, 0, 0, { 0, 0 } };
return &info;
}
VOID
AnMoveNumber(
IN ANINFO* pInfo,
IN BOOL fUp )
// Refill the ListView of devices with the selected item moved up or down
// one position. 'FUp' is set to move up, otherwise moves down. 'PInfo'
// is the property sheeet context.
//
{
DTLNODE* pNode;
DTLNODE* pPrevNode;
DTLNODE* pNextNode;
DTLLIST* pList;
// Notice which node is selected, then rebuild the edit link's PBPHONE
// list from the ListView.
//
pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
if (pNode == NULL)
{
return;
}
AnListFromLv( pInfo );
pList = pInfo->pLink->pdtllistPhones;
// Move the selected node forward or backward a node in the chain.
//
if (fUp)
{
pPrevNode = DtlGetPrevNode( pNode );
if (pPrevNode)
{
DtlRemoveNode( pList, pNode );
DtlAddNodeBefore( pList, pPrevNode, pNode );
}
}
else
{
pNextNode = DtlGetNextNode( pNode );
if (pNextNode)
{
DtlRemoveNode( pList, pNode );
DtlAddNodeAfter( pList, pNextNode, pNode );
}
}
// Refill the ListView with the new order.
//
AnFillLv( pInfo, pNode );
}
BOOL
AnSave(
IN ANINFO* pInfo )
// Load the contents of the dialog into caller's stub API output argument.
// 'PInfo' is the dialog context.
//
// Returns true if succesful, false otherwise.
//
{
TRACE( "AnSave" );
// Rebuild the edit link's PBPHONE list from the ListView.
//
AnListFromLv( pInfo );
// Retrieve check box settings.
//
pInfo->pLink->fPromoteAlternates =
Button_GetCheck( pInfo->hwndCbMoveToTop );
pInfo->pLink->fTryNextAlternateOnFail =
Button_GetCheck( pInfo->hwndCbTryNext );
// Copy the edit buffer to caller's output argument.
//
CopyLinkPhoneNumberInfo( pInfo->pArgs->pLinkNode, pInfo->pNode );
// Swap lists, saving updates to caller's global list of area codes.
// Caller's original list will be destroyed by AnTerm.
//
if (pInfo->pListAreaCodes)
{
DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
}
return TRUE;
}
VOID
AnTerm(
IN HWND hwndDlg )
// Dialog termination.
//
{
ANINFO* pInfo;
TRACE( "AnTerm" );
pInfo = (ANINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
if (pInfo)
{
// Release any PBPHONE nodes still in the list, e.g. if user Canceled.
//
if (pInfo->pNode)
{
AnListFromLv( pInfo );
DestroyLinkNode( pInfo->pNode );
}
if (pInfo->pListAreaCodes)
{
DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
}
Free( pInfo );
TRACE( "Context freed" );
}
}
VOID
AnUpdateButtons(
IN ANINFO* pInfo )
// Determine if the Up, Down, Edit, and Delete operations make sense and
// enable/disable those buttons accordingly. If a disabled button has
// focus, focus is given to the ListView. 'PInfo' is the dialog context.
//
{
INT iSel;
INT cItems;
BOOL fSel;
iSel = ListView_GetNextItem( pInfo->hwndLv, -1, LVNI_SELECTED );
fSel = (iSel >= 0);
cItems = ListView_GetItemCount( pInfo->hwndLv );
// "Up" button.
//
if (iSel > 0)
{
EnableWindow( pInfo->hwndPbUp, TRUE );
SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
(LPARAM )pInfo->hiconUpArr );
}
else
{
EnableWindow( pInfo->hwndPbUp, FALSE );
SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
(LPARAM )pInfo->hiconUpArrDis );
}
// "Down" button.
//
if (fSel && (iSel < cItems - 1))
{
EnableWindow( pInfo->hwndPbDown, TRUE );
SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
(LPARAM )pInfo->hiconDnArr );
}
else
{
EnableWindow( pInfo->hwndPbDown, FALSE );
SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
(LPARAM )pInfo->hiconDnArrDis );
}
// "Edit" and "Delete" buttons.
//
EnableWindow( pInfo->hwndPbEdit, fSel );
EnableWindow( pInfo->hwndPbDelete, fSel );
// If the focus button is disabled, move focus to the ListView and make OK
// the default button.
//
if (!IsWindowEnabled( GetFocus() ))
{
SetFocus( pInfo->hwndLv );
Button_MakeDefault( pInfo->hwndDlg, pInfo->hwndPbOk );
}
}
VOID
AnUpdateCheckboxes(
IN ANINFO* pInfo )
// Update so "move to top" checkbox is enabled only when "try next" is set
// maintaining a restore state for "move to top". 'PInfo' is the dialog
// context.
//
{
if (Button_GetCheck( pInfo->hwndCbTryNext ))
{
Button_SetCheck( pInfo->hwndCbMoveToTop, pInfo->fMoveToTop );
EnableWindow( pInfo->hwndCbMoveToTop, TRUE );
}
else
{
pInfo->fMoveToTop = Button_GetCheck( pInfo->hwndCbMoveToTop );
Button_SetCheck( pInfo->hwndCbMoveToTop, FALSE );
EnableWindow( pInfo->hwndCbMoveToTop, FALSE );
}
}
//----------------------------------------------------------------------------
// Phone number editor dialog routines
// Listed alphabetically following entrypoint and dialog proc
//----------------------------------------------------------------------------
BOOL
EditPhoneNumberDlg(
IN HWND hwndOwner,
IN OUT DTLNODE* pPhoneNode,
IN OUT DTLLIST* pListAreaCodes,
IN DWORD sidTitle )
// Popup a dialog to edit the phone number in 'pPhoneNode' and update the
// area code list 'pListAreaCodes'. 'HwndOwner' is the owning window.
// 'SidTitle' is the string ID of the title for the dialog.
//
// Returns true if user pressed OK and succeeded or false on Cancel or
// error.
//
{
INT_PTR nStatus;
CEARGS args;
TRACE( "EditPhoneNumberDlg" );
args.pPhoneNode = pPhoneNode;
args.pListAreaCodes = pListAreaCodes;
args.sidTitle = sidTitle;
nStatus =
DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_CE_ComplexPhoneEditor ),
hwndOwner,
CeDlgProc,
(LPARAM )&args );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
CeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the phone number editor dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "CeDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return CeInit( hwnd, (CEARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwCeHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
CEINFO* pInfo = (CEINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
return CeCommand(
pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_DESTROY:
{
CeTerm( hwnd );
break;
}
}
return FALSE;
}
BOOL
CeCommand(
IN CEINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
// is the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
TRACE3( "CeCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case CID_CE_CB_UseDialingRules:
{
if (CuDialingRulesCbHandler( &pInfo->cuinfo, wNotification ))
{
return TRUE;
}
break;
}
case CID_CE_LB_CountryCodes:
{
if (CuCountryCodeLbHandler( &pInfo->cuinfo, wNotification ))
{
return TRUE;
}
break;
}
case IDOK:
{
EndDialog( pInfo->hwndDlg, CeSave( pInfo ) );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( pInfo->hwndDlg, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL
CeInit(
IN HWND hwndDlg,
IN CEARGS* pArgs )
// Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
// dialog window. 'PArgs' is caller's link node argument as passed to the
// stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
CEINFO* pInfo;
DTLNODE* pNode;
PBPHONE* pPhone;
TRACE( "CeInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pInfo->hwndStAreaCodes =
GetDlgItem( hwndDlg, CID_CE_ST_AreaCodes );
ASSERT( pInfo->hwndStAreaCodes );
pInfo->hwndClbAreaCodes =
GetDlgItem( hwndDlg, CID_CE_CLB_AreaCodes );
ASSERT( pInfo->hwndClbAreaCodes );
pInfo->hwndEbPhoneNumber =
GetDlgItem( hwndDlg, CID_CE_EB_PhoneNumber );
ASSERT( pInfo->hwndEbPhoneNumber );
pInfo->hwndLbCountryCodes =
GetDlgItem( hwndDlg, CID_CE_LB_CountryCodes );
ASSERT( pInfo->hwndLbCountryCodes );
pInfo->hwndCbUseDialingRules =
GetDlgItem( hwndDlg, CID_CE_CB_UseDialingRules );
ASSERT( pInfo->hwndCbUseDialingRules );
pInfo->hwndEbComment =
GetDlgItem( hwndDlg, CID_CE_EB_Comment );
ASSERT( pInfo->hwndEbComment );
// Set title to caller's resource string.
//
{
TCHAR* pszTitle;
pszTitle = PszFromId( g_hinstDll, pArgs->sidTitle );
if (pszTitle)
{
SetWindowText( hwndDlg, pszTitle );
Free( pszTitle );
}
}
// Make an edit copy of the argument node and area-code list.
//
pInfo->pNode = DuplicatePhoneNode( pArgs->pPhoneNode );
if (!pInfo->pNode)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
pInfo->pPhone = (PBPHONE* )DtlGetData( pInfo->pNode );
ASSERT( pInfo->pPhone );
pInfo->pListAreaCodes = DtlDuplicateList(
pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
// Initialize area-code/country-code helper context.
//
CuInit( &pInfo->cuinfo,
pInfo->hwndStAreaCodes, pInfo->hwndClbAreaCodes,
NULL, pInfo->hwndEbPhoneNumber,
pInfo->hwndStCountryCodes, pInfo->hwndLbCountryCodes,
pInfo->hwndCbUseDialingRules, NULL,
NULL,
NULL, pInfo->hwndEbComment,
pInfo->pListAreaCodes );
pInfo->fCuInfoInitialized = TRUE;
// Load the fields.
//
CuSetInfo( &pInfo->cuinfo, pInfo->pNode, FALSE );
// Center dialog on the owner window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
// Initial focus is on the phone number.
//
Edit_SetSel( pInfo->hwndEbPhoneNumber, 0, -1 );
SetFocus( pInfo->hwndEbPhoneNumber );
return FALSE;
}
BOOL
CeSave(
IN CEINFO* pInfo )
// Load the contents of the dialog into caller's stub API output argument.
// 'PInfo' is the dialog context.
//
// Returns true if succesful, false otherwise.
//
{
PBPHONE* pSrcPhone;
PBPHONE* pDstPhone;
TRACE( "CeSave" );
// Load the settings in the controls into the edit node.
//
CuGetInfo( &pInfo->cuinfo, pInfo->pNode );
// Copy the edit node to the stub API caller's argument node.
//
pDstPhone = (PBPHONE* )DtlGetData( pInfo->pArgs->pPhoneNode );
pSrcPhone = pInfo->pPhone;
pDstPhone->dwCountryCode = pSrcPhone->dwCountryCode;
pDstPhone->dwCountryID = pSrcPhone->dwCountryID;
pDstPhone->fUseDialingRules = pSrcPhone->fUseDialingRules;
Free0( pDstPhone->pszPhoneNumber );
pDstPhone->pszPhoneNumber = StrDup( pSrcPhone->pszPhoneNumber );
Free0( pDstPhone->pszAreaCode );
pDstPhone->pszAreaCode = StrDup( pSrcPhone->pszAreaCode );
Free0( pDstPhone->pszComment );
pDstPhone->pszComment = StrDup( pSrcPhone->pszComment );
// Swap lists, saving updates to caller's global list of area codes.
// Caller's original list will be destroyed by AnTerm.
//
if (pInfo->pListAreaCodes)
{
DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
}
return TRUE;
}
VOID
CeTerm(
IN HWND hwndDlg )
// Dialog termination.
//
{
CEINFO* pInfo;
TRACE( "CeTerm" );
pInfo = (CEINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
if (pInfo)
{
if (pInfo->pNode)
{
DestroyPhoneNode( pInfo->pNode );
}
if (pInfo->pListAreaCodes)
{
DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
}
if (pInfo->fCuInfoInitialized)
{
CuFree( &pInfo->cuinfo );
}
Free( pInfo );
TRACE( "Context freed" );
}
}