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.

1283 lines
39 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // AtlLCPair.h
  7. //
  8. // Implementation File:
  9. // None.
  10. //
  11. // Description:
  12. // Definition of the CListCtrlPair dialog.
  13. // Derive from CDialogImpl<> or CPropertyPageImpl<>.
  14. //
  15. // Author:
  16. // David Potter (davidp) August 8, 1996
  17. //
  18. // Revision History:
  19. //
  20. // Notes:
  21. //
  22. /////////////////////////////////////////////////////////////////////////////
  23. #ifndef __ATLLCPAIR_H_
  24. #define __ATLLCPAIR_H_
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Forward Class Declarations
  27. /////////////////////////////////////////////////////////////////////////////
  28. template < class T, class ObjT, class BaseT > class CListCtrlPair;
  29. /////////////////////////////////////////////////////////////////////////////
  30. // External Class Declarations
  31. /////////////////////////////////////////////////////////////////////////////
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Include Files
  34. /////////////////////////////////////////////////////////////////////////////
  35. #ifndef __ADMCOMMONRES_H_
  36. #include "AdmCommonRes.h" // for ADMC_IDC_LCP_xxx
  37. #endif
  38. #ifndef __ATLUTIL_H_
  39. #include "AtlUtil.h" // for DDX_xxx
  40. #endif
  41. /////////////////////////////////////////////////////////////////////////////
  42. // Type Definitions
  43. /////////////////////////////////////////////////////////////////////////////
  44. struct CLcpColumn
  45. {
  46. UINT m_idsText;
  47. int m_nWidth;
  48. };
  49. #define LCPS_SHOW_IMAGES 0x1
  50. #define LCPS_ALLOW_EMPTY 0x2
  51. #define LCPS_CAN_BE_ORDERED 0x4
  52. #define LCPS_ORDERED 0x8
  53. #define LCPS_DONT_OUTPUT_RIGHT_LIST 0x10
  54. #define LCPS_READ_ONLY 0x20
  55. #define LCPS_PROPERTIES_BUTTON 0x40
  56. #define LCPS_MAX 0x40
  57. /////////////////////////////////////////////////////////////////////////////
  58. //++
  59. //
  60. // class CListCtrlPair
  61. //
  62. // Description:
  63. // Class to support dual list box.
  64. //
  65. // Inheritance:
  66. // CListCtrlPair< T, ObjT, BaseT >
  67. // <BaseT>
  68. // ...
  69. // CDialogImpl< T >
  70. //
  71. //--
  72. /////////////////////////////////////////////////////////////////////////////
  73. template < class T, class ObjT, class BaseT >
  74. class CListCtrlPair : public BaseT
  75. {
  76. // friend class CListCtrlPairDlg;
  77. // friend class CListCtrlPairPage;
  78. // friend class CListCtrlPairWizPage;
  79. typedef CListCtrlPair< T, ObjT, BaseT > thisClass;
  80. typedef std::list< ObjT * > _objptrlist;
  81. typedef typename std::list< ObjT * >::iterator _objptrlistit;
  82. protected:
  83. // Column structure and collection.
  84. typedef std::vector< CLcpColumn > CColumnArray;
  85. CColumnArray m_aColumns;
  86. // Sort information.
  87. struct SortInfo
  88. {
  89. int m_nDirection;
  90. int m_nColumn;
  91. };
  92. public:
  93. //
  94. // Construction
  95. //
  96. // Default constructor
  97. CListCtrlPair( void )
  98. {
  99. CommonConstruct();
  100. } //*** CListCtrlPair()
  101. // Constructor with style specified
  102. CListCtrlPair(
  103. IN DWORD dwStyle,
  104. IN LPCTSTR lpszTitle = NULL
  105. )
  106. : BaseT( lpszTitle )
  107. {
  108. CommonConstruct();
  109. m_dwStyle = dwStyle;
  110. } //*** CListCtrlPair( lpszTitle )
  111. // Constructor with style specified
  112. CListCtrlPair(
  113. IN DWORD dwStyle,
  114. IN UINT nIDTitle
  115. )
  116. : BaseT( nIDTitle )
  117. {
  118. CommonConstruct();
  119. m_dwStyle = dwStyle;
  120. } //*** CListCtrlPair( nIDTitle )
  121. // Common object construction
  122. void CommonConstruct( void )
  123. {
  124. m_dwStyle = LCPS_ALLOW_EMPTY;
  125. m_plvcFocusList = NULL;
  126. // Set the sort info.
  127. SiLeft().m_nDirection = -1;
  128. SiLeft().m_nColumn = -1;
  129. SiRight().m_nDirection = -1;
  130. SiRight().m_nColumn = -1;
  131. } //*** CommonConstruct()
  132. public:
  133. //
  134. // Functions that are required to be implemented by derived class.
  135. //
  136. // Return list of objects for right list control
  137. _objptrlist * PlpobjRight( void ) const
  138. {
  139. ATLTRACE( _T("PlpobjRight() - Define in derived class\n") );
  140. ATLASSERT( 0 );
  141. return NULL;
  142. } //*** PlpobjRight()
  143. // Return list of objects for left list control
  144. const _objptrlist * PlpobjLeft( void ) const
  145. {
  146. ATLTRACE( _T("PlpobjLeft() - Define in derived class\n") );
  147. ATLASSERT( 0 );
  148. return NULL;
  149. } //*** PlpobjLeft()
  150. // Get column text and image
  151. void GetColumnInfo(
  152. IN OUT ObjT * pobj,
  153. IN int iItem,
  154. IN int icol,
  155. OUT CString & rstr,
  156. OUT int * piimg
  157. )
  158. {
  159. ATLTRACE( _T("GetColumnInfo() - Define in derived class\n") );
  160. ATLASSERT( 0 );
  161. } //*** GetColumnInfo()
  162. // Display properties for the object
  163. int BDisplayProperties( IN OUT ObjT * pobj )
  164. {
  165. ATLTRACE( _T("BDisplayProperties() - Define in derived class\n") );
  166. ATLASSERT( 0 );
  167. return FALSE;
  168. } //*** BDisplayProperties()
  169. // Display an application-wide message box
  170. virtual int AppMessageBox( LPCWSTR lpszText, UINT fuStyle )
  171. {
  172. ATLTRACE( _T("BDisplayProperties() - Define in derived class\n") );
  173. ATLASSERT( 0 );
  174. return MessageBox( lpszText, _T(""), fuStyle );
  175. } //*** AppMessageBox()
  176. // Display an application-wide message box
  177. int AppMessageBox( UINT nID, UINT fuStyle )
  178. {
  179. CString strMsg;
  180. strMsg.LoadString( nID );
  181. return AppMessageBox( strMsg, fuStyle );
  182. } //*** AppMessageBox()
  183. protected:
  184. //
  185. // List control pair style.
  186. //
  187. DWORD m_dwStyle;
  188. BOOL BIsStyleSet( IN DWORD dwStyle ) const { return (m_dwStyle & dwStyle) == dwStyle; }
  189. void ModifyStyle( IN DWORD dwRemove, IN DWORD dwAdd )
  190. {
  191. ATLASSERT( (dwRemove & dwAdd) == 0 );
  192. if ( dwRemove != 0 )
  193. {
  194. m_dwStyle &= ~dwRemove;
  195. } // if: removing some styles
  196. if ( dwAdd != 0 )
  197. {
  198. m_dwStyle |= dwAdd;
  199. } // if: adding some styles
  200. } //*** ModifyStyle()
  201. DWORD DwStyle( void ) const { return m_dwStyle; }
  202. BOOL BShowImages( void ) const { return BIsStyleSet( LCPS_SHOW_IMAGES ); }
  203. BOOL BAllowEmpty( void ) const { return BIsStyleSet( LCPS_ALLOW_EMPTY ); }
  204. BOOL BCanBeOrdered( void ) const { return BIsStyleSet( LCPS_CAN_BE_ORDERED ); }
  205. BOOL BOrdered( void ) const { return BIsStyleSet( LCPS_ORDERED ); }
  206. BOOL BReadOnly( void ) const { return BIsStyleSet( LCPS_READ_ONLY ); }
  207. BOOL BPropertiesButton( void ) const { return BIsStyleSet( LCPS_PROPERTIES_BUTTON ); }
  208. // Operations
  209. public:
  210. // Add column to list of columns displayed in each list control
  211. void AddColumn( IN UINT idsText, IN int nWidth )
  212. {
  213. CLcpColumn col;
  214. ATLASSERT( idsText != 0 );
  215. ATLASSERT( nWidth > 0 );
  216. ATLASSERT( LpobjRight().empty() );
  217. col.m_idsText = idsText;
  218. col.m_nWidth = nWidth;
  219. m_aColumns.insert( m_aColumns.end(), col );
  220. } //*** AddColumn()
  221. // Insert an item in a list control
  222. int NInsertItemInListCtrl(
  223. IN int iitem,
  224. IN OUT ObjT * pobj,
  225. IN OUT CListViewCtrl & rlc
  226. )
  227. {
  228. int iRetItem;
  229. CString strText;
  230. int iimg = 0;
  231. int icol;
  232. // Insert the first column.
  233. ((T *) this)->GetColumnInfo( pobj, iitem, 0, strText, &iimg );
  234. iRetItem = rlc.InsertItem(
  235. LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, // nMask
  236. iitem, // nItem
  237. strText, // lpszItem
  238. 0, // nState
  239. 0, // nStateMask
  240. iimg, // nImage
  241. (LPARAM) pobj // lParam
  242. );
  243. ATLASSERT( iRetItem != -1 );
  244. for ( icol = 1 ; icol < (int) m_aColumns.size() ; icol++ )
  245. {
  246. ((T *) this)->GetColumnInfo( pobj, iRetItem, icol, strText, NULL );
  247. rlc.SetItemText( iRetItem, icol, strText );
  248. } // for: each column
  249. return iRetItem;
  250. } //*** NInsertItemInListCtrl()
  251. // Update data on or from the dialog
  252. BOOL UpdateData( IN BOOL bSaveAndValidate )
  253. {
  254. BOOL bSuccess = TRUE;
  255. if ( bSaveAndValidate )
  256. {
  257. //
  258. // Verify that the list is not empty.
  259. //
  260. if ( ! BAllowEmpty() && (m_lvcRight.GetItemCount() == 0) )
  261. {
  262. CString strMsg;
  263. CString strLabel;
  264. TCHAR * pszLabel;
  265. DDX_GetText( m_hWnd, ADMC_IDC_LCP_RIGHT_LABEL, strLabel );
  266. //
  267. // Remove ampersands (&) and colons (:).
  268. //
  269. pszLabel = strLabel.GetBuffer( 1 );
  270. CleanupLabel( pszLabel );
  271. strLabel.ReleaseBuffer();
  272. //
  273. // Display an error message.
  274. //
  275. strMsg.FormatMessage( ADMC_IDS_EMPTY_RIGHT_LIST, pszLabel );
  276. AppMessageBox( strMsg, MB_OK | MB_ICONWARNING );
  277. bSuccess = FALSE;
  278. } // if: list is empty and isn't allowed to be
  279. } // if: saving data from the dialog
  280. else
  281. {
  282. } // else: setting data to the dialog
  283. return bSuccess;
  284. } //*** UpdateData()
  285. // Apply changes made on this dialog
  286. BOOL BApplyChanges( void )
  287. {
  288. ATLASSERT( ! BIsStyleSet( LCPS_DONT_OUTPUT_RIGHT_LIST ) );
  289. ATLASSERT( ! BReadOnly() );
  290. T * pT = static_cast< T * >( this );
  291. //
  292. // Copy the Nodes list.
  293. //
  294. *pT->PlpobjRight() = LpobjRight();
  295. //
  296. // Call the base class method.
  297. //
  298. return BaseT::BApplyChanges();
  299. } //*** BApplyChanges()
  300. // Implementation
  301. protected:
  302. _objptrlist m_lpobjRight;
  303. _objptrlist m_lpobjLeft;
  304. CListViewCtrl m_lvcRight;
  305. CListViewCtrl m_lvcLeft;
  306. CListViewCtrl * m_plvcFocusList;
  307. CButton m_pbAdd;
  308. CButton m_pbRemove;
  309. CButton m_pbMoveUp;
  310. CButton m_pbMoveDown;
  311. CButton m_pbProperties;
  312. public:
  313. //
  314. // Message map.
  315. //
  316. BEGIN_MSG_MAP( thisClass )
  317. MESSAGE_HANDLER( WM_CONTEXTMENU, OnContextMenu )
  318. COMMAND_HANDLER( ADMC_IDC_LCP_ADD, BN_CLICKED, OnAdd )
  319. COMMAND_HANDLER( ADMC_IDC_LCP_REMOVE, BN_CLICKED, OnRemove )
  320. COMMAND_HANDLER( ADMC_IDC_LCP_MOVE_UP, BN_CLICKED, OnMoveUp )
  321. COMMAND_HANDLER( ADMC_IDC_LCP_MOVE_DOWN, BN_CLICKED, OnMoveDown )
  322. COMMAND_HANDLER( ADMC_IDC_LCP_PROPERTIES, BN_CLICKED, OnProperties )
  323. COMMAND_HANDLER( IDOK, BN_CLICKED, OnOK )
  324. COMMAND_HANDLER( IDCANCEL, BN_CLICKED, OnCancel )
  325. COMMAND_HANDLER( ADMC_ID_MENU_PROPERTIES, 0, OnProperties )
  326. NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, NM_DBLCLK, OnDblClkList )
  327. NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, NM_DBLCLK, OnDblClkList )
  328. NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, LVN_ITEMCHANGED, OnItemChangedList )
  329. NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, LVN_ITEMCHANGED, OnItemChangedList )
  330. NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, LVN_COLUMNCLICK, OnColumnClickList )
  331. NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, LVN_COLUMNCLICK, OnColumnClickList )
  332. CHAIN_MSG_MAP( BaseT )
  333. END_MSG_MAP()
  334. //
  335. // Message handler functions.
  336. //
  337. // Handler for WM_CONTEXTMENU
  338. LRESULT OnContextMenu(
  339. IN UINT uMsg,
  340. IN WPARAM wParam,
  341. IN LPARAM lParam,
  342. IN OUT BOOL & bHandled
  343. )
  344. {
  345. BOOL bDisplayed = FALSE;
  346. CMenu * pmenu = NULL;
  347. HWND hWnd = (HWND) wParam;
  348. WORD xPos = LOWORD( lParam );
  349. WORD yPos = HIWORD( lParam );
  350. CListViewCtrl * plvc;
  351. CString strMenuName;
  352. CWaitCursor wc;
  353. //
  354. // If focus is not in a list control, don't handle the message.
  355. //
  356. if ( hWnd == m_lvcLeft.m_hWnd )
  357. {
  358. plvc = &m_lvcLeft;
  359. } // if: context menu on left list
  360. else if ( hWnd == m_lvcRight.m_hWnd )
  361. {
  362. plvc = &m_lvcRight;
  363. } // else if: context menu on right list
  364. else
  365. {
  366. bHandled = FALSE;
  367. return 0;
  368. } // else: focus not in a list control
  369. ATLASSERT( plvc != NULL );
  370. //
  371. // If the properties button is not enabled, don't display a menu.
  372. //
  373. if ( ! BPropertiesButton() )
  374. {
  375. bHandled = FALSE;
  376. return 0;
  377. } // if: no properties button
  378. //
  379. // Create the menu to display.
  380. //
  381. pmenu = new CMenu;
  382. ATLASSERT( pmenu != NULL );
  383. if ( pmenu == NULL )
  384. {
  385. bHandled = FALSE;
  386. return 0;
  387. } // if: error allocating memory for the new menu
  388. if ( pmenu->CreatePopupMenu() )
  389. {
  390. UINT nFlags = MF_STRING;
  391. //
  392. // If there are no items in the list, disable the menu item.
  393. //
  394. if ( plvc->GetItemCount() == 0 )
  395. {
  396. nFlags |= MF_GRAYED;
  397. } // if: no items in the list
  398. //
  399. // Add the Properties item to the menu.
  400. //
  401. strMenuName.LoadString( ADMC_ID_MENU_PROPERTIES );
  402. if ( pmenu->AppendMenu( nFlags, ADMC_ID_MENU_PROPERTIES, strMenuName ) )
  403. {
  404. m_plvcFocusList = plvc;
  405. bDisplayed = TRUE;
  406. } // if: successfully added menu item
  407. } // if: menu created successfully
  408. if ( bDisplayed )
  409. {
  410. //
  411. // Display the menu.
  412. //
  413. if ( ! pmenu->TrackPopupMenu(
  414. TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  415. xPos,
  416. yPos,
  417. m_hWnd
  418. ) )
  419. {
  420. } // if: unsuccessfully displayed the menu
  421. } // if: there is a menu to display
  422. delete pmenu;
  423. return 0;
  424. } //*** OnContextMenu()
  425. // Handler for BN_CLICKED on ADMC_IDC_LCP_ADD
  426. LRESULT OnAdd(
  427. IN WORD wNotifyCode,
  428. IN int idCtrl,
  429. IN HWND hwndCtrl,
  430. IN OUT BOOL & bHandled
  431. )
  432. {
  433. ATLASSERT( ! BReadOnly() );
  434. //
  435. // Move selected items from the left list to the right list.
  436. //
  437. MoveItems( m_lvcRight, LpobjRight(), m_lvcLeft, LpobjLeft() );
  438. return 0;
  439. } //*** OnAdd()
  440. // Handler for BN_CLICKED on ADMC_IDC_LCP_REMOVE
  441. LRESULT OnRemove(
  442. IN WORD wNotifyCode,
  443. IN int idCtrl,
  444. IN HWND hwndCtrl,
  445. IN OUT BOOL & bHandled
  446. )
  447. {
  448. ATLASSERT( ! BReadOnly() );
  449. //
  450. // Move selected items from the right list to the left list.
  451. //
  452. MoveItems( m_lvcLeft, LpobjLeft(), m_lvcRight, LpobjRight() );
  453. return 0;
  454. } //*** OnRemove()
  455. // Handler for BN_CLICKED on ADMC_IDC_LCP_MOVE_UP
  456. LRESULT OnMoveUp(
  457. IN WORD wNotifyCode,
  458. IN int idCtrl,
  459. IN HWND hwndCtrl,
  460. IN OUT BOOL & bHandled
  461. )
  462. {
  463. int nItem;
  464. ObjT * pobj;
  465. //
  466. // Find the index of the selected item.
  467. //
  468. nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
  469. ATLASSERT( nItem != -1 );
  470. //
  471. // Get the item pointer.
  472. //
  473. pobj = (ObjT *) m_lvcRight.GetItemData( nItem );
  474. ATLASSERT( pobj != NULL );
  475. // Remove the selected item from the list and add it back in.
  476. {
  477. _objptrlistit itRemove;
  478. _objptrlistit itAdd;
  479. // Find the position of the item to be removed and the item before
  480. // which the item is to be inserted.
  481. itRemove = std::find( LpobjRight().begin(), LpobjRight().end(), pobj );
  482. ATLASSERT( itRemove != LpobjRight().end() );
  483. itAdd = itRemove--;
  484. LpobjRight().insert( itAdd, pobj );
  485. LpobjRight().erase( itRemove );
  486. } // Remove the selected item from the list and add it back in
  487. // Remove the selected item from the list control and add it back in.
  488. m_lvcRight.DeleteItem( nItem );
  489. NInsertItemInListCtrl( nItem - 1, pobj, m_lvcRight );
  490. m_lvcRight.SetItemState(
  491. nItem - 1,
  492. LVIS_SELECTED | LVIS_FOCUSED,
  493. LVIS_SELECTED | LVIS_FOCUSED
  494. );
  495. m_lvcRight.EnsureVisible( nItem - 1, FALSE /*bPartialOK*/ );
  496. m_lvcRight.SetFocus();
  497. return 0;
  498. } //*** OnMoveUp()
  499. // Handler for BN_CLICKED on ADMC_IDC_LCP_MOVE_DOWN
  500. LRESULT OnMoveDown(
  501. IN WORD wNotifyCode,
  502. IN int idCtrl,
  503. IN HWND hwndCtrl,
  504. IN OUT BOOL & bHandled
  505. )
  506. {
  507. int nItem;
  508. ObjT * pobj;
  509. //
  510. // Find the index of the selected item.
  511. //
  512. nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
  513. ATLASSERT( nItem != -1 );
  514. //
  515. // Get the item pointer.
  516. //
  517. pobj = (ObjT *) m_lvcRight.GetItemData( nItem );
  518. ATLASSERT( pobj != NULL );
  519. // Remove the selected item from the list and add it back in.
  520. {
  521. _objptrlistit itRemove;
  522. _objptrlistit itAdd;
  523. // Find the position of the item to be removed and the item after
  524. // which the item is to be inserted.
  525. itRemove = std::find( LpobjRight().begin(), LpobjRight().end(), pobj );
  526. ATLASSERT( itRemove != LpobjRight().end() );
  527. itAdd = itRemove++;
  528. LpobjRight().insert( itAdd, pobj );
  529. LpobjRight().erase( itRemove );
  530. } // Remove the selected item from the list and add it back in
  531. // Remove the selected item from the list control and add it back in.
  532. m_lvcRight.DeleteItem( nItem );
  533. NInsertItemInListCtrl( nItem + 1, pobj, m_lvcRight );
  534. m_lvcRight.SetItemState(
  535. nItem + 1,
  536. LVIS_SELECTED | LVIS_FOCUSED,
  537. LVIS_SELECTED | LVIS_FOCUSED
  538. );
  539. m_lvcRight.EnsureVisible( nItem + 1, FALSE /*bPartialOK*/ );
  540. m_lvcRight.SetFocus();
  541. return 0;
  542. } //*** OnMoveDown()
  543. // Handler for BN_CLICKED on ADMC_IDC_LCP_PROPERTIES
  544. LRESULT OnProperties(
  545. IN WORD wNotifyCode,
  546. IN int idCtrl,
  547. IN HWND hwndCtrl,
  548. IN OUT BOOL & bHandled
  549. )
  550. {
  551. int iitem;
  552. ObjT * pobj;
  553. ATLASSERT( m_plvcFocusList != NULL );
  554. // Get the index of the item with the focus.
  555. iitem = m_plvcFocusList->GetNextItem( -1, LVNI_FOCUSED );
  556. ATLASSERT( iitem != -1 );
  557. // Get a pointer to the selected item.
  558. pobj = (ObjT *) m_plvcFocusList->GetItemData( iitem );
  559. ATLASSERT( pobj != NULL );
  560. T * pT = static_cast< T * >( this );
  561. if ( pT->BDisplayProperties( pobj ) )
  562. {
  563. // Update this item.
  564. {
  565. CString strText;
  566. int iimg = 0;
  567. int icol;
  568. pT->GetColumnInfo( pobj, iitem, 0, strText, &iimg );
  569. m_plvcFocusList->SetItem( iitem, 0, LVIF_TEXT /*| LVIF_IMAGE*/, strText, iimg, 0, 0, 0 );
  570. for ( icol = 1 ; icol < (int) m_aColumns.size() ; icol++ )
  571. {
  572. pT->GetColumnInfo( pobj, iitem, icol, strText, NULL );
  573. m_plvcFocusList->SetItemText( iitem, icol, strText );
  574. } // for: each column
  575. } // Update this item
  576. } // if: properties changed
  577. return 0;
  578. } //*** OnProperties()
  579. // Handler for BN_CLICKED on IDOK
  580. LRESULT OnOK(
  581. IN WORD wNotifyCode,
  582. IN int idCtrl,
  583. IN HWND hwndCtrl,
  584. IN OUT BOOL & bHandled
  585. )
  586. {
  587. //
  588. // Save dialog data and exit the dialog.
  589. //
  590. if ( BSaveChanges() )
  591. {
  592. EndDialog( IDOK );
  593. } // if: dialgo data saved
  594. return 0;
  595. } //*** OnOK()
  596. // Handler for BN_CLICKED on IDCANCEL
  597. LRESULT OnCancel(
  598. IN WORD wNotifyCode,
  599. IN int idCtrl,
  600. IN HWND hwndCtrl,
  601. IN OUT BOOL & bHandled
  602. )
  603. {
  604. //
  605. // Exit the dialog.
  606. //
  607. EndDialog( IDCANCEL );
  608. return 0;
  609. } //*** OnCancel()
  610. // Handler for NM_DBLCLK on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
  611. LRESULT OnDblClkList(
  612. IN int idCtrl,
  613. IN LPNMHDR pnmh,
  614. IN OUT BOOL & bHandled
  615. )
  616. {
  617. ATLASSERT( ! BReadOnly() );
  618. LRESULT lResult;
  619. if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
  620. {
  621. m_plvcFocusList = &m_lvcLeft;
  622. lResult = OnAdd( BN_CLICKED, idCtrl, pnmh->hwndFrom, bHandled );
  623. } // if: double-clicked in left list
  624. else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
  625. {
  626. m_plvcFocusList = &m_lvcRight;
  627. lResult = OnRemove( BN_CLICKED, idCtrl, pnmh->hwndFrom, bHandled );
  628. } // else if: double-clicked in right list
  629. else
  630. {
  631. ATLASSERT( 0 );
  632. lResult = 0;
  633. } // else: double-clicked in an unknown location
  634. return lResult;
  635. } //*** OnDblClkList()
  636. // Handler for LVN_ITEMCHANGED on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
  637. LRESULT OnItemChangedList(
  638. IN int idCtrl,
  639. IN LPNMHDR pnmh,
  640. IN OUT BOOL & bHandled
  641. )
  642. {
  643. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pnmh;
  644. BOOL bEnable;
  645. CButton * ppb;
  646. if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
  647. {
  648. m_plvcFocusList = &m_lvcLeft;
  649. ppb = &m_pbAdd;
  650. } // if: item changed in left list
  651. else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
  652. {
  653. m_plvcFocusList = &m_lvcRight;
  654. ppb = &m_pbRemove;
  655. } // else if: item changed in right list
  656. else
  657. {
  658. ATLASSERT( 0 );
  659. bHandled = FALSE;
  660. return 0;
  661. } // else: unknown list
  662. ATLASSERT( ppb != NULL );
  663. // If the selection changed, enable/disable the Add button.
  664. if ( (pNMListView->uChanged & LVIF_STATE)
  665. && ( (pNMListView->uOldState & LVIS_SELECTED)
  666. || (pNMListView->uNewState & LVIS_SELECTED) )
  667. && ! BReadOnly() )
  668. {
  669. UINT cSelected = m_plvcFocusList->GetSelectedCount();
  670. //
  671. // If there is a selection, enable the Add or Remove button.
  672. // Otherwise disable it.
  673. //
  674. bEnable = (cSelected != 0);
  675. ppb->EnableWindow( bEnable );
  676. if ( BPropertiesButton() )
  677. {
  678. m_pbProperties.EnableWindow( (cSelected == 1) ? TRUE : FALSE );
  679. } // if: dialog has Properties button
  680. //
  681. // If the right list is ordered, setup the state of the Up/Down buttons.
  682. //
  683. if ( BOrdered() )
  684. {
  685. SetUpDownState();
  686. } // if: right list is ordered
  687. } // if: selection changed
  688. return 0;
  689. } //*** OnItemChangedList()
  690. // Handler for LVN_COLUMNCLICK on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
  691. LRESULT OnColumnClickList(
  692. IN int idCtrl,
  693. IN LPNMHDR pnmh,
  694. IN OUT BOOL & bHandled
  695. )
  696. {
  697. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pnmh;
  698. if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
  699. {
  700. m_plvcFocusList = &m_lvcLeft;
  701. m_psiCur = &SiLeft();
  702. } // if: column clicked in left list
  703. else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
  704. {
  705. m_plvcFocusList = &m_lvcRight;
  706. m_psiCur = &SiRight();
  707. } // else if: column clicked in right list
  708. else
  709. {
  710. ATLASSERT( 0 );
  711. bHandled = FALSE;
  712. return 0;
  713. } // else: column clicked in unknown list
  714. // Save the current sort column and direction.
  715. if ( pNMListView->iSubItem == m_psiCur->m_nColumn )
  716. {
  717. m_psiCur->m_nDirection ^= -1;
  718. } // if: sorting same column again
  719. else
  720. {
  721. m_psiCur->m_nColumn = pNMListView->iSubItem;
  722. m_psiCur->m_nDirection = 0;
  723. } // else: different column
  724. // Sort the list.
  725. if ( ! m_plvcFocusList->SortItems( CompareItems, (LPARAM) this ) )
  726. {
  727. ATLASSERT( 0 );
  728. } // if: error sorting items
  729. return 0;
  730. } //*** OnColumnClickList
  731. //
  732. // Message handler overrides.
  733. //
  734. // Handler for the WM_INITDIALOG message
  735. BOOL OnInitDialog( void )
  736. {
  737. #if DBG
  738. T * pT = static_cast< T * >( this );
  739. ATLASSERT( pT->PlpobjRight() != NULL );
  740. ATLASSERT( pT->PlpobjLeft() != NULL );
  741. #endif // DBG
  742. BOOL fReturn = FALSE;
  743. //
  744. // Attach the controls to control member variables.
  745. //
  746. AttachControl( m_lvcRight, ADMC_IDC_LCP_RIGHT_LIST );
  747. AttachControl( m_lvcLeft, ADMC_IDC_LCP_LEFT_LIST );
  748. AttachControl( m_pbAdd, ADMC_IDC_LCP_ADD );
  749. AttachControl( m_pbRemove, ADMC_IDC_LCP_REMOVE );
  750. if ( BPropertiesButton() )
  751. {
  752. AttachControl( m_pbProperties, ADMC_IDC_LCP_PROPERTIES );
  753. } // if: dialog has Properties button
  754. if ( BCanBeOrdered() )
  755. {
  756. AttachControl( m_pbMoveUp, ADMC_IDC_LCP_MOVE_UP );
  757. AttachControl( m_pbMoveDown, ADMC_IDC_LCP_MOVE_DOWN );
  758. } // if: left list can be ordered
  759. // if ( BShowImages() )
  760. // {
  761. // CClusterAdminApp * papp = GetClusterAdminApp();
  762. //
  763. // m_lvcLeft.SetImageList( papp->PilSmallImages(), LVSIL_SMALL );
  764. // m_lvcRight.SetImageList( papp->PilSmallImages(), LVSIL_SMALL );
  765. // } // if: showing images
  766. //
  767. // Disable buttons by default.
  768. //
  769. m_pbAdd.EnableWindow( FALSE );
  770. m_pbRemove.EnableWindow( FALSE );
  771. if ( BPropertiesButton() )
  772. {
  773. m_pbProperties.EnableWindow( FALSE );
  774. } // if: dialog has Properties button
  775. //
  776. // Set the right list to sort if not ordered. Set both to show selection always.
  777. //
  778. if ( BOrdered() )
  779. {
  780. m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
  781. } // if: right list is ordered
  782. else
  783. {
  784. m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS | LVS_SORTASCENDING, 0 );
  785. } // else: right list is not ordered
  786. m_lvcLeft.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
  787. //
  788. // If this is an ordered list, show the Move buttons.
  789. // Otherwise, hide them.
  790. //
  791. if ( BCanBeOrdered() )
  792. {
  793. SetUpDownState();
  794. } // if: list can be ordered
  795. //
  796. // Change left list view control extended styles.
  797. //
  798. m_lvcLeft.SetExtendedListViewStyle(
  799. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
  800. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
  801. );
  802. //
  803. // Change right list view control extended styles.
  804. //
  805. m_lvcRight.SetExtendedListViewStyle(
  806. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
  807. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
  808. );
  809. // Duplicate lists.
  810. DuplicateLists();
  811. //
  812. // Insert all the columns.
  813. //
  814. {
  815. int icol;
  816. int ncol;
  817. size_t nUpperBound = m_aColumns.size();
  818. CString strColText;
  819. ATLASSERT( nUpperBound > 0 );
  820. for ( icol = 0 ; icol < static_cast< int >( nUpperBound ) ; icol++ )
  821. {
  822. strColText.LoadString( m_aColumns[icol].m_idsText );
  823. ncol = m_lvcLeft.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
  824. ATLASSERT( ncol == icol );
  825. ncol = m_lvcRight.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
  826. ATLASSERT( ncol == icol );
  827. } // for: each column
  828. } // Insert all the columns
  829. //
  830. // Fill the list controls.
  831. //
  832. FillList( m_lvcRight, LpobjRight() );
  833. FillList( m_lvcLeft, LpobjLeft() );
  834. //
  835. // If read-only, set all controls to be either disabled or read-only.
  836. //
  837. if ( BReadOnly() )
  838. {
  839. m_lvcRight.EnableWindow( FALSE );
  840. m_lvcLeft.EnableWindow( FALSE );
  841. } // if: sheet is read-only
  842. //
  843. // Call the base class method.
  844. //
  845. fReturn = static_cast< BOOL >( BaseT::OnInitDialog() );
  846. return fReturn;
  847. } //*** OnInitDialog()
  848. // Handler for PSN_SETACTIVE
  849. BOOL OnSetActive( void )
  850. {
  851. UINT nSelCount;
  852. // Set the focus to the left list.
  853. m_lvcLeft.SetFocus();
  854. m_plvcFocusList = &m_lvcLeft;
  855. // Enable/disable the Properties button.
  856. nSelCount = m_lvcLeft.GetSelectedCount();
  857. if ( BPropertiesButton() )
  858. {
  859. m_pbProperties.EnableWindow( nSelCount == 1 );
  860. } // if: dialog has Properties button
  861. // Enable or disable the other buttons.
  862. if ( ! BReadOnly() )
  863. {
  864. m_pbAdd.EnableWindow( nSelCount > 0 );
  865. nSelCount = m_lvcRight.GetSelectedCount();
  866. m_pbRemove.EnableWindow( nSelCount > 0 );
  867. SetUpDownState();
  868. } // if: not read-only page
  869. return TRUE;
  870. } //*** OnSetActive()
  871. public:
  872. _objptrlist & LpobjRight( void ) { return m_lpobjRight; }
  873. _objptrlist & LpobjLeft( void ) { return m_lpobjLeft; }
  874. protected:
  875. void DuplicateLists( void )
  876. {
  877. LpobjRight().erase( LpobjRight().begin(), LpobjRight().end() );
  878. LpobjLeft().erase( LpobjLeft().begin(), LpobjLeft().end() );
  879. T * pT = static_cast< T * >( this );
  880. if ( (pT->PlpobjRight() == NULL) || (pT->PlpobjLeft() == NULL) )
  881. {
  882. return;
  883. } // if: either list is empty
  884. //
  885. // Duplicate the lists.
  886. //
  887. LpobjRight() = *pT->PlpobjRight();
  888. LpobjLeft() = *pT->PlpobjLeft();
  889. //
  890. // Remove all the items that are in the right list from
  891. // the left list.
  892. //
  893. _objptrlistit itRight;
  894. _objptrlistit itLeft;
  895. for ( itRight = LpobjRight().begin()
  896. ; itRight != LpobjRight().end()
  897. ; itRight++ )
  898. {
  899. //
  900. // Find the item in the left list.
  901. //
  902. itLeft = std::find( LpobjLeft().begin(), LpobjLeft().end(), *itRight );
  903. if ( itLeft != LpobjLeft().end() )
  904. {
  905. LpobjLeft().erase( itLeft );
  906. } // if: object found in left list
  907. } // for: each item in the right list
  908. } //*** DuplicateLists()
  909. // Fill a list control
  910. void FillList( IN OUT CListViewCtrl & rlvc, IN const _objptrlist & rlpobj )
  911. {
  912. _objptrlistit itpobj;
  913. ObjT * pobj;
  914. int iItem;
  915. // Initialize the control.
  916. if ( ! rlvc.DeleteAllItems() )
  917. {
  918. ATLASSERT( 0 );
  919. } // if: error deleting all items
  920. rlvc.SetItemCount( static_cast< int >( rlpobj.size() ) );
  921. // Add the items to the list.
  922. itpobj = rlpobj.begin();
  923. for ( iItem = 0 ; itpobj != rlpobj.end() ; iItem++, itpobj++ )
  924. {
  925. pobj = *itpobj;
  926. NInsertItemInListCtrl( iItem, pobj, rlvc );
  927. } // for: each string in the list
  928. // If there are any items, set the focus on the first one.
  929. if ( rlvc.GetItemCount() != 0)
  930. {
  931. rlvc.SetItemState( 0, LVIS_FOCUSED, LVIS_FOCUSED );
  932. } // if: items were added to the list
  933. } //*** FillList()
  934. // Move items from one list to another
  935. void MoveItems(
  936. IN OUT CListViewCtrl & rlvcDst,
  937. IN OUT _objptrlist & rlpobjDst,
  938. IN OUT CListViewCtrl & rlvcSrc,
  939. IN OUT _objptrlist & rlpobjSrc
  940. )
  941. {
  942. int iSrcItem;
  943. int iDstItem;
  944. int nItem = -1;
  945. ObjT * pobj;
  946. _objptrlistit itpobj;
  947. ATLASSERT( ! BReadOnly() );
  948. iDstItem = rlvcDst.GetItemCount();
  949. while ( (iSrcItem = rlvcSrc.GetNextItem( -1, LVNI_SELECTED )) != -1 )
  950. {
  951. // Get the item pointer.
  952. pobj = (ObjT *) rlvcSrc.GetItemData( iSrcItem );
  953. ATLASSERT( pobj );
  954. // Remove the item from the source list.
  955. itpobj = std::find( rlpobjSrc.begin(), rlpobjSrc.end(), pobj );
  956. ATLASSERT( itpobj != rlpobjSrc.end() );
  957. rlpobjSrc.remove( *itpobj );
  958. // Add the item to the destination list.
  959. rlpobjDst.insert( rlpobjDst.end(), pobj );
  960. // Remove the item from the source list control and
  961. // add it to the destination list control.
  962. if ( ! rlvcSrc.DeleteItem( iSrcItem ) )
  963. {
  964. ATLASSERT( 0 );
  965. } // if: error deleting the item
  966. nItem = NInsertItemInListCtrl( iDstItem++, pobj, rlvcDst );
  967. rlvcDst.SetItemState(
  968. nItem,
  969. LVIS_SELECTED | LVIS_FOCUSED,
  970. LVIS_SELECTED | LVIS_FOCUSED
  971. );
  972. } // while: more items
  973. ATLASSERT( nItem != -1 );
  974. rlvcDst.EnsureVisible( nItem, FALSE /*bPartialOK*/ );
  975. rlvcDst.SetFocus();
  976. // Indicate that the data has changed.
  977. ::SendMessage( GetParent(), PSM_CHANGED, (WPARAM) m_hWnd, NULL );
  978. } //*** MoveItems()
  979. BOOL BSaveChanges( void )
  980. {
  981. ATLASSERT( ! BIsStyleSet( LCPS_DONT_OUTPUT_RIGHT_LIST ) );
  982. ATLASSERT( ! BReadOnly() );
  983. T * pT = static_cast< T * >( this );
  984. //
  985. // Update the data first.
  986. //
  987. if ( ! pT->UpdateData( TRUE /*bSaveAndValidate*/ ) )
  988. {
  989. return FALSE;
  990. } // if: error updating data
  991. //
  992. // Copy the object list.
  993. //
  994. *pT->PlpobjRight() = LpobjRight();
  995. return TRUE;
  996. } //*** BSaveChanges()
  997. // Set the state of the Up/Down buttons based on the selection.
  998. void SetUpDownState( void )
  999. {
  1000. BOOL bEnableUp;
  1001. BOOL bEnableDown;
  1002. if ( BOrdered()
  1003. && ! BReadOnly()
  1004. && (m_lvcRight.GetSelectedCount() == 1) )
  1005. {
  1006. int nItem;
  1007. bEnableUp = TRUE;
  1008. bEnableDown = TRUE;
  1009. //
  1010. // Find the index of the selected item.
  1011. //
  1012. nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
  1013. ATLASSERT( nItem != -1 );
  1014. //
  1015. // If the first item is selected, can't move up.
  1016. //
  1017. if ( nItem == 0 )
  1018. {
  1019. bEnableUp = FALSE;
  1020. } // if: first item is selected
  1021. //
  1022. // If the last item is selected, can't move down.
  1023. //
  1024. if ( nItem == m_lvcRight.GetItemCount() - 1 )
  1025. {
  1026. bEnableDown = FALSE;
  1027. } // if: last item is selected
  1028. } // if: only one item selected
  1029. else
  1030. {
  1031. bEnableUp = FALSE;
  1032. bEnableDown = FALSE;
  1033. } // else: zero or more than one item selected
  1034. m_pbMoveUp.EnableWindow( bEnableUp );
  1035. m_pbMoveDown.EnableWindow( bEnableDown );
  1036. } //*** SetUpDownState()
  1037. static int CALLBACK CompareItems( LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort )
  1038. {
  1039. ObjT * pobj1 = reinterpret_cast< ObjT * >( lparam1 );
  1040. ObjT * pobj2 = reinterpret_cast< ObjT * >( lparam2 );
  1041. T * plcp = reinterpret_cast< T * >( lparamSort );
  1042. SortInfo * psiCur = plcp->PsiCur();
  1043. int icol = psiCur->m_nColumn;
  1044. int nResult;
  1045. CString str1;
  1046. CString str2;
  1047. ATLASSERT( pobj1 != NULL );
  1048. ATLASSERT( pobj2 != NULL );
  1049. ATLASSERT( plcp != NULL );
  1050. ATLASSERT( psiCur->m_nColumn >= 0 );
  1051. ATLASSERT( icol >= 0 );
  1052. plcp->GetColumnInfo( pobj1, 0, icol, str1, NULL );
  1053. plcp->GetColumnInfo( pobj2, 0, icol, str2, NULL );
  1054. nResult = str1.Compare( str2 );
  1055. // Return the result based on the direction we are sorting.
  1056. if ( psiCur->m_nDirection != 0 )
  1057. {
  1058. nResult = -nResult;
  1059. } // if: sorting in reverse direction
  1060. return nResult;
  1061. } //*** CompareItems()
  1062. SortInfo m_siLeft;
  1063. SortInfo m_siRight;
  1064. SortInfo * m_psiCur;
  1065. SortInfo & SiLeft( void ) { return m_siLeft; }
  1066. SortInfo & SiRight( void ) { return m_siRight; }
  1067. public:
  1068. SortInfo * PsiCur( void ) const { return m_psiCur; }
  1069. }; //*** class CListCtrlPair
  1070. /////////////////////////////////////////////////////////////////////////////
  1071. #endif // __ATLLCPAIR_H_