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.

1448 lines
34 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. //
  3. // alternat.c
  4. // Remote Access Common Dialog APIs
  5. // Alternate phone number dialogs
  6. //
  7. // 11/06/97 Steve Cobb
  8. #include "rasdlgp.h"
  9. //----------------------------------------------------------------------------
  10. // Help maps
  11. //----------------------------------------------------------------------------
  12. static DWORD g_adwAnHelp[] =
  13. {
  14. CID_AN_ST_Explain, HID_AN_ST_Explain,
  15. CID_AN_ST_Numbers, HID_AN_LV_Numbers,
  16. CID_AN_LV_Numbers, HID_AN_LV_Numbers,
  17. CID_AN_PB_Up, HID_AN_PB_Up,
  18. CID_AN_PB_Down, HID_AN_PB_Down,
  19. CID_AN_PB_Add, HID_AN_PB_Add,
  20. CID_AN_PB_Edit, HID_AN_PB_Edit,
  21. CID_AN_PB_Delete, HID_AN_PB_Delete,
  22. CID_AN_CB_MoveToTop, HID_AN_CB_MoveToTop,
  23. CID_AN_CB_TryNextOnFail, HID_AN_CB_TryNextOnFail,
  24. 0, 0
  25. };
  26. static DWORD g_adwCeHelp[] =
  27. {
  28. CID_CE_GB_PhoneNumber, HID_CE_GB_PhoneNumber,
  29. CID_CE_ST_AreaCodes, HID_CE_CLB_AreaCodes,
  30. CID_CE_CLB_AreaCodes, HID_CE_CLB_AreaCodes,
  31. CID_CE_ST_PhoneNumber, HID_CE_EB_PhoneNumber,
  32. CID_CE_EB_PhoneNumber, HID_CE_EB_PhoneNumber,
  33. CID_CE_ST_CountryCodes, HID_CE_LB_CountryCodes,
  34. CID_CE_LB_CountryCodes, HID_CE_LB_CountryCodes,
  35. CID_CE_GB_Comment, HID_CE_GB_Comment,
  36. CID_CE_EB_Comment, HID_CE_EB_Comment,
  37. CID_CE_CB_UseDialingRules, HID_CE_CB_UseDialingRules,
  38. 0, 0
  39. };
  40. //----------------------------------------------------------------------------
  41. // Local datatypes
  42. //----------------------------------------------------------------------------
  43. // Alternate Phone Number dialog argument block.
  44. //
  45. typedef struct
  46. _ANARGS
  47. {
  48. DTLNODE* pLinkNode;
  49. DTLLIST* pListAreaCodes;
  50. }
  51. ANARGS;
  52. // Alternate Phone Number dialog context block.
  53. //
  54. typedef struct
  55. _ANINFO
  56. {
  57. // Caller's arguments to the dialog.
  58. //
  59. ANARGS* pArgs;
  60. // Handle of this dialog and some of it's controls.
  61. //
  62. HWND hwndDlg;
  63. HWND hwndLv;
  64. HWND hwndPbUp;
  65. HWND hwndPbDown;
  66. HWND hwndPbAdd;
  67. HWND hwndPbEdit;
  68. HWND hwndPbDelete;
  69. HWND hwndCbTryNext;
  70. HWND hwndCbMoveToTop;
  71. HWND hwndPbOk;
  72. // Up/down arrow icons.
  73. //
  74. HANDLE hiconUpArr;
  75. HANDLE hiconDnArr;
  76. HANDLE hiconUpArrDis;
  77. HANDLE hiconDnArrDis;
  78. // The state to display in the "move to top" checkbox should it be
  79. // enabled.
  80. //
  81. BOOL fMoveToTop;
  82. // Link node containing edited phone number list and check box settings
  83. // and a shortcut to the contained link.
  84. //
  85. DTLNODE* pNode;
  86. PBLINK* pLink;
  87. // List of area codes passed to CuInit plus all strings retrieved with
  88. // CuGetInfo. The list is an editing duplicate of the one in 'pArgs'.
  89. //
  90. DTLLIST* pListAreaCodes;
  91. }
  92. ANINFO;
  93. // Phone number editor dialog argument block
  94. //
  95. typedef struct
  96. _CEARGS
  97. {
  98. DTLNODE* pPhoneNode;
  99. DTLLIST* pListAreaCodes;
  100. DWORD sidTitle;
  101. }
  102. CEARGS;
  103. // Phone number editor dialog context block.
  104. //
  105. typedef struct
  106. _CEINFO
  107. {
  108. // Caller's arguments to the dialog.
  109. //
  110. CEARGS* pArgs;
  111. // Handle of this dialog and some of it's controls.
  112. //
  113. HWND hwndDlg;
  114. HWND hwndStAreaCodes;
  115. HWND hwndClbAreaCodes;
  116. HWND hwndEbPhoneNumber;
  117. HWND hwndLbCountryCodes;
  118. HWND hwndStCountryCodes;
  119. HWND hwndCbUseDialingRules;
  120. HWND hwndEbComment;
  121. // Phone node containing edited phone number settings and a shortcut to
  122. // the contained PBPHONE.
  123. //
  124. DTLNODE* pNode;
  125. PBPHONE* pPhone;
  126. // List of area codes passed to CuInit plus all strings retrieved with
  127. // CuGetInfo. The list is an editing duplicate of the one in 'pArgs'.
  128. //
  129. DTLLIST* pListAreaCodes;
  130. // Area-code and country-code helper context block, and a flag indicating
  131. // if the block has been initialized.
  132. //
  133. CUINFO cuinfo;
  134. BOOL fCuInfoInitialized;
  135. }
  136. CEINFO;
  137. //-----------------------------------------------------------------------------
  138. // Local prototypes (alphabetically)
  139. //-----------------------------------------------------------------------------
  140. VOID
  141. AnAddNumber(
  142. IN ANINFO* pInfo );
  143. BOOL
  144. AnCommand(
  145. IN ANINFO* pInfo,
  146. IN WORD wNotification,
  147. IN WORD wId,
  148. IN HWND hwndCtrl );
  149. INT_PTR CALLBACK
  150. AnDlgProc(
  151. IN HWND hwnd,
  152. IN UINT unMsg,
  153. IN WPARAM wparam,
  154. IN LPARAM lparam );
  155. VOID
  156. AnDeleteNumber(
  157. IN ANINFO* pInfo );
  158. VOID
  159. AnEditNumber(
  160. IN ANINFO* pInfo );
  161. VOID
  162. AnFillLv(
  163. IN ANINFO* pInfo,
  164. IN DTLNODE* pNodeToSelect );
  165. BOOL
  166. AnInit(
  167. IN HWND hwndDlg,
  168. IN ANARGS* pArgs );
  169. VOID
  170. AnInitLv(
  171. IN ANINFO* pInfo );
  172. VOID
  173. AnListFromLv(
  174. IN ANINFO* pInfo );
  175. LVXDRAWINFO*
  176. AnLvCallback(
  177. IN HWND hwndLv,
  178. IN DWORD dwItem );
  179. VOID
  180. AnMoveNumber(
  181. IN ANINFO* pInfo,
  182. IN BOOL fUp );
  183. BOOL
  184. AnSave(
  185. IN ANINFO* pInfo );
  186. VOID
  187. AnTerm(
  188. IN HWND hwndDlg );
  189. VOID
  190. AnUpdateButtons(
  191. IN ANINFO* pInfo );
  192. VOID
  193. AnUpdateCheckboxes(
  194. IN ANINFO* pInfo );
  195. BOOL
  196. CeCommand(
  197. IN CEINFO* pInfo,
  198. IN WORD wNotification,
  199. IN WORD wId,
  200. IN HWND hwndCtrl );
  201. INT_PTR CALLBACK
  202. CeDlgProc(
  203. IN HWND hwnd,
  204. IN UINT unMsg,
  205. IN WPARAM wparam,
  206. IN LPARAM lparam );
  207. BOOL
  208. CeInit(
  209. IN HWND hwndDlg,
  210. IN CEARGS* pArgs );
  211. BOOL
  212. CeSave(
  213. IN CEINFO* pInfo );
  214. VOID
  215. CeTerm(
  216. IN HWND hwndDlg );
  217. //----------------------------------------------------------------------------
  218. // Alternate Phone Number dialog routines
  219. // Listed alphabetically following entrypoint and dialog proc
  220. //----------------------------------------------------------------------------
  221. BOOL
  222. AlternatePhoneNumbersDlg(
  223. IN HWND hwndOwner,
  224. IN OUT DTLNODE* pLinkNode,
  225. IN OUT DTLLIST* pListAreaCodes )
  226. // Popup a dialog to edit the phone number list for in 'pLinkNode'.
  227. // 'HwndOwner' is the owning window.
  228. //
  229. // Returns true if user pressed OK and succeeded or false on Cancel or
  230. // error.
  231. //
  232. {
  233. INT_PTR nStatus;
  234. ANARGS args;
  235. TRACE( "AlternatePhoneNumbersDlg" );
  236. args.pLinkNode = pLinkNode;
  237. args.pListAreaCodes = pListAreaCodes;
  238. nStatus =
  239. DialogBoxParam(
  240. g_hinstDll,
  241. MAKEINTRESOURCE( DID_AN_AlternateNumbers ),
  242. hwndOwner,
  243. AnDlgProc,
  244. (LPARAM )(&args) );
  245. if (nStatus == -1)
  246. {
  247. ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
  248. nStatus = FALSE;
  249. }
  250. return (BOOL )nStatus;
  251. }
  252. INT_PTR CALLBACK
  253. AnDlgProc(
  254. IN HWND hwnd,
  255. IN UINT unMsg,
  256. IN WPARAM wparam,
  257. IN LPARAM lparam )
  258. // DialogProc callback for the Alternate Phone Number dialog. Parameters
  259. // and return value are as described for standard windows 'DialogProc's.
  260. //
  261. {
  262. #if 0
  263. TRACE4( "AnDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
  264. (DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
  265. #endif
  266. if (ListView_OwnerHandler(
  267. hwnd, unMsg, wparam, lparam, AnLvCallback ))
  268. {
  269. return TRUE;
  270. }
  271. switch (unMsg)
  272. {
  273. case WM_INITDIALOG:
  274. {
  275. return AnInit( hwnd, (ANARGS* )lparam );
  276. }
  277. case WM_HELP:
  278. case WM_CONTEXTMENU:
  279. {
  280. ContextHelp( g_adwAnHelp, hwnd, unMsg, wparam, lparam );
  281. break;
  282. }
  283. case WM_COMMAND:
  284. {
  285. ANINFO* pInfo = (ANINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
  286. ASSERT( pInfo );
  287. return AnCommand(
  288. pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
  289. }
  290. case WM_NOTIFY:
  291. {
  292. switch (((NMHDR* )lparam)->code)
  293. {
  294. case LVN_ITEMCHANGED:
  295. {
  296. NM_LISTVIEW* p;
  297. p = (NM_LISTVIEW* )lparam;
  298. if ((p->uNewState & LVIS_SELECTED)
  299. && !(p->uOldState & LVIS_SELECTED))
  300. {
  301. ANINFO* pInfo;
  302. // This item was just selected.
  303. //
  304. pInfo = (ANINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
  305. ASSERT( pInfo );
  306. AnUpdateButtons( pInfo );
  307. }
  308. break;
  309. }
  310. }
  311. break;
  312. }
  313. case WM_DESTROY:
  314. {
  315. AnTerm( hwnd );
  316. break;
  317. }
  318. }
  319. return FALSE;
  320. }
  321. BOOL
  322. AnCommand(
  323. IN ANINFO* pInfo,
  324. IN WORD wNotification,
  325. IN WORD wId,
  326. IN HWND hwndCtrl )
  327. // Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
  328. // is the notification code of the command. 'wId' is the control/menu
  329. // identifier of the command. 'HwndCtrl' is the control window handle of
  330. // the command.
  331. //
  332. // Returns true if processed message, false otherwise.
  333. //
  334. {
  335. TRACE3( "AnCommand(n=%d,i=%d,c=$%x)",
  336. (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
  337. switch (wId)
  338. {
  339. case CID_AN_PB_Up:
  340. {
  341. AnMoveNumber( pInfo, TRUE );
  342. return TRUE;
  343. }
  344. case CID_AN_PB_Down:
  345. {
  346. AnMoveNumber( pInfo, FALSE );
  347. return TRUE;
  348. }
  349. case CID_AN_PB_Add:
  350. {
  351. AnAddNumber( pInfo );
  352. return TRUE;
  353. }
  354. case CID_AN_PB_Edit:
  355. {
  356. AnEditNumber( pInfo );
  357. return TRUE;
  358. }
  359. case CID_AN_PB_Delete:
  360. {
  361. AnDeleteNumber( pInfo );
  362. return TRUE;
  363. }
  364. case CID_AN_CB_TryNextOnFail:
  365. {
  366. AnUpdateCheckboxes( pInfo );
  367. return TRUE;
  368. }
  369. case IDOK:
  370. {
  371. EndDialog( pInfo->hwndDlg, AnSave( pInfo ) );
  372. return TRUE;
  373. }
  374. case IDCANCEL:
  375. {
  376. TRACE( "Cancel pressed" );
  377. EndDialog( pInfo->hwndDlg, FALSE );
  378. return TRUE;
  379. }
  380. }
  381. return FALSE;
  382. }
  383. VOID
  384. AnAddNumber(
  385. IN ANINFO* pInfo )
  386. // Add a new phone number to the bottom of the ListView, by prompting user
  387. // with dialog. 'PInfo' is the dialog context.
  388. //
  389. {
  390. DTLNODE* pNode;
  391. pNode = CreatePhoneNode();
  392. if (!pNode)
  393. {
  394. return;
  395. }
  396. if (!EditPhoneNumberDlg(
  397. pInfo->hwndDlg,
  398. pNode,
  399. pInfo->pListAreaCodes,
  400. SID_AddAlternateTitle ))
  401. {
  402. DestroyPhoneNode( pNode );
  403. return;
  404. }
  405. AnListFromLv( pInfo );
  406. DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
  407. AnFillLv( pInfo, pNode );
  408. }
  409. VOID
  410. AnDeleteNumber(
  411. IN ANINFO* pInfo )
  412. // Deletes the selected phone number in the ListView. 'PInfo' is the
  413. // dialog context.
  414. //
  415. {
  416. DTLNODE* pNode;
  417. DTLNODE* pSelNode;
  418. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  419. if (!pNode)
  420. {
  421. ASSERT( FALSE );
  422. return;
  423. }
  424. AnListFromLv( pInfo );
  425. // The item under the deleted selection gets the selection unless the
  426. // lowest item was deleted. In that case the item above the deleted item
  427. // is selected.
  428. //
  429. pSelNode = DtlGetNextNode( pNode );
  430. if (!pSelNode)
  431. {
  432. pSelNode = DtlGetPrevNode( pNode );
  433. }
  434. DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
  435. DestroyPhoneNode( pNode );
  436. AnFillLv( pInfo, pSelNode );
  437. }
  438. VOID
  439. AnEditNumber(
  440. IN ANINFO* pInfo )
  441. // Edit the selected phone number in the ListView, by prompting user with
  442. // dialog. 'PInfo' is the dialog context.
  443. //
  444. {
  445. DTLNODE* pNode;
  446. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  447. if (!pNode)
  448. {
  449. ASSERT( FALSE );
  450. return;
  451. }
  452. if (!EditPhoneNumberDlg(
  453. pInfo->hwndDlg,
  454. pNode,
  455. pInfo->pListAreaCodes,
  456. SID_EditAlternateTitle ))
  457. {
  458. return;
  459. }
  460. AnListFromLv( pInfo );
  461. AnFillLv( pInfo, pNode );
  462. }
  463. VOID
  464. AnFillLv(
  465. IN ANINFO* pInfo,
  466. IN DTLNODE* pNodeToSelect )
  467. // Fill the ListView from the edit node, and select the 'pNodeToSelect'
  468. // node. 'PInfo' is the dialog context.
  469. //
  470. {
  471. INT iItem;
  472. INT iSelItem;
  473. DTLNODE* pNode;
  474. TRACE( "AnFillLv" );
  475. ASSERT( ListView_GetItemCount( pInfo->hwndLv ) == 0 );
  476. // Transfer nodes from the edit node list to the ListView one at a time,
  477. // noticing the item number of the node we'll need to select later.
  478. //
  479. iSelItem = 0;
  480. iItem = 0;
  481. while (pNode = DtlGetFirstNode( pInfo->pLink->pdtllistPhones ))
  482. {
  483. PBPHONE* pPhone;
  484. LV_ITEM item;
  485. TCHAR* psz;
  486. DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
  487. if (PhoneNodeIsBlank( pNode ))
  488. {
  489. // "Blank" numbers are discarded.
  490. //
  491. DestroyPhoneNode( pNode );
  492. continue;
  493. }
  494. pPhone = (PBPHONE* )DtlGetData( pNode );
  495. ASSERT( pPhone );
  496. ZeroMemory( &item, sizeof(item) );
  497. item.mask = LVIF_TEXT | LVIF_PARAM;
  498. item.iItem = iItem;
  499. item.pszText = pPhone->pszPhoneNumber;
  500. item.lParam = (LPARAM )pNode;
  501. ListView_InsertItem( pInfo->hwndLv, &item );
  502. if (pNode == pNodeToSelect)
  503. {
  504. iSelItem = iItem;
  505. }
  506. ListView_SetItemText( pInfo->hwndLv, iItem, 1, pPhone->pszComment );
  507. ++iItem;
  508. }
  509. if (ListView_GetItemCount( pInfo->hwndLv ) > 0)
  510. {
  511. // Select the specified node, or if none, the first node which
  512. // triggers updates of the button states.
  513. //
  514. ListView_SetItemState(
  515. pInfo->hwndLv, iSelItem, LVIS_SELECTED, LVIS_SELECTED );
  516. }
  517. else
  518. {
  519. // Trigger the button state update directly when the list is redrawn
  520. // empty.
  521. //
  522. AnUpdateButtons( pInfo );
  523. }
  524. }
  525. BOOL
  526. AnInit(
  527. IN HWND hwndDlg,
  528. IN ANARGS* pArgs )
  529. // Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
  530. // dialog window. 'PArgs' is caller's arguments as passed to the stub
  531. // API.
  532. //
  533. // Return false if focus was set, true otherwise, i.e. as defined for
  534. // WM_INITDIALOG.
  535. //
  536. {
  537. DWORD dwErr;
  538. ANINFO* pInfo;
  539. DTLNODE* pNode;
  540. PBPHONE* pPhone;
  541. TRACE( "AnInit" );
  542. // Allocate the dialog context block. Initialize minimally for proper
  543. // cleanup, then attach to the dialog window.
  544. //
  545. {
  546. pInfo = Malloc( sizeof(*pInfo) );
  547. if (!pInfo)
  548. {
  549. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  550. EndDialog( hwndDlg, FALSE );
  551. return TRUE;
  552. }
  553. ZeroMemory( pInfo, sizeof(*pInfo) );
  554. pInfo->pArgs = pArgs;
  555. pInfo->hwndDlg = hwndDlg;
  556. SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
  557. TRACE( "Context set" );
  558. }
  559. pInfo->hwndLv = GetDlgItem( hwndDlg, CID_AN_LV_Numbers );
  560. ASSERT( pInfo->hwndLv );
  561. pInfo->hwndPbUp = GetDlgItem( hwndDlg, CID_AN_PB_Up );
  562. ASSERT( pInfo->hwndPbUp );
  563. pInfo->hwndPbDown = GetDlgItem( hwndDlg, CID_AN_PB_Down );
  564. ASSERT( pInfo->hwndPbDown );
  565. pInfo->hwndPbAdd = GetDlgItem( hwndDlg, CID_AN_PB_Add );
  566. ASSERT( pInfo->hwndPbAdd );
  567. pInfo->hwndPbEdit = GetDlgItem( hwndDlg, CID_AN_PB_Edit );
  568. ASSERT( pInfo->hwndPbEdit );
  569. pInfo->hwndPbDelete = GetDlgItem( hwndDlg, CID_AN_PB_Delete );
  570. ASSERT( pInfo->hwndPbDelete );
  571. pInfo->hwndCbMoveToTop = GetDlgItem( hwndDlg, CID_AN_CB_MoveToTop );
  572. ASSERT( pInfo->hwndCbMoveToTop );
  573. pInfo->hwndCbTryNext = GetDlgItem( hwndDlg, CID_AN_CB_TryNextOnFail );
  574. ASSERT( pInfo->hwndCbTryNext );
  575. pInfo->hwndPbOk = GetDlgItem( hwndDlg, IDOK );
  576. ASSERT( pInfo->hwndPbOk );
  577. // Load the up and down arrow icons, enabled and disabled versions,
  578. // loading the disabled version into the move up and move down buttons.
  579. // Making a selection in the ListView will trigger the enabled version to
  580. // be loaded if appropriate. From what I can tell tell in MSDN, you don't
  581. // have to close or destroy the icon handle.
  582. //
  583. pInfo->hiconUpArr = LoadImage(
  584. g_hinstDll, MAKEINTRESOURCE( IID_UpArr ), IMAGE_ICON, 0, 0, 0 );
  585. pInfo->hiconDnArr = LoadImage(
  586. g_hinstDll, MAKEINTRESOURCE( IID_DnArr ), IMAGE_ICON, 0, 0, 0 );
  587. pInfo->hiconUpArrDis = LoadImage(
  588. g_hinstDll, MAKEINTRESOURCE( IID_UpArrDis ), IMAGE_ICON, 0, 0, 0 );
  589. pInfo->hiconDnArrDis = LoadImage(
  590. g_hinstDll, MAKEINTRESOURCE( IID_DnArrDis ), IMAGE_ICON, 0, 0, 0 );
  591. // Make a copy of the argument node and list for editing since user can
  592. // Cancel the dialog and discard any edits.
  593. //
  594. pInfo->pNode = CreateLinkNode();
  595. if (!pInfo->pNode)
  596. {
  597. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  598. EndDialog( hwndDlg, FALSE );
  599. return TRUE;
  600. }
  601. CopyLinkPhoneNumberInfo( pInfo->pNode, pInfo->pArgs->pLinkNode );
  602. pInfo->pLink = (PBLINK* )DtlGetData( pInfo->pNode );
  603. ASSERT( pInfo->pLink );
  604. pInfo->pListAreaCodes = DtlDuplicateList(
  605. pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
  606. // Fill the ListView of phone numbers and select the first one.
  607. //
  608. AnInitLv( pInfo );
  609. AnFillLv( pInfo, NULL );
  610. // Initialize the check boxes.
  611. //
  612. Button_SetCheck( pInfo->hwndCbTryNext,
  613. pInfo->pLink->fTryNextAlternateOnFail );
  614. Button_SetCheck( pInfo->hwndCbMoveToTop,
  615. pInfo->pLink->fPromoteAlternates );
  616. pInfo->fMoveToTop = pInfo->pLink->fPromoteAlternates;
  617. AnUpdateCheckboxes( pInfo );
  618. // Center dialog on the owner window.
  619. //
  620. CenterWindow( hwndDlg, GetParent( hwndDlg ) );
  621. // Add context help button to title bar.
  622. //
  623. AddContextHelpButton( hwndDlg );
  624. return TRUE;
  625. }
  626. VOID
  627. AnInitLv(
  628. IN ANINFO* pInfo )
  629. // Fill the ListView with phone numbers and comments. 'PInfo' is the
  630. // dialog context.
  631. //
  632. {
  633. TRACE( "AnInitLv" );
  634. // Add columns.
  635. //
  636. {
  637. LV_COLUMN col;
  638. TCHAR* pszHeader0;
  639. TCHAR* pszHeader1;
  640. pszHeader0 = PszFromId( g_hinstDll, SID_PhoneNumbersColHead );
  641. pszHeader1 = PszFromId( g_hinstDll, SID_CommentColHead );
  642. ZeroMemory( &col, sizeof(col) );
  643. col.mask = LVCF_FMT + LVCF_TEXT;
  644. col.fmt = LVCFMT_LEFT;
  645. col.pszText = (pszHeader0) ? pszHeader0 : TEXT("");
  646. ListView_InsertColumn( pInfo->hwndLv, 0, &col );
  647. ZeroMemory( &col, sizeof(col) );
  648. col.mask = LVCF_FMT + LVCF_SUBITEM + LVCF_TEXT;
  649. col.fmt = LVCFMT_LEFT;
  650. col.pszText = (pszHeader1) ? pszHeader1 : TEXT("");
  651. col.iSubItem = 1;
  652. ListView_InsertColumn( pInfo->hwndLv, 1, &col );
  653. Free0( pszHeader0 );
  654. Free0( pszHeader1 );
  655. }
  656. // Size columns. Gives half for phone number and half for comment.
  657. //
  658. {
  659. RECT rect;
  660. LONG dx;
  661. LONG dxPhone;
  662. LONG dxComment;
  663. // The (2 * 2) is 2 columns of 2-pel column separator which the
  664. // ListView doesn't seem to account for when accepting column widths.
  665. // This gives a full ListView with no horizontal scroll bar.
  666. //
  667. GetWindowRect( pInfo->hwndLv, &rect );
  668. dx = rect.right - rect.left - (2 * 2);
  669. dxPhone = dx / 2;
  670. dxComment = dx - dxPhone;
  671. ListView_SetColumnWidth( pInfo->hwndLv, 0, dxPhone );
  672. ListView_SetColumnWidth( pInfo->hwndLv, 1, dxComment );
  673. }
  674. }
  675. VOID
  676. AnListFromLv(
  677. IN ANINFO* pInfo )
  678. // Rebuild the edit link's PBPHONE list from the ListView. 'PInfo' is the
  679. // dialog context.
  680. //
  681. {
  682. INT i;
  683. i = -1;
  684. while ((i = ListView_GetNextItem( pInfo->hwndLv, i, LVNI_ALL )) >= 0)
  685. {
  686. DTLNODE* pNode;
  687. pNode = (DTLNODE* )ListView_GetParamPtr( pInfo->hwndLv, i );
  688. ASSERT( pNode );
  689. if(NULL == pNode)
  690. {
  691. continue;
  692. }
  693. if (PhoneNodeIsBlank( pNode ))
  694. {
  695. // "Blank" numbers are discarded.
  696. //
  697. DestroyPhoneNode( pNode );
  698. continue;
  699. }
  700. DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
  701. }
  702. ListView_DeleteAllItems( pInfo->hwndLv );
  703. }
  704. LVXDRAWINFO*
  705. AnLvCallback(
  706. IN HWND hwndLv,
  707. IN DWORD dwItem )
  708. // Enhanced list view callback to report drawing information. 'HwndLv' is
  709. // the handle of the list view control. 'DwItem' is the index of the item
  710. // being drawn.
  711. //
  712. // Returns the address of the draw information.
  713. //
  714. {
  715. // Use "full row select" and other recommended options.
  716. //
  717. // Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'.
  718. //
  719. static LVXDRAWINFO info = { 2, 0, 0, { 0, 0 } };
  720. return &info;
  721. }
  722. VOID
  723. AnMoveNumber(
  724. IN ANINFO* pInfo,
  725. IN BOOL fUp )
  726. // Refill the ListView of devices with the selected item moved up or down
  727. // one position. 'FUp' is set to move up, otherwise moves down. 'PInfo'
  728. // is the property sheeet context.
  729. //
  730. {
  731. DTLNODE* pNode;
  732. DTLNODE* pPrevNode;
  733. DTLNODE* pNextNode;
  734. DTLLIST* pList;
  735. // Notice which node is selected, then rebuild the edit link's PBPHONE
  736. // list from the ListView.
  737. //
  738. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  739. if (pNode == NULL)
  740. {
  741. return;
  742. }
  743. AnListFromLv( pInfo );
  744. pList = pInfo->pLink->pdtllistPhones;
  745. // Move the selected node forward or backward a node in the chain.
  746. //
  747. if (fUp)
  748. {
  749. pPrevNode = DtlGetPrevNode( pNode );
  750. if (pPrevNode)
  751. {
  752. DtlRemoveNode( pList, pNode );
  753. DtlAddNodeBefore( pList, pPrevNode, pNode );
  754. }
  755. }
  756. else
  757. {
  758. pNextNode = DtlGetNextNode( pNode );
  759. if (pNextNode)
  760. {
  761. DtlRemoveNode( pList, pNode );
  762. DtlAddNodeAfter( pList, pNextNode, pNode );
  763. }
  764. }
  765. // Refill the ListView with the new order.
  766. //
  767. AnFillLv( pInfo, pNode );
  768. }
  769. BOOL
  770. AnSave(
  771. IN ANINFO* pInfo )
  772. // Load the contents of the dialog into caller's stub API output argument.
  773. // 'PInfo' is the dialog context.
  774. //
  775. // Returns true if succesful, false otherwise.
  776. //
  777. {
  778. TRACE( "AnSave" );
  779. // Rebuild the edit link's PBPHONE list from the ListView.
  780. //
  781. AnListFromLv( pInfo );
  782. // Retrieve check box settings.
  783. //
  784. pInfo->pLink->fPromoteAlternates =
  785. Button_GetCheck( pInfo->hwndCbMoveToTop );
  786. pInfo->pLink->fTryNextAlternateOnFail =
  787. Button_GetCheck( pInfo->hwndCbTryNext );
  788. // Copy the edit buffer to caller's output argument.
  789. //
  790. CopyLinkPhoneNumberInfo( pInfo->pArgs->pLinkNode, pInfo->pNode );
  791. // Swap lists, saving updates to caller's global list of area codes.
  792. // Caller's original list will be destroyed by AnTerm.
  793. //
  794. if (pInfo->pListAreaCodes)
  795. {
  796. DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
  797. }
  798. return TRUE;
  799. }
  800. VOID
  801. AnTerm(
  802. IN HWND hwndDlg )
  803. // Dialog termination.
  804. //
  805. {
  806. ANINFO* pInfo;
  807. TRACE( "AnTerm" );
  808. pInfo = (ANINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
  809. if (pInfo)
  810. {
  811. // Release any PBPHONE nodes still in the list, e.g. if user Canceled.
  812. //
  813. if (pInfo->pNode)
  814. {
  815. AnListFromLv( pInfo );
  816. DestroyLinkNode( pInfo->pNode );
  817. }
  818. if (pInfo->pListAreaCodes)
  819. {
  820. DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
  821. }
  822. Free( pInfo );
  823. TRACE( "Context freed" );
  824. }
  825. }
  826. VOID
  827. AnUpdateButtons(
  828. IN ANINFO* pInfo )
  829. // Determine if the Up, Down, Edit, and Delete operations make sense and
  830. // enable/disable those buttons accordingly. If a disabled button has
  831. // focus, focus is given to the ListView. 'PInfo' is the dialog context.
  832. //
  833. {
  834. INT iSel;
  835. INT cItems;
  836. BOOL fSel;
  837. iSel = ListView_GetNextItem( pInfo->hwndLv, -1, LVNI_SELECTED );
  838. fSel = (iSel >= 0);
  839. cItems = ListView_GetItemCount( pInfo->hwndLv );
  840. // "Up" button.
  841. //
  842. if (iSel > 0)
  843. {
  844. EnableWindow( pInfo->hwndPbUp, TRUE );
  845. SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
  846. (LPARAM )pInfo->hiconUpArr );
  847. }
  848. else
  849. {
  850. EnableWindow( pInfo->hwndPbUp, FALSE );
  851. SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
  852. (LPARAM )pInfo->hiconUpArrDis );
  853. }
  854. // "Down" button.
  855. //
  856. if (fSel && (iSel < cItems - 1))
  857. {
  858. EnableWindow( pInfo->hwndPbDown, TRUE );
  859. SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
  860. (LPARAM )pInfo->hiconDnArr );
  861. }
  862. else
  863. {
  864. EnableWindow( pInfo->hwndPbDown, FALSE );
  865. SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
  866. (LPARAM )pInfo->hiconDnArrDis );
  867. }
  868. // "Edit" and "Delete" buttons.
  869. //
  870. EnableWindow( pInfo->hwndPbEdit, fSel );
  871. EnableWindow( pInfo->hwndPbDelete, fSel );
  872. // If the focus button is disabled, move focus to the ListView and make OK
  873. // the default button.
  874. //
  875. if (!IsWindowEnabled( GetFocus() ))
  876. {
  877. SetFocus( pInfo->hwndLv );
  878. Button_MakeDefault( pInfo->hwndDlg, pInfo->hwndPbOk );
  879. }
  880. }
  881. VOID
  882. AnUpdateCheckboxes(
  883. IN ANINFO* pInfo )
  884. // Update so "move to top" checkbox is enabled only when "try next" is set
  885. // maintaining a restore state for "move to top". 'PInfo' is the dialog
  886. // context.
  887. //
  888. {
  889. if (Button_GetCheck( pInfo->hwndCbTryNext ))
  890. {
  891. Button_SetCheck( pInfo->hwndCbMoveToTop, pInfo->fMoveToTop );
  892. EnableWindow( pInfo->hwndCbMoveToTop, TRUE );
  893. }
  894. else
  895. {
  896. pInfo->fMoveToTop = Button_GetCheck( pInfo->hwndCbMoveToTop );
  897. Button_SetCheck( pInfo->hwndCbMoveToTop, FALSE );
  898. EnableWindow( pInfo->hwndCbMoveToTop, FALSE );
  899. }
  900. }
  901. //----------------------------------------------------------------------------
  902. // Phone number editor dialog routines
  903. // Listed alphabetically following entrypoint and dialog proc
  904. //----------------------------------------------------------------------------
  905. BOOL
  906. EditPhoneNumberDlg(
  907. IN HWND hwndOwner,
  908. IN OUT DTLNODE* pPhoneNode,
  909. IN OUT DTLLIST* pListAreaCodes,
  910. IN DWORD sidTitle )
  911. // Popup a dialog to edit the phone number in 'pPhoneNode' and update the
  912. // area code list 'pListAreaCodes'. 'HwndOwner' is the owning window.
  913. // 'SidTitle' is the string ID of the title for the dialog.
  914. //
  915. // Returns true if user pressed OK and succeeded or false on Cancel or
  916. // error.
  917. //
  918. {
  919. INT_PTR nStatus;
  920. CEARGS args;
  921. TRACE( "EditPhoneNumberDlg" );
  922. args.pPhoneNode = pPhoneNode;
  923. args.pListAreaCodes = pListAreaCodes;
  924. args.sidTitle = sidTitle;
  925. nStatus =
  926. DialogBoxParam(
  927. g_hinstDll,
  928. MAKEINTRESOURCE( DID_CE_ComplexPhoneEditor ),
  929. hwndOwner,
  930. CeDlgProc,
  931. (LPARAM )&args );
  932. if (nStatus == -1)
  933. {
  934. ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
  935. nStatus = FALSE;
  936. }
  937. return (BOOL )nStatus;
  938. }
  939. INT_PTR CALLBACK
  940. CeDlgProc(
  941. IN HWND hwnd,
  942. IN UINT unMsg,
  943. IN WPARAM wparam,
  944. IN LPARAM lparam )
  945. // DialogProc callback for the phone number editor dialog. Parameters and
  946. // return value are as described for standard windows 'DialogProc's.
  947. //
  948. {
  949. #if 0
  950. TRACE4( "CeDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
  951. (DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
  952. #endif
  953. switch (unMsg)
  954. {
  955. case WM_INITDIALOG:
  956. {
  957. return CeInit( hwnd, (CEARGS* )lparam );
  958. }
  959. case WM_HELP:
  960. case WM_CONTEXTMENU:
  961. {
  962. ContextHelp( g_adwCeHelp, hwnd, unMsg, wparam, lparam );
  963. break;
  964. }
  965. case WM_COMMAND:
  966. {
  967. CEINFO* pInfo = (CEINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
  968. ASSERT( pInfo );
  969. return CeCommand(
  970. pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
  971. }
  972. case WM_DESTROY:
  973. {
  974. CeTerm( hwnd );
  975. break;
  976. }
  977. }
  978. return FALSE;
  979. }
  980. BOOL
  981. CeCommand(
  982. IN CEINFO* pInfo,
  983. IN WORD wNotification,
  984. IN WORD wId,
  985. IN HWND hwndCtrl )
  986. // Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
  987. // is the notification code of the command. 'wId' is the control/menu
  988. // identifier of the command. 'HwndCtrl' is the control window handle of
  989. // the command.
  990. //
  991. // Returns true if processed message, false otherwise.
  992. //
  993. {
  994. TRACE3( "CeCommand(n=%d,i=%d,c=$%x)",
  995. (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
  996. switch (wId)
  997. {
  998. case CID_CE_CB_UseDialingRules:
  999. {
  1000. if (CuDialingRulesCbHandler( &pInfo->cuinfo, wNotification ))
  1001. {
  1002. return TRUE;
  1003. }
  1004. break;
  1005. }
  1006. case CID_CE_LB_CountryCodes:
  1007. {
  1008. if (CuCountryCodeLbHandler( &pInfo->cuinfo, wNotification ))
  1009. {
  1010. return TRUE;
  1011. }
  1012. break;
  1013. }
  1014. case IDOK:
  1015. {
  1016. EndDialog( pInfo->hwndDlg, CeSave( pInfo ) );
  1017. return TRUE;
  1018. }
  1019. case IDCANCEL:
  1020. {
  1021. TRACE( "Cancel pressed" );
  1022. EndDialog( pInfo->hwndDlg, FALSE );
  1023. return TRUE;
  1024. }
  1025. }
  1026. return FALSE;
  1027. }
  1028. BOOL
  1029. CeInit(
  1030. IN HWND hwndDlg,
  1031. IN CEARGS* pArgs )
  1032. // Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
  1033. // dialog window. 'PArgs' is caller's link node argument as passed to the
  1034. // stub API.
  1035. //
  1036. // Return false if focus was set, true otherwise, i.e. as defined for
  1037. // WM_INITDIALOG.
  1038. //
  1039. {
  1040. DWORD dwErr;
  1041. CEINFO* pInfo;
  1042. DTLNODE* pNode;
  1043. PBPHONE* pPhone;
  1044. TRACE( "CeInit" );
  1045. // Allocate the dialog context block. Initialize minimally for proper
  1046. // cleanup, then attach to the dialog window.
  1047. //
  1048. {
  1049. pInfo = Malloc( sizeof(*pInfo) );
  1050. if (!pInfo)
  1051. {
  1052. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  1053. EndDialog( hwndDlg, FALSE );
  1054. return TRUE;
  1055. }
  1056. ZeroMemory( pInfo, sizeof(*pInfo) );
  1057. pInfo->pArgs = pArgs;
  1058. pInfo->hwndDlg = hwndDlg;
  1059. SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
  1060. TRACE( "Context set" );
  1061. }
  1062. pInfo->hwndStAreaCodes =
  1063. GetDlgItem( hwndDlg, CID_CE_ST_AreaCodes );
  1064. ASSERT( pInfo->hwndStAreaCodes );
  1065. pInfo->hwndClbAreaCodes =
  1066. GetDlgItem( hwndDlg, CID_CE_CLB_AreaCodes );
  1067. ASSERT( pInfo->hwndClbAreaCodes );
  1068. pInfo->hwndEbPhoneNumber =
  1069. GetDlgItem( hwndDlg, CID_CE_EB_PhoneNumber );
  1070. ASSERT( pInfo->hwndEbPhoneNumber );
  1071. pInfo->hwndLbCountryCodes =
  1072. GetDlgItem( hwndDlg, CID_CE_LB_CountryCodes );
  1073. ASSERT( pInfo->hwndLbCountryCodes );
  1074. pInfo->hwndCbUseDialingRules =
  1075. GetDlgItem( hwndDlg, CID_CE_CB_UseDialingRules );
  1076. ASSERT( pInfo->hwndCbUseDialingRules );
  1077. pInfo->hwndEbComment =
  1078. GetDlgItem( hwndDlg, CID_CE_EB_Comment );
  1079. ASSERT( pInfo->hwndEbComment );
  1080. // Set title to caller's resource string.
  1081. //
  1082. {
  1083. TCHAR* pszTitle;
  1084. pszTitle = PszFromId( g_hinstDll, pArgs->sidTitle );
  1085. if (pszTitle)
  1086. {
  1087. SetWindowText( hwndDlg, pszTitle );
  1088. Free( pszTitle );
  1089. }
  1090. }
  1091. // Make an edit copy of the argument node and area-code list.
  1092. //
  1093. pInfo->pNode = DuplicatePhoneNode( pArgs->pPhoneNode );
  1094. if (!pInfo->pNode)
  1095. {
  1096. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  1097. EndDialog( hwndDlg, FALSE );
  1098. return TRUE;
  1099. }
  1100. pInfo->pPhone = (PBPHONE* )DtlGetData( pInfo->pNode );
  1101. ASSERT( pInfo->pPhone );
  1102. pInfo->pListAreaCodes = DtlDuplicateList(
  1103. pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
  1104. // Initialize area-code/country-code helper context.
  1105. //
  1106. CuInit( &pInfo->cuinfo,
  1107. pInfo->hwndStAreaCodes, pInfo->hwndClbAreaCodes,
  1108. NULL, pInfo->hwndEbPhoneNumber,
  1109. pInfo->hwndStCountryCodes, pInfo->hwndLbCountryCodes,
  1110. pInfo->hwndCbUseDialingRules, NULL,
  1111. NULL,
  1112. NULL, pInfo->hwndEbComment,
  1113. pInfo->pListAreaCodes );
  1114. pInfo->fCuInfoInitialized = TRUE;
  1115. // Load the fields.
  1116. //
  1117. CuSetInfo( &pInfo->cuinfo, pInfo->pNode, FALSE );
  1118. // Center dialog on the owner window.
  1119. //
  1120. CenterWindow( hwndDlg, GetParent( hwndDlg ) );
  1121. // Add context help button to title bar.
  1122. //
  1123. AddContextHelpButton( hwndDlg );
  1124. // Initial focus is on the phone number.
  1125. //
  1126. Edit_SetSel( pInfo->hwndEbPhoneNumber, 0, -1 );
  1127. SetFocus( pInfo->hwndEbPhoneNumber );
  1128. return FALSE;
  1129. }
  1130. BOOL
  1131. CeSave(
  1132. IN CEINFO* pInfo )
  1133. // Load the contents of the dialog into caller's stub API output argument.
  1134. // 'PInfo' is the dialog context.
  1135. //
  1136. // Returns true if succesful, false otherwise.
  1137. //
  1138. {
  1139. PBPHONE* pSrcPhone;
  1140. PBPHONE* pDstPhone;
  1141. TRACE( "CeSave" );
  1142. // Load the settings in the controls into the edit node.
  1143. //
  1144. CuGetInfo( &pInfo->cuinfo, pInfo->pNode );
  1145. // Copy the edit node to the stub API caller's argument node.
  1146. //
  1147. pDstPhone = (PBPHONE* )DtlGetData( pInfo->pArgs->pPhoneNode );
  1148. pSrcPhone = pInfo->pPhone;
  1149. pDstPhone->dwCountryCode = pSrcPhone->dwCountryCode;
  1150. pDstPhone->dwCountryID = pSrcPhone->dwCountryID;
  1151. pDstPhone->fUseDialingRules = pSrcPhone->fUseDialingRules;
  1152. Free0( pDstPhone->pszPhoneNumber );
  1153. pDstPhone->pszPhoneNumber = StrDup( pSrcPhone->pszPhoneNumber );
  1154. Free0( pDstPhone->pszAreaCode );
  1155. pDstPhone->pszAreaCode = StrDup( pSrcPhone->pszAreaCode );
  1156. Free0( pDstPhone->pszComment );
  1157. pDstPhone->pszComment = StrDup( pSrcPhone->pszComment );
  1158. // Swap lists, saving updates to caller's global list of area codes.
  1159. // Caller's original list will be destroyed by AnTerm.
  1160. //
  1161. if (pInfo->pListAreaCodes)
  1162. {
  1163. DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
  1164. }
  1165. return TRUE;
  1166. }
  1167. VOID
  1168. CeTerm(
  1169. IN HWND hwndDlg )
  1170. // Dialog termination.
  1171. //
  1172. {
  1173. CEINFO* pInfo;
  1174. TRACE( "CeTerm" );
  1175. pInfo = (CEINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
  1176. if (pInfo)
  1177. {
  1178. if (pInfo->pNode)
  1179. {
  1180. DestroyPhoneNode( pInfo->pNode );
  1181. }
  1182. if (pInfo->pListAreaCodes)
  1183. {
  1184. DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
  1185. }
  1186. if (pInfo->fCuInfoInitialized)
  1187. {
  1188. CuFree( &pInfo->cuinfo );
  1189. }
  1190. Free( pInfo );
  1191. TRACE( "Context freed" );
  1192. }
  1193. }