Leaked source code of windows server 2003
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.

1471 lines
36 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. // For whistler bug 29378 gangz
  309. // Disable Edit and Delete Button if no item is selected
  310. //
  311. {
  312. UINT uNumSelected = 0;
  313. uNumSelected= ListView_GetSelectedCount(
  314. ((NMHDR*)lparam)->hwndFrom
  315. );
  316. if ( 0 == uNumSelected )
  317. {
  318. EnableWindow( GetDlgItem(hwnd,
  319. CID_AN_PB_Edit),
  320. FALSE);
  321. EnableWindow( GetDlgItem(hwnd,
  322. CID_AN_PB_Delete),
  323. FALSE);
  324. }
  325. }
  326. break;
  327. }
  328. }
  329. break;
  330. }
  331. case WM_DESTROY:
  332. {
  333. AnTerm( hwnd );
  334. break;
  335. }
  336. }
  337. return FALSE;
  338. }
  339. BOOL
  340. AnCommand(
  341. IN ANINFO* pInfo,
  342. IN WORD wNotification,
  343. IN WORD wId,
  344. IN HWND hwndCtrl )
  345. // Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
  346. // is the notification code of the command. 'wId' is the control/menu
  347. // identifier of the command. 'HwndCtrl' is the control window handle of
  348. // the command.
  349. //
  350. // Returns true if processed message, false otherwise.
  351. //
  352. {
  353. TRACE3( "AnCommand(n=%d,i=%d,c=$%x)",
  354. (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
  355. switch (wId)
  356. {
  357. case CID_AN_PB_Up:
  358. {
  359. AnMoveNumber( pInfo, TRUE );
  360. return TRUE;
  361. }
  362. case CID_AN_PB_Down:
  363. {
  364. AnMoveNumber( pInfo, FALSE );
  365. return TRUE;
  366. }
  367. case CID_AN_PB_Add:
  368. {
  369. AnAddNumber( pInfo );
  370. return TRUE;
  371. }
  372. case CID_AN_PB_Edit:
  373. {
  374. AnEditNumber( pInfo );
  375. return TRUE;
  376. }
  377. case CID_AN_PB_Delete:
  378. {
  379. AnDeleteNumber( pInfo );
  380. return TRUE;
  381. }
  382. case CID_AN_CB_TryNextOnFail:
  383. {
  384. AnUpdateCheckboxes( pInfo );
  385. return TRUE;
  386. }
  387. case IDOK:
  388. {
  389. EndDialog( pInfo->hwndDlg, AnSave( pInfo ) );
  390. return TRUE;
  391. }
  392. case IDCANCEL:
  393. {
  394. TRACE( "Cancel pressed" );
  395. EndDialog( pInfo->hwndDlg, FALSE );
  396. return TRUE;
  397. }
  398. }
  399. return FALSE;
  400. }
  401. VOID
  402. AnAddNumber(
  403. IN ANINFO* pInfo )
  404. // Add a new phone number to the bottom of the ListView, by prompting user
  405. // with dialog. 'PInfo' is the dialog context.
  406. //
  407. {
  408. DTLNODE* pNode;
  409. pNode = CreatePhoneNode();
  410. if (!pNode)
  411. {
  412. return;
  413. }
  414. if (!EditPhoneNumberDlg(
  415. pInfo->hwndDlg,
  416. pNode,
  417. pInfo->pListAreaCodes,
  418. SID_AddAlternateTitle ))
  419. {
  420. DestroyPhoneNode( pNode );
  421. return;
  422. }
  423. AnListFromLv( pInfo );
  424. DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
  425. AnFillLv( pInfo, pNode );
  426. }
  427. VOID
  428. AnDeleteNumber(
  429. IN ANINFO* pInfo )
  430. // Deletes the selected phone number in the ListView. 'PInfo' is the
  431. // dialog context.
  432. //
  433. {
  434. DTLNODE* pNode;
  435. DTLNODE* pSelNode;
  436. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  437. if (!pNode)
  438. {
  439. ASSERT( FALSE );
  440. return;
  441. }
  442. AnListFromLv( pInfo );
  443. // The item under the deleted selection gets the selection unless the
  444. // lowest item was deleted. In that case the item above the deleted item
  445. // is selected.
  446. //
  447. pSelNode = DtlGetNextNode( pNode );
  448. if (!pSelNode)
  449. {
  450. pSelNode = DtlGetPrevNode( pNode );
  451. }
  452. DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
  453. DestroyPhoneNode( pNode );
  454. AnFillLv( pInfo, pSelNode );
  455. }
  456. VOID
  457. AnEditNumber(
  458. IN ANINFO* pInfo )
  459. // Edit the selected phone number in the ListView, by prompting user with
  460. // dialog. 'PInfo' is the dialog context.
  461. //
  462. {
  463. DTLNODE* pNode;
  464. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  465. if (!pNode)
  466. {
  467. ASSERT( FALSE );
  468. return;
  469. }
  470. if (!EditPhoneNumberDlg(
  471. pInfo->hwndDlg,
  472. pNode,
  473. pInfo->pListAreaCodes,
  474. SID_EditAlternateTitle ))
  475. {
  476. return;
  477. }
  478. AnListFromLv( pInfo );
  479. AnFillLv( pInfo, pNode );
  480. }
  481. VOID
  482. AnFillLv(
  483. IN ANINFO* pInfo,
  484. IN DTLNODE* pNodeToSelect )
  485. // Fill the ListView from the edit node, and select the 'pNodeToSelect'
  486. // node. 'PInfo' is the dialog context.
  487. //
  488. {
  489. INT iItem;
  490. INT iSelItem;
  491. DTLNODE* pNode;
  492. TRACE( "AnFillLv" );
  493. ASSERT( ListView_GetItemCount( pInfo->hwndLv ) == 0 );
  494. // Transfer nodes from the edit node list to the ListView one at a time,
  495. // noticing the item number of the node we'll need to select later.
  496. //
  497. iSelItem = 0;
  498. iItem = 0;
  499. while (pNode = DtlGetFirstNode( pInfo->pLink->pdtllistPhones ))
  500. {
  501. PBPHONE* pPhone;
  502. LV_ITEM item;
  503. TCHAR* psz;
  504. DtlRemoveNode( pInfo->pLink->pdtllistPhones, pNode );
  505. if (PhoneNodeIsBlank( pNode ))
  506. {
  507. // "Blank" numbers are discarded.
  508. //
  509. DestroyPhoneNode( pNode );
  510. continue;
  511. }
  512. pPhone = (PBPHONE* )DtlGetData( pNode );
  513. ASSERT( pPhone );
  514. ZeroMemory( &item, sizeof(item) );
  515. item.mask = LVIF_TEXT | LVIF_PARAM;
  516. item.iItem = iItem;
  517. item.pszText = pPhone->pszPhoneNumber;
  518. item.lParam = (LPARAM )pNode;
  519. ListView_InsertItem( pInfo->hwndLv, &item );
  520. if (pNode == pNodeToSelect)
  521. {
  522. iSelItem = iItem;
  523. }
  524. ListView_SetItemText( pInfo->hwndLv, iItem, 1, pPhone->pszComment );
  525. ++iItem;
  526. }
  527. if (ListView_GetItemCount( pInfo->hwndLv ) > 0)
  528. {
  529. // Select the specified node, or if none, the first node which
  530. // triggers updates of the button states.
  531. //
  532. ListView_SetItemState(
  533. pInfo->hwndLv, iSelItem, LVIS_SELECTED, LVIS_SELECTED );
  534. }
  535. else
  536. {
  537. // Trigger the button state update directly when the list is redrawn
  538. // empty.
  539. //
  540. AnUpdateButtons( pInfo );
  541. }
  542. }
  543. BOOL
  544. AnInit(
  545. IN HWND hwndDlg,
  546. IN ANARGS* pArgs )
  547. // Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
  548. // dialog window. 'PArgs' is caller's arguments as passed to the stub
  549. // API.
  550. //
  551. // Return false if focus was set, true otherwise, i.e. as defined for
  552. // WM_INITDIALOG.
  553. //
  554. {
  555. DWORD dwErr;
  556. ANINFO* pInfo;
  557. DTLNODE* pNode;
  558. PBPHONE* pPhone;
  559. TRACE( "AnInit" );
  560. // Allocate the dialog context block. Initialize minimally for proper
  561. // cleanup, then attach to the dialog window.
  562. //
  563. {
  564. pInfo = Malloc( sizeof(*pInfo) );
  565. if (!pInfo)
  566. {
  567. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  568. EndDialog( hwndDlg, FALSE );
  569. return TRUE;
  570. }
  571. ZeroMemory( pInfo, sizeof(*pInfo) );
  572. pInfo->pArgs = pArgs;
  573. pInfo->hwndDlg = hwndDlg;
  574. SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
  575. TRACE( "Context set" );
  576. }
  577. pInfo->hwndLv = GetDlgItem( hwndDlg, CID_AN_LV_Numbers );
  578. ASSERT( pInfo->hwndLv );
  579. pInfo->hwndPbUp = GetDlgItem( hwndDlg, CID_AN_PB_Up );
  580. ASSERT( pInfo->hwndPbUp );
  581. pInfo->hwndPbDown = GetDlgItem( hwndDlg, CID_AN_PB_Down );
  582. ASSERT( pInfo->hwndPbDown );
  583. pInfo->hwndPbAdd = GetDlgItem( hwndDlg, CID_AN_PB_Add );
  584. ASSERT( pInfo->hwndPbAdd );
  585. pInfo->hwndPbEdit = GetDlgItem( hwndDlg, CID_AN_PB_Edit );
  586. ASSERT( pInfo->hwndPbEdit );
  587. pInfo->hwndPbDelete = GetDlgItem( hwndDlg, CID_AN_PB_Delete );
  588. ASSERT( pInfo->hwndPbDelete );
  589. pInfo->hwndCbMoveToTop = GetDlgItem( hwndDlg, CID_AN_CB_MoveToTop );
  590. ASSERT( pInfo->hwndCbMoveToTop );
  591. pInfo->hwndCbTryNext = GetDlgItem( hwndDlg, CID_AN_CB_TryNextOnFail );
  592. ASSERT( pInfo->hwndCbTryNext );
  593. pInfo->hwndPbOk = GetDlgItem( hwndDlg, IDOK );
  594. ASSERT( pInfo->hwndPbOk );
  595. // Load the up and down arrow icons, enabled and disabled versions,
  596. // loading the disabled version into the move up and move down buttons.
  597. // Making a selection in the ListView will trigger the enabled version to
  598. // be loaded if appropriate. From what I can tell tell in MSDN, you don't
  599. // have to close or destroy the icon handle.
  600. //
  601. pInfo->hiconUpArr = LoadImage(
  602. g_hinstDll, MAKEINTRESOURCE( IID_UpArr ), IMAGE_ICON, 0, 0, 0 );
  603. pInfo->hiconDnArr = LoadImage(
  604. g_hinstDll, MAKEINTRESOURCE( IID_DnArr ), IMAGE_ICON, 0, 0, 0 );
  605. pInfo->hiconUpArrDis = LoadImage(
  606. g_hinstDll, MAKEINTRESOURCE( IID_UpArrDis ), IMAGE_ICON, 0, 0, 0 );
  607. pInfo->hiconDnArrDis = LoadImage(
  608. g_hinstDll, MAKEINTRESOURCE( IID_DnArrDis ), IMAGE_ICON, 0, 0, 0 );
  609. // Make a copy of the argument node and list for editing since user can
  610. // Cancel the dialog and discard any edits.
  611. //
  612. pInfo->pNode = CreateLinkNode();
  613. if (!pInfo->pNode)
  614. {
  615. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  616. EndDialog( hwndDlg, FALSE );
  617. return TRUE;
  618. }
  619. CopyLinkPhoneNumberInfo( pInfo->pNode, pInfo->pArgs->pLinkNode );
  620. pInfo->pLink = (PBLINK* )DtlGetData( pInfo->pNode );
  621. ASSERT( pInfo->pLink );
  622. pInfo->pListAreaCodes = DtlDuplicateList(
  623. pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
  624. // Fill the ListView of phone numbers and select the first one.
  625. //
  626. AnInitLv( pInfo );
  627. AnFillLv( pInfo, NULL );
  628. // Initialize the check boxes.
  629. //
  630. Button_SetCheck( pInfo->hwndCbTryNext,
  631. pInfo->pLink->fTryNextAlternateOnFail );
  632. Button_SetCheck( pInfo->hwndCbMoveToTop,
  633. pInfo->pLink->fPromoteAlternates );
  634. pInfo->fMoveToTop = pInfo->pLink->fPromoteAlternates;
  635. AnUpdateCheckboxes( pInfo );
  636. // Center dialog on the owner window.
  637. //
  638. CenterWindow( hwndDlg, GetParent( hwndDlg ) );
  639. // Add context help button to title bar.
  640. //
  641. AddContextHelpButton( hwndDlg );
  642. return TRUE;
  643. }
  644. VOID
  645. AnInitLv(
  646. IN ANINFO* pInfo )
  647. // Fill the ListView with phone numbers and comments. 'PInfo' is the
  648. // dialog context.
  649. //
  650. {
  651. TRACE( "AnInitLv" );
  652. // Add columns.
  653. //
  654. {
  655. LV_COLUMN col;
  656. TCHAR* pszHeader0;
  657. TCHAR* pszHeader1;
  658. pszHeader0 = PszFromId( g_hinstDll, SID_PhoneNumbersColHead );
  659. pszHeader1 = PszFromId( g_hinstDll, SID_CommentColHead );
  660. ZeroMemory( &col, sizeof(col) );
  661. col.mask = LVCF_FMT + LVCF_TEXT;
  662. col.fmt = LVCFMT_LEFT;
  663. col.pszText = (pszHeader0) ? pszHeader0 : TEXT("");
  664. ListView_InsertColumn( pInfo->hwndLv, 0, &col );
  665. ZeroMemory( &col, sizeof(col) );
  666. col.mask = LVCF_FMT + LVCF_SUBITEM + LVCF_TEXT;
  667. col.fmt = LVCFMT_LEFT;
  668. col.pszText = (pszHeader1) ? pszHeader1 : TEXT("");
  669. col.iSubItem = 1;
  670. ListView_InsertColumn( pInfo->hwndLv, 1, &col );
  671. Free0( pszHeader0 );
  672. Free0( pszHeader1 );
  673. }
  674. // Size columns. Gives half for phone number and half for comment.
  675. //
  676. {
  677. RECT rect;
  678. LONG dx;
  679. LONG dxPhone;
  680. LONG dxComment;
  681. // The (2 * 2) is 2 columns of 2-pel column separator which the
  682. // ListView doesn't seem to account for when accepting column widths.
  683. // This gives a full ListView with no horizontal scroll bar.
  684. //
  685. GetWindowRect( pInfo->hwndLv, &rect );
  686. dx = rect.right - rect.left - (2 * 2);
  687. dxPhone = dx / 2;
  688. dxComment = dx - dxPhone;
  689. ListView_SetColumnWidth( pInfo->hwndLv, 0, dxPhone );
  690. ListView_SetColumnWidth( pInfo->hwndLv, 1, dxComment );
  691. }
  692. }
  693. VOID
  694. AnListFromLv(
  695. IN ANINFO* pInfo )
  696. // Rebuild the edit link's PBPHONE list from the ListView. 'PInfo' is the
  697. // dialog context.
  698. //
  699. {
  700. INT i;
  701. i = -1;
  702. while ((i = ListView_GetNextItem( pInfo->hwndLv, i, LVNI_ALL )) >= 0)
  703. {
  704. DTLNODE* pNode;
  705. pNode = (DTLNODE* )ListView_GetParamPtr( pInfo->hwndLv, i );
  706. ASSERT( pNode );
  707. if(NULL == pNode)
  708. {
  709. continue;
  710. }
  711. if (PhoneNodeIsBlank( pNode ))
  712. {
  713. // "Blank" numbers are discarded.
  714. //
  715. DestroyPhoneNode( pNode );
  716. continue;
  717. }
  718. DtlAddNodeLast( pInfo->pLink->pdtllistPhones, pNode );
  719. }
  720. ListView_DeleteAllItems( pInfo->hwndLv );
  721. }
  722. LVXDRAWINFO*
  723. AnLvCallback(
  724. IN HWND hwndLv,
  725. IN DWORD dwItem )
  726. // Enhanced list view callback to report drawing information. 'HwndLv' is
  727. // the handle of the list view control. 'DwItem' is the index of the item
  728. // being drawn.
  729. //
  730. // Returns the address of the draw information.
  731. //
  732. {
  733. // Use "full row select" and other recommended options.
  734. //
  735. // Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'.
  736. //
  737. static LVXDRAWINFO info = { 2, 0, 0, { 0, 0 } };
  738. return &info;
  739. }
  740. VOID
  741. AnMoveNumber(
  742. IN ANINFO* pInfo,
  743. IN BOOL fUp )
  744. // Refill the ListView of devices with the selected item moved up or down
  745. // one position. 'FUp' is set to move up, otherwise moves down. 'PInfo'
  746. // is the property sheeet context.
  747. //
  748. {
  749. DTLNODE* pNode;
  750. DTLNODE* pPrevNode;
  751. DTLNODE* pNextNode;
  752. DTLLIST* pList;
  753. // Notice which node is selected, then rebuild the edit link's PBPHONE
  754. // list from the ListView.
  755. //
  756. pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );
  757. if (pNode == NULL)
  758. {
  759. return;
  760. }
  761. AnListFromLv( pInfo );
  762. pList = pInfo->pLink->pdtllistPhones;
  763. // Move the selected node forward or backward a node in the chain.
  764. //
  765. if (fUp)
  766. {
  767. pPrevNode = DtlGetPrevNode( pNode );
  768. if (pPrevNode)
  769. {
  770. DtlRemoveNode( pList, pNode );
  771. DtlAddNodeBefore( pList, pPrevNode, pNode );
  772. }
  773. }
  774. else
  775. {
  776. pNextNode = DtlGetNextNode( pNode );
  777. if (pNextNode)
  778. {
  779. DtlRemoveNode( pList, pNode );
  780. DtlAddNodeAfter( pList, pNextNode, pNode );
  781. }
  782. }
  783. // Refill the ListView with the new order.
  784. //
  785. AnFillLv( pInfo, pNode );
  786. }
  787. BOOL
  788. AnSave(
  789. IN ANINFO* pInfo )
  790. // Load the contents of the dialog into caller's stub API output argument.
  791. // 'PInfo' is the dialog context.
  792. //
  793. // Returns true if succesful, false otherwise.
  794. //
  795. {
  796. TRACE( "AnSave" );
  797. // Rebuild the edit link's PBPHONE list from the ListView.
  798. //
  799. AnListFromLv( pInfo );
  800. // Retrieve check box settings.
  801. //
  802. pInfo->pLink->fPromoteAlternates =
  803. Button_GetCheck( pInfo->hwndCbMoveToTop );
  804. pInfo->pLink->fTryNextAlternateOnFail =
  805. Button_GetCheck( pInfo->hwndCbTryNext );
  806. // Copy the edit buffer to caller's output argument.
  807. //
  808. CopyLinkPhoneNumberInfo( pInfo->pArgs->pLinkNode, pInfo->pNode );
  809. // Swap lists, saving updates to caller's global list of area codes.
  810. // Caller's original list will be destroyed by AnTerm.
  811. //
  812. if (pInfo->pListAreaCodes)
  813. {
  814. DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
  815. }
  816. return TRUE;
  817. }
  818. VOID
  819. AnTerm(
  820. IN HWND hwndDlg )
  821. // Dialog termination.
  822. //
  823. {
  824. ANINFO* pInfo;
  825. TRACE( "AnTerm" );
  826. pInfo = (ANINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
  827. if (pInfo)
  828. {
  829. // Release any PBPHONE nodes still in the list, e.g. if user Canceled.
  830. //
  831. if (pInfo->pNode)
  832. {
  833. AnListFromLv( pInfo );
  834. DestroyLinkNode( pInfo->pNode );
  835. }
  836. if (pInfo->pListAreaCodes)
  837. {
  838. DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
  839. }
  840. Free( pInfo );
  841. TRACE( "Context freed" );
  842. }
  843. }
  844. VOID
  845. AnUpdateButtons(
  846. IN ANINFO* pInfo )
  847. // Determine if the Up, Down, Edit, and Delete operations make sense and
  848. // enable/disable those buttons accordingly. If a disabled button has
  849. // focus, focus is given to the ListView. 'PInfo' is the dialog context.
  850. //
  851. {
  852. INT iSel;
  853. INT cItems;
  854. BOOL fSel;
  855. iSel = ListView_GetNextItem( pInfo->hwndLv, -1, LVNI_SELECTED );
  856. fSel = (iSel >= 0);
  857. cItems = ListView_GetItemCount( pInfo->hwndLv );
  858. // "Up" button.
  859. //
  860. if (iSel > 0)
  861. {
  862. EnableWindow( pInfo->hwndPbUp, TRUE );
  863. SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
  864. (LPARAM )pInfo->hiconUpArr );
  865. }
  866. else
  867. {
  868. EnableWindow( pInfo->hwndPbUp, FALSE );
  869. SendMessage( pInfo->hwndPbUp, BM_SETIMAGE, IMAGE_ICON,
  870. (LPARAM )pInfo->hiconUpArrDis );
  871. }
  872. // "Down" button.
  873. //
  874. if (fSel && (iSel < cItems - 1))
  875. {
  876. EnableWindow( pInfo->hwndPbDown, TRUE );
  877. SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
  878. (LPARAM )pInfo->hiconDnArr );
  879. }
  880. else
  881. {
  882. EnableWindow( pInfo->hwndPbDown, FALSE );
  883. SendMessage( pInfo->hwndPbDown, BM_SETIMAGE, IMAGE_ICON,
  884. (LPARAM )pInfo->hiconDnArrDis );
  885. }
  886. // "Edit" and "Delete" buttons.
  887. //
  888. EnableWindow( pInfo->hwndPbEdit, fSel );
  889. EnableWindow( pInfo->hwndPbDelete, fSel );
  890. // If the focus button is disabled, move focus to the ListView and make OK
  891. // the default button.
  892. //
  893. if (!IsWindowEnabled( GetFocus() ))
  894. {
  895. SetFocus( pInfo->hwndLv );
  896. Button_MakeDefault( pInfo->hwndDlg, pInfo->hwndPbOk );
  897. }
  898. }
  899. VOID
  900. AnUpdateCheckboxes(
  901. IN ANINFO* pInfo )
  902. // Update so "move to top" checkbox is enabled only when "try next" is set
  903. // maintaining a restore state for "move to top". 'PInfo' is the dialog
  904. // context.
  905. //
  906. {
  907. if (Button_GetCheck( pInfo->hwndCbTryNext ))
  908. {
  909. Button_SetCheck( pInfo->hwndCbMoveToTop, pInfo->fMoveToTop );
  910. EnableWindow( pInfo->hwndCbMoveToTop, TRUE );
  911. }
  912. else
  913. {
  914. pInfo->fMoveToTop = Button_GetCheck( pInfo->hwndCbMoveToTop );
  915. Button_SetCheck( pInfo->hwndCbMoveToTop, FALSE );
  916. EnableWindow( pInfo->hwndCbMoveToTop, FALSE );
  917. }
  918. }
  919. //----------------------------------------------------------------------------
  920. // Phone number editor dialog routines
  921. // Listed alphabetically following entrypoint and dialog proc
  922. //----------------------------------------------------------------------------
  923. BOOL
  924. EditPhoneNumberDlg(
  925. IN HWND hwndOwner,
  926. IN OUT DTLNODE* pPhoneNode,
  927. IN OUT DTLLIST* pListAreaCodes,
  928. IN DWORD sidTitle )
  929. // Popup a dialog to edit the phone number in 'pPhoneNode' and update the
  930. // area code list 'pListAreaCodes'. 'HwndOwner' is the owning window.
  931. // 'SidTitle' is the string ID of the title for the dialog.
  932. //
  933. // Returns true if user pressed OK and succeeded or false on Cancel or
  934. // error.
  935. //
  936. {
  937. INT_PTR nStatus;
  938. CEARGS args;
  939. TRACE( "EditPhoneNumberDlg" );
  940. args.pPhoneNode = pPhoneNode;
  941. args.pListAreaCodes = pListAreaCodes;
  942. args.sidTitle = sidTitle;
  943. nStatus =
  944. DialogBoxParam(
  945. g_hinstDll,
  946. MAKEINTRESOURCE( DID_CE_ComplexPhoneEditor ),
  947. hwndOwner,
  948. CeDlgProc,
  949. (LPARAM )&args );
  950. if (nStatus == -1)
  951. {
  952. ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
  953. nStatus = FALSE;
  954. }
  955. return (BOOL )nStatus;
  956. }
  957. INT_PTR CALLBACK
  958. CeDlgProc(
  959. IN HWND hwnd,
  960. IN UINT unMsg,
  961. IN WPARAM wparam,
  962. IN LPARAM lparam )
  963. // DialogProc callback for the phone number editor dialog. Parameters and
  964. // return value are as described for standard windows 'DialogProc's.
  965. //
  966. {
  967. #if 0
  968. TRACE4( "CeDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
  969. (DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
  970. #endif
  971. switch (unMsg)
  972. {
  973. case WM_INITDIALOG:
  974. {
  975. return CeInit( hwnd, (CEARGS* )lparam );
  976. }
  977. case WM_HELP:
  978. case WM_CONTEXTMENU:
  979. {
  980. ContextHelp( g_adwCeHelp, hwnd, unMsg, wparam, lparam );
  981. break;
  982. }
  983. case WM_COMMAND:
  984. {
  985. CEINFO* pInfo = (CEINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
  986. ASSERT( pInfo );
  987. return CeCommand(
  988. pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
  989. }
  990. case WM_DESTROY:
  991. {
  992. CeTerm( hwnd );
  993. break;
  994. }
  995. }
  996. return FALSE;
  997. }
  998. BOOL
  999. CeCommand(
  1000. IN CEINFO* pInfo,
  1001. IN WORD wNotification,
  1002. IN WORD wId,
  1003. IN HWND hwndCtrl )
  1004. // Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
  1005. // is the notification code of the command. 'wId' is the control/menu
  1006. // identifier of the command. 'HwndCtrl' is the control window handle of
  1007. // the command.
  1008. //
  1009. // Returns true if processed message, false otherwise.
  1010. //
  1011. {
  1012. TRACE3( "CeCommand(n=%d,i=%d,c=$%x)",
  1013. (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
  1014. switch (wId)
  1015. {
  1016. case CID_CE_CB_UseDialingRules:
  1017. {
  1018. if (CuDialingRulesCbHandler( &pInfo->cuinfo, wNotification ))
  1019. {
  1020. return TRUE;
  1021. }
  1022. break;
  1023. }
  1024. case CID_CE_LB_CountryCodes:
  1025. {
  1026. if (CuCountryCodeLbHandler( &pInfo->cuinfo, wNotification ))
  1027. {
  1028. return TRUE;
  1029. }
  1030. break;
  1031. }
  1032. case IDOK:
  1033. {
  1034. EndDialog( pInfo->hwndDlg, CeSave( pInfo ) );
  1035. return TRUE;
  1036. }
  1037. case IDCANCEL:
  1038. {
  1039. TRACE( "Cancel pressed" );
  1040. EndDialog( pInfo->hwndDlg, FALSE );
  1041. return TRUE;
  1042. }
  1043. }
  1044. return FALSE;
  1045. }
  1046. BOOL
  1047. CeInit(
  1048. IN HWND hwndDlg,
  1049. IN CEARGS* pArgs )
  1050. // Called on WM_INITDIALOG. 'HwndDlg' is the handle of the phonebook
  1051. // dialog window. 'PArgs' is caller's link node argument as passed to the
  1052. // stub API.
  1053. //
  1054. // Return false if focus was set, true otherwise, i.e. as defined for
  1055. // WM_INITDIALOG.
  1056. //
  1057. {
  1058. DWORD dwErr;
  1059. CEINFO* pInfo;
  1060. DTLNODE* pNode;
  1061. PBPHONE* pPhone;
  1062. TRACE( "CeInit" );
  1063. // Allocate the dialog context block. Initialize minimally for proper
  1064. // cleanup, then attach to the dialog window.
  1065. //
  1066. {
  1067. pInfo = Malloc( sizeof(*pInfo) );
  1068. if (!pInfo)
  1069. {
  1070. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  1071. EndDialog( hwndDlg, FALSE );
  1072. return TRUE;
  1073. }
  1074. ZeroMemory( pInfo, sizeof(*pInfo) );
  1075. pInfo->pArgs = pArgs;
  1076. pInfo->hwndDlg = hwndDlg;
  1077. SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
  1078. TRACE( "Context set" );
  1079. }
  1080. pInfo->hwndStAreaCodes =
  1081. GetDlgItem( hwndDlg, CID_CE_ST_AreaCodes );
  1082. ASSERT( pInfo->hwndStAreaCodes );
  1083. pInfo->hwndClbAreaCodes =
  1084. GetDlgItem( hwndDlg, CID_CE_CLB_AreaCodes );
  1085. ASSERT( pInfo->hwndClbAreaCodes );
  1086. pInfo->hwndEbPhoneNumber =
  1087. GetDlgItem( hwndDlg, CID_CE_EB_PhoneNumber );
  1088. ASSERT( pInfo->hwndEbPhoneNumber );
  1089. pInfo->hwndLbCountryCodes =
  1090. GetDlgItem( hwndDlg, CID_CE_LB_CountryCodes );
  1091. ASSERT( pInfo->hwndLbCountryCodes );
  1092. pInfo->hwndCbUseDialingRules =
  1093. GetDlgItem( hwndDlg, CID_CE_CB_UseDialingRules );
  1094. ASSERT( pInfo->hwndCbUseDialingRules );
  1095. pInfo->hwndEbComment =
  1096. GetDlgItem( hwndDlg, CID_CE_EB_Comment );
  1097. ASSERT( pInfo->hwndEbComment );
  1098. // Set title to caller's resource string.
  1099. //
  1100. {
  1101. TCHAR* pszTitle;
  1102. pszTitle = PszFromId( g_hinstDll, pArgs->sidTitle );
  1103. if (pszTitle)
  1104. {
  1105. SetWindowText( hwndDlg, pszTitle );
  1106. Free( pszTitle );
  1107. }
  1108. }
  1109. // Make an edit copy of the argument node and area-code list.
  1110. //
  1111. pInfo->pNode = DuplicatePhoneNode( pArgs->pPhoneNode );
  1112. if (!pInfo->pNode)
  1113. {
  1114. ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
  1115. EndDialog( hwndDlg, FALSE );
  1116. return TRUE;
  1117. }
  1118. pInfo->pPhone = (PBPHONE* )DtlGetData( pInfo->pNode );
  1119. ASSERT( pInfo->pPhone );
  1120. pInfo->pListAreaCodes = DtlDuplicateList(
  1121. pArgs->pListAreaCodes, DuplicatePszNode, DestroyPszNode );
  1122. // Initialize area-code/country-code helper context.
  1123. //
  1124. CuInit( &pInfo->cuinfo,
  1125. pInfo->hwndStAreaCodes, pInfo->hwndClbAreaCodes,
  1126. NULL, pInfo->hwndEbPhoneNumber,
  1127. pInfo->hwndStCountryCodes, pInfo->hwndLbCountryCodes,
  1128. pInfo->hwndCbUseDialingRules, NULL,
  1129. NULL,
  1130. NULL, pInfo->hwndEbComment,
  1131. pInfo->pListAreaCodes );
  1132. pInfo->fCuInfoInitialized = TRUE;
  1133. // Load the fields.
  1134. //
  1135. CuSetInfo( &pInfo->cuinfo, pInfo->pNode, FALSE );
  1136. // Center dialog on the owner window.
  1137. //
  1138. CenterWindow( hwndDlg, GetParent( hwndDlg ) );
  1139. // Add context help button to title bar.
  1140. //
  1141. AddContextHelpButton( hwndDlg );
  1142. // Initial focus is on the phone number.
  1143. //
  1144. Edit_SetSel( pInfo->hwndEbPhoneNumber, 0, -1 );
  1145. SetFocus( pInfo->hwndEbPhoneNumber );
  1146. return FALSE;
  1147. }
  1148. BOOL
  1149. CeSave(
  1150. IN CEINFO* pInfo )
  1151. // Load the contents of the dialog into caller's stub API output argument.
  1152. // 'PInfo' is the dialog context.
  1153. //
  1154. // Returns true if succesful, false otherwise.
  1155. //
  1156. {
  1157. PBPHONE* pSrcPhone;
  1158. PBPHONE* pDstPhone;
  1159. TRACE( "CeSave" );
  1160. // Load the settings in the controls into the edit node.
  1161. //
  1162. CuGetInfo( &pInfo->cuinfo, pInfo->pNode );
  1163. // Copy the edit node to the stub API caller's argument node.
  1164. //
  1165. pDstPhone = (PBPHONE* )DtlGetData( pInfo->pArgs->pPhoneNode );
  1166. pSrcPhone = pInfo->pPhone;
  1167. pDstPhone->dwCountryCode = pSrcPhone->dwCountryCode;
  1168. pDstPhone->dwCountryID = pSrcPhone->dwCountryID;
  1169. pDstPhone->fUseDialingRules = pSrcPhone->fUseDialingRules;
  1170. Free0( pDstPhone->pszPhoneNumber );
  1171. pDstPhone->pszPhoneNumber = StrDup( pSrcPhone->pszPhoneNumber );
  1172. Free0( pDstPhone->pszAreaCode );
  1173. pDstPhone->pszAreaCode = StrDup( pSrcPhone->pszAreaCode );
  1174. Free0( pDstPhone->pszComment );
  1175. pDstPhone->pszComment = StrDup( pSrcPhone->pszComment );
  1176. // Swap lists, saving updates to caller's global list of area codes.
  1177. // Caller's original list will be destroyed by AnTerm.
  1178. //
  1179. if (pInfo->pListAreaCodes)
  1180. {
  1181. DtlSwapLists( pInfo->pArgs->pListAreaCodes, pInfo->pListAreaCodes );
  1182. }
  1183. return TRUE;
  1184. }
  1185. VOID
  1186. CeTerm(
  1187. IN HWND hwndDlg )
  1188. // Dialog termination.
  1189. //
  1190. {
  1191. CEINFO* pInfo;
  1192. TRACE( "CeTerm" );
  1193. pInfo = (CEINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
  1194. if (pInfo)
  1195. {
  1196. if (pInfo->pNode)
  1197. {
  1198. DestroyPhoneNode( pInfo->pNode );
  1199. }
  1200. if (pInfo->pListAreaCodes)
  1201. {
  1202. DtlDestroyList( pInfo->pListAreaCodes, DestroyPszNode );
  1203. }
  1204. if (pInfo->fCuInfoInitialized)
  1205. {
  1206. CuFree( &pInfo->cuinfo );
  1207. }
  1208. Free( pInfo );
  1209. TRACE( "Context freed" );
  1210. }
  1211. }