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.

1279 lines
37 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 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 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 < 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 WORD 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 WORD 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 WORD 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 WORD 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 WORD 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 < 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 WORD 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 WORD 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 WORD 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. //
  743. // Attach the controls to control member variables.
  744. //
  745. AttachControl( m_lvcRight, ADMC_IDC_LCP_RIGHT_LIST );
  746. AttachControl( m_lvcLeft, ADMC_IDC_LCP_LEFT_LIST );
  747. AttachControl( m_pbAdd, ADMC_IDC_LCP_ADD );
  748. AttachControl( m_pbRemove, ADMC_IDC_LCP_REMOVE );
  749. if ( BPropertiesButton() )
  750. {
  751. AttachControl( m_pbProperties, ADMC_IDC_LCP_PROPERTIES );
  752. } // if: dialog has Properties button
  753. if ( BCanBeOrdered() )
  754. {
  755. AttachControl( m_pbMoveUp, ADMC_IDC_LCP_MOVE_UP );
  756. AttachControl( m_pbMoveDown, ADMC_IDC_LCP_MOVE_DOWN );
  757. } // if: left list can be ordered
  758. // if ( BShowImages() )
  759. // {
  760. // CClusterAdminApp * papp = GetClusterAdminApp();
  761. //
  762. // m_lvcLeft.SetImageList( papp->PilSmallImages(), LVSIL_SMALL );
  763. // m_lvcRight.SetImageList( papp->PilSmallImages(), LVSIL_SMALL );
  764. // } // if: showing images
  765. //
  766. // Disable buttons by default.
  767. //
  768. m_pbAdd.EnableWindow( FALSE );
  769. m_pbRemove.EnableWindow( FALSE );
  770. if ( BPropertiesButton() )
  771. {
  772. m_pbProperties.EnableWindow( FALSE );
  773. } // if: dialog has Properties button
  774. //
  775. // Set the right list to sort if not ordered. Set both to show selection always.
  776. //
  777. if ( BOrdered() )
  778. {
  779. m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
  780. } // if: right list is ordered
  781. else
  782. {
  783. m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS | LVS_SORTASCENDING, 0 );
  784. } // else: right list is not ordered
  785. m_lvcLeft.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
  786. //
  787. // If this is an ordered list, show the Move buttons.
  788. // Otherwise, hide them.
  789. //
  790. if ( BCanBeOrdered() )
  791. {
  792. SetUpDownState();
  793. } // if: list can be ordered
  794. //
  795. // Change left list view control extended styles.
  796. //
  797. m_lvcLeft.SetExtendedListViewStyle(
  798. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
  799. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
  800. );
  801. //
  802. // Change right list view control extended styles.
  803. //
  804. m_lvcRight.SetExtendedListViewStyle(
  805. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
  806. LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
  807. );
  808. // Duplicate lists.
  809. DuplicateLists();
  810. //
  811. // Insert all the columns.
  812. //
  813. {
  814. int icol;
  815. int ncol;
  816. int nUpperBound = m_aColumns.size();
  817. CString strColText;
  818. ATLASSERT( nUpperBound > 0 );
  819. for ( icol = 0 ; icol < nUpperBound ; icol++ )
  820. {
  821. strColText.LoadString( m_aColumns[icol].m_idsText );
  822. ncol = m_lvcLeft.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
  823. ATLASSERT( ncol == icol );
  824. ncol = m_lvcRight.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
  825. ATLASSERT( ncol == icol );
  826. } // for: each column
  827. } // Insert all the columns
  828. //
  829. // Fill the list controls.
  830. //
  831. FillList( m_lvcRight, LpobjRight() );
  832. FillList( m_lvcLeft, LpobjLeft() );
  833. //
  834. // If read-only, set all controls to be either disabled or read-only.
  835. //
  836. if ( BReadOnly() )
  837. {
  838. m_lvcRight.EnableWindow( FALSE );
  839. m_lvcLeft.EnableWindow( FALSE );
  840. } // if: sheet is read-only
  841. //
  842. // Call the base class method.
  843. //
  844. return BaseT::OnInitDialog();
  845. } //*** OnInitDialog()
  846. // Handler for PSN_SETACTIVE
  847. BOOL OnSetActive( void )
  848. {
  849. UINT nSelCount;
  850. // Set the focus to the left list.
  851. m_lvcLeft.SetFocus();
  852. m_plvcFocusList = &m_lvcLeft;
  853. // Enable/disable the Properties button.
  854. nSelCount = m_lvcLeft.GetSelectedCount();
  855. if ( BPropertiesButton() )
  856. {
  857. m_pbProperties.EnableWindow( nSelCount == 1 );
  858. } // if: dialog has Properties button
  859. // Enable or disable the other buttons.
  860. if ( ! BReadOnly() )
  861. {
  862. m_pbAdd.EnableWindow( nSelCount > 0 );
  863. nSelCount = m_lvcRight.GetSelectedCount();
  864. m_pbRemove.EnableWindow( nSelCount > 0 );
  865. SetUpDownState();
  866. } // if: not read-only page
  867. return TRUE;
  868. } //*** OnSetActive()
  869. public:
  870. _objptrlist & LpobjRight( void ) { return m_lpobjRight; }
  871. _objptrlist & LpobjLeft( void ) { return m_lpobjLeft; }
  872. protected:
  873. void DuplicateLists( void )
  874. {
  875. LpobjRight().erase( LpobjRight().begin(), LpobjRight().end() );
  876. LpobjLeft().erase( LpobjLeft().begin(), LpobjLeft().end() );
  877. T * pT = static_cast< T * >( this );
  878. if ( (pT->PlpobjRight() == NULL) || (pT->PlpobjLeft() == NULL) )
  879. {
  880. return;
  881. } // if: either list is empty
  882. //
  883. // Duplicate the lists.
  884. //
  885. LpobjRight() = *pT->PlpobjRight();
  886. LpobjLeft() = *pT->PlpobjLeft();
  887. //
  888. // Remove all the items that are in the right list from
  889. // the left list.
  890. //
  891. _objptrlistit itRight;
  892. _objptrlistit itLeft;
  893. for ( itRight = LpobjRight().begin()
  894. ; itRight != LpobjRight().end()
  895. ; itRight++ )
  896. {
  897. //
  898. // Find the item in the left list.
  899. //
  900. itLeft = std::find( LpobjLeft().begin(), LpobjLeft().end(), *itRight );
  901. if ( itLeft != LpobjLeft().end() )
  902. {
  903. LpobjLeft().erase( itLeft );
  904. } // if: object found in left list
  905. } // for: each item in the right list
  906. } //*** DuplicateLists()
  907. // Fill a list control
  908. void FillList( IN OUT CListViewCtrl & rlvc, IN const _objptrlist & rlpobj )
  909. {
  910. _objptrlistit itpobj;
  911. ObjT * pobj;
  912. int iItem;
  913. // Initialize the control.
  914. if ( ! rlvc.DeleteAllItems() )
  915. {
  916. ATLASSERT( 0 );
  917. } // if: error deleting all items
  918. rlvc.SetItemCount( rlpobj.size() );
  919. // Add the items to the list.
  920. itpobj = rlpobj.begin();
  921. for ( iItem = 0 ; itpobj != rlpobj.end() ; iItem++, itpobj++ )
  922. {
  923. pobj = *itpobj;
  924. NInsertItemInListCtrl( iItem, pobj, rlvc );
  925. } // for: each string in the list
  926. // If there are any items, set the focus on the first one.
  927. if ( rlvc.GetItemCount() != 0)
  928. {
  929. rlvc.SetItemState( 0, LVIS_FOCUSED, LVIS_FOCUSED );
  930. } // if: items were added to the list
  931. } //*** FillList()
  932. // Move items from one list to another
  933. void MoveItems(
  934. IN OUT CListViewCtrl & rlvcDst,
  935. IN OUT _objptrlist & rlpobjDst,
  936. IN OUT CListViewCtrl & rlvcSrc,
  937. IN OUT _objptrlist & rlpobjSrc
  938. )
  939. {
  940. int iSrcItem;
  941. int iDstItem;
  942. int nItem = -1;
  943. ObjT * pobj;
  944. _objptrlistit itpobj;
  945. ATLASSERT( ! BReadOnly() );
  946. iDstItem = rlvcDst.GetItemCount();
  947. while ( (iSrcItem = rlvcSrc.GetNextItem( -1, LVNI_SELECTED )) != -1 )
  948. {
  949. // Get the item pointer.
  950. pobj = (ObjT *) rlvcSrc.GetItemData( iSrcItem );
  951. ATLASSERT( pobj );
  952. // Remove the item from the source list.
  953. itpobj = std::find( rlpobjSrc.begin(), rlpobjSrc.end(), pobj );
  954. ATLASSERT( itpobj != rlpobjSrc.end() );
  955. rlpobjSrc.remove( *itpobj );
  956. // Add the item to the destination list.
  957. rlpobjDst.insert( rlpobjDst.end(), pobj );
  958. // Remove the item from the source list control and
  959. // add it to the destination list control.
  960. if ( ! rlvcSrc.DeleteItem( iSrcItem ) )
  961. {
  962. ATLASSERT( 0 );
  963. } // if: error deleting the item
  964. nItem = NInsertItemInListCtrl( iDstItem++, pobj, rlvcDst );
  965. rlvcDst.SetItemState(
  966. nItem,
  967. LVIS_SELECTED | LVIS_FOCUSED,
  968. LVIS_SELECTED | LVIS_FOCUSED
  969. );
  970. } // while: more items
  971. ATLASSERT( nItem != -1 );
  972. rlvcDst.EnsureVisible( nItem, FALSE /*bPartialOK*/ );
  973. rlvcDst.SetFocus();
  974. // Indicate that the data has changed.
  975. ::SendMessage( GetParent(), PSM_CHANGED, (WPARAM) m_hWnd, NULL );
  976. } //*** MoveItems()
  977. BOOL BSaveChanges( void )
  978. {
  979. ATLASSERT( ! BIsStyleSet( LCPS_DONT_OUTPUT_RIGHT_LIST ) );
  980. ATLASSERT( ! BReadOnly() );
  981. T * pT = static_cast< T * >( this );
  982. //
  983. // Update the data first.
  984. //
  985. if ( ! pT->UpdateData( TRUE /*bSaveAndValidate*/ ) )
  986. {
  987. return FALSE;
  988. } // if: error updating data
  989. //
  990. // Copy the object list.
  991. //
  992. *pT->PlpobjRight() = LpobjRight();
  993. return TRUE;
  994. } //*** BSaveChanges()
  995. // Set the state of the Up/Down buttons based on the selection.
  996. void SetUpDownState( void )
  997. {
  998. BOOL bEnableUp;
  999. BOOL bEnableDown;
  1000. if ( BOrdered()
  1001. && ! BReadOnly()
  1002. && (m_lvcRight.GetSelectedCount() == 1) )
  1003. {
  1004. int nItem;
  1005. bEnableUp = TRUE;
  1006. bEnableDown = TRUE;
  1007. //
  1008. // Find the index of the selected item.
  1009. //
  1010. nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
  1011. ATLASSERT( nItem != -1 );
  1012. //
  1013. // If the first item is selected, can't move up.
  1014. //
  1015. if ( nItem == 0 )
  1016. {
  1017. bEnableUp = FALSE;
  1018. } // if: first item is selected
  1019. //
  1020. // If the last item is selected, can't move down.
  1021. //
  1022. if ( nItem == m_lvcRight.GetItemCount() - 1 )
  1023. {
  1024. bEnableDown = FALSE;
  1025. } // if: last item is selected
  1026. } // if: only one item selected
  1027. else
  1028. {
  1029. bEnableUp = FALSE;
  1030. bEnableDown = FALSE;
  1031. } // else: zero or more than one item selected
  1032. m_pbMoveUp.EnableWindow( bEnableUp );
  1033. m_pbMoveDown.EnableWindow( bEnableDown );
  1034. } //*** SetUpDownState()
  1035. static int CALLBACK CompareItems( LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort )
  1036. {
  1037. ObjT * pobj1 = reinterpret_cast< ObjT * >( lparam1 );
  1038. ObjT * pobj2 = reinterpret_cast< ObjT * >( lparam2 );
  1039. T * plcp = reinterpret_cast< T * >( lparamSort );
  1040. SortInfo * psiCur = plcp->PsiCur();
  1041. int icol = psiCur->m_nColumn;
  1042. int nResult;
  1043. CString str1;
  1044. CString str2;
  1045. ATLASSERT( pobj1 != NULL );
  1046. ATLASSERT( pobj2 != NULL );
  1047. ATLASSERT( plcp != NULL );
  1048. ATLASSERT( psiCur->m_nColumn >= 0 );
  1049. ATLASSERT( icol >= 0 );
  1050. plcp->GetColumnInfo( pobj1, 0, icol, str1, NULL );
  1051. plcp->GetColumnInfo( pobj2, 0, icol, str2, NULL );
  1052. nResult = str1.Compare( str2 );
  1053. // Return the result based on the direction we are sorting.
  1054. if ( psiCur->m_nDirection != 0 )
  1055. {
  1056. nResult = -nResult;
  1057. } // if: sorting in reverse direction
  1058. return nResult;
  1059. } //*** CompareItems()
  1060. SortInfo m_siLeft;
  1061. SortInfo m_siRight;
  1062. SortInfo * m_psiCur;
  1063. SortInfo & SiLeft( void ) { return m_siLeft; }
  1064. SortInfo & SiRight( void ) { return m_siRight; }
  1065. public:
  1066. SortInfo * PsiCur( void ) const { return m_psiCur; }
  1067. }; //*** class CListCtrlPair
  1068. /////////////////////////////////////////////////////////////////////////////
  1069. #endif // __ATLLCPAIR_H_