|
|
// 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" ); } }
|