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.

1234 lines
34 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // LCPair.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the CListCtrlPair class.
  10. //
  11. // Author:
  12. // David Potter (davidp) August 8, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "CluAdmin.h"
  21. #include "LCPair.h"
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. /////////////////////////////////////////////////////////////////////////////
  28. // CListCtrlPair
  29. /////////////////////////////////////////////////////////////////////////////
  30. IMPLEMENT_DYNAMIC(CListCtrlPair, CCmdTarget)
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Message Maps
  33. BEGIN_MESSAGE_MAP(CListCtrlPair, CCmdTarget)
  34. //{{AFX_MSG_MAP(CListCtrlPair)
  35. //}}AFX_MSG_MAP
  36. ON_BN_CLICKED(IDC_LCP_ADD, OnAdd)
  37. ON_BN_CLICKED(IDC_LCP_REMOVE, OnRemove)
  38. ON_BN_CLICKED(IDC_LCP_PROPERTIES, OnProperties)
  39. ON_NOTIFY(NM_DBLCLK, IDC_LCP_LEFT_LIST, OnDblClkLeftList)
  40. ON_NOTIFY(NM_DBLCLK, IDC_LCP_RIGHT_LIST, OnDblClkRightList)
  41. ON_NOTIFY(LVN_ITEMCHANGED, IDC_LCP_LEFT_LIST, OnItemChangedLeftList)
  42. ON_NOTIFY(LVN_ITEMCHANGED, IDC_LCP_RIGHT_LIST, OnItemChangedRightList)
  43. ON_NOTIFY(LVN_COLUMNCLICK, IDC_LCP_LEFT_LIST, OnColumnClickLeftList)
  44. ON_NOTIFY(LVN_COLUMNCLICK, IDC_LCP_RIGHT_LIST, OnColumnClickRightList)
  45. ON_COMMAND(ID_FILE_PROPERTIES, OnProperties)
  46. END_MESSAGE_MAP()
  47. /////////////////////////////////////////////////////////////////////////////
  48. //++
  49. //
  50. // CListCtrlPair::CListCtrlPair
  51. //
  52. // Routine Description:
  53. // Default constructor.
  54. //
  55. // Arguments:
  56. // None.
  57. //
  58. // Return Value:
  59. // None.
  60. //
  61. //--
  62. /////////////////////////////////////////////////////////////////////////////
  63. CListCtrlPair::CListCtrlPair(void)
  64. {
  65. CommonConstruct();
  66. } //*** CListCtrlPair::CListCtrlPair()
  67. /////////////////////////////////////////////////////////////////////////////
  68. //++
  69. //
  70. // CListCtrlPair::CListCtrlPair
  71. //
  72. // Routine Description:
  73. // Cconstructor.
  74. //
  75. // Arguments:
  76. // pdlg [IN OUT] Dialog to which controls belong.
  77. // plpobjRight [IN OUT] List for the right list control.
  78. // plpobjLeft [IN] List for the left list control.
  79. // dwStyle [IN] Style:
  80. // LCPS_SHOW_IMAGES Show images to left of items.
  81. // LCPS_ALLOW_EMPTY Allow right list to be empty.
  82. // pfnGetColumn [IN] Function pointer for retrieving columns.
  83. // pfnDisplayProps [IN] Function pointer for displaying properties.
  84. //
  85. // Return Value:
  86. // None.
  87. //
  88. //--
  89. /////////////////////////////////////////////////////////////////////////////
  90. CListCtrlPair::CListCtrlPair(
  91. IN OUT CDialog * pdlg,
  92. IN OUT CClusterItemList * plpobjRight,
  93. IN const CClusterItemList * plpobjLeft,
  94. IN DWORD dwStyle,
  95. IN PFNLCPGETCOLUMN pfnGetColumn,
  96. IN PFNLCPDISPPROPS pfnDisplayProps
  97. )
  98. {
  99. ASSERT(pfnGetColumn != NULL);
  100. ASSERT(pfnDisplayProps != NULL);
  101. CommonConstruct();
  102. m_pdlg = pdlg;
  103. if (plpobjRight != NULL)
  104. m_plpobjRight = plpobjRight;
  105. if (plpobjLeft != NULL)
  106. m_plpobjLeft = plpobjLeft;
  107. m_dwStyle = dwStyle;
  108. m_pfnGetColumn = pfnGetColumn;
  109. m_pfnDisplayProps = pfnDisplayProps;
  110. } //*** CListCtrlPair::CListCtrlPair()
  111. /////////////////////////////////////////////////////////////////////////////
  112. //++
  113. //
  114. // CListCtrlPair::CommonConstruct
  115. //
  116. // Routine Description:
  117. // Common construction.
  118. //
  119. // Arguments:
  120. // None.
  121. //
  122. // Return Value:
  123. // None.
  124. //
  125. //--
  126. /////////////////////////////////////////////////////////////////////////////
  127. void CListCtrlPair::CommonConstruct(void)
  128. {
  129. m_pdlg = NULL;
  130. m_plpobjLeft = NULL;
  131. m_plpobjRight = NULL;
  132. m_dwStyle = LCPS_ALLOW_EMPTY;
  133. m_pfnGetColumn = NULL;
  134. m_plcFocusList = NULL;
  135. // Set the sort info.
  136. SiLeft().m_nDirection = -1;
  137. SiLeft().m_nColumn = -1;
  138. SiRight().m_nDirection = -1;
  139. SiRight().m_nColumn = -1;
  140. } //*** CListCtrlPair::CommonConstruct()
  141. /////////////////////////////////////////////////////////////////////////////
  142. //++
  143. //
  144. // CListCtrlPair::NAddColumn
  145. //
  146. // Routine Description:
  147. // Add a column to the list of columns displayed in each list control.
  148. //
  149. // Arguments:
  150. // idsText [IN] String resource ID for text to display on column.
  151. // nWidth [IN] Initial width of the column.
  152. //
  153. // Return Value:
  154. // icol Index of the column.
  155. //
  156. // Exceptions Thrown:
  157. // Any exceptions thrown by CArray::Add.
  158. //--
  159. /////////////////////////////////////////////////////////////////////////////
  160. int CListCtrlPair::NAddColumn(IN IDS idsText, IN int nWidth)
  161. {
  162. CColumn col;
  163. ASSERT(idsText != 0);
  164. ASSERT(nWidth > 0);
  165. ASSERT(LpobjRight().GetCount() == 0);
  166. col.m_idsText = idsText;
  167. col.m_nWidth = nWidth;
  168. return (int)m_aColumns.Add(col);
  169. } //*** CListCtrlPair::NAddColumn()
  170. /////////////////////////////////////////////////////////////////////////////
  171. //++
  172. //
  173. // CListCtrlPair::DoDataExchange
  174. //
  175. // Routine Description:
  176. // Do data exchange between the dialog and the class.
  177. //
  178. // Arguments:
  179. // pDX [IN OUT] Data exchange object
  180. //
  181. // Return Value:
  182. // None.
  183. //
  184. //--
  185. /////////////////////////////////////////////////////////////////////////////
  186. void CListCtrlPair::DoDataExchange(CDataExchange * pDX)
  187. {
  188. DDX_Control(pDX, IDC_LCP_RIGHT_LIST, m_lcRight);
  189. DDX_Control(pDX, IDC_LCP_LEFT_LIST, m_lcLeft);
  190. DDX_Control(pDX, IDC_LCP_ADD, m_pbAdd);
  191. DDX_Control(pDX, IDC_LCP_REMOVE, m_pbRemove);
  192. if (BPropertiesButton())
  193. DDX_Control(pDX, IDC_LCP_PROPERTIES, m_pbProperties);
  194. if (pDX->m_bSaveAndValidate)
  195. {
  196. // Verify that the list is not empty.
  197. if (!BAllowEmpty() && (m_lcRight.GetItemCount() == 0))
  198. {
  199. CString strMsg;
  200. CString strLabel;
  201. TCHAR * pszLabel;
  202. TCHAR szStrippedLabel[1024];
  203. int iSrc;
  204. int iDst;
  205. TCHAR ch;
  206. DDX_Text(pDX, IDC_LCP_RIGHT_LABEL, strLabel);
  207. // Remove ampersands (&) and colons (:).
  208. pszLabel = strLabel.GetBuffer(1);
  209. for (iSrc = 0, iDst = 0 ; pszLabel[iSrc] != _T('\0') ; iSrc++)
  210. {
  211. ch = pszLabel[iSrc];
  212. if ((ch != _T('&')) && (ch != _T(':')))
  213. szStrippedLabel[iDst++] = ch;
  214. } // for: each character in the label
  215. szStrippedLabel[iDst] = _T('\0');
  216. strMsg.FormatMessage(IDS_EMPTY_RIGHT_LIST, szStrippedLabel);
  217. ::AfxMessageBox(strMsg, MB_OK | MB_ICONWARNING);
  218. strMsg.Empty();
  219. pDX->Fail();
  220. } // if: list is empty and isn't allowed to be
  221. } // if: saving data from the dialog
  222. else
  223. {
  224. // Fill the lists.
  225. if (m_plpobjRight != NULL)
  226. FillList(m_lcRight, LpobjRight());
  227. if (m_plpobjLeft != NULL)
  228. FillList(m_lcLeft, LpobjLeft());
  229. } // else: setting data to the dialog
  230. } //*** CListCtrlPair::DoDataExchange()
  231. /////////////////////////////////////////////////////////////////////////////
  232. //++
  233. //
  234. // CListCtrlPair::OnInitDialog
  235. //
  236. // Routine Description:
  237. // Handler for the WM_INITDIALOG message.
  238. //
  239. // Arguments:
  240. // None.
  241. //
  242. // Return Value:
  243. // TRUE Focus needs to be set.
  244. // FALSE Focus already set.
  245. //
  246. //--
  247. /////////////////////////////////////////////////////////////////////////////
  248. BOOL CListCtrlPair::OnInitDialog(void)
  249. {
  250. ASSERT_VALID(Pdlg());
  251. ASSERT(PlpobjRight() != NULL);
  252. ASSERT(PlpobjLeft() != NULL);
  253. Pdlg()->UpdateData(FALSE /*bSaveAndValidate*/);
  254. if (BShowImages())
  255. {
  256. CClusterAdminApp * papp = GetClusterAdminApp();
  257. m_lcLeft.SetImageList(papp->PilSmallImages(), LVSIL_SMALL);
  258. m_lcRight.SetImageList(papp->PilSmallImages(), LVSIL_SMALL);
  259. } // if: showing images
  260. // Disable buttons by default.
  261. m_pbAdd.EnableWindow(FALSE);
  262. m_pbRemove.EnableWindow(FALSE);
  263. if (BPropertiesButton())
  264. m_pbProperties.EnableWindow(FALSE);
  265. // Set the right list to sort. Set both to show selection always.
  266. m_lcRight.ModifyStyle(0, LVS_SHOWSELALWAYS | LVS_SORTASCENDING, 0);
  267. m_lcLeft.ModifyStyle(0, LVS_SHOWSELALWAYS, 0);
  268. // Change list view control extended styles.
  269. {
  270. DWORD dwExtendedStyle;
  271. // Left control.
  272. dwExtendedStyle = (DWORD)m_lcLeft.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE);
  273. m_lcLeft.SendMessage(
  274. LVM_SETEXTENDEDLISTVIEWSTYLE,
  275. 0,
  276. dwExtendedStyle
  277. | LVS_EX_FULLROWSELECT
  278. | LVS_EX_HEADERDRAGDROP
  279. );
  280. // Right control.
  281. dwExtendedStyle = (DWORD)m_lcRight.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE);
  282. m_lcRight.SendMessage(
  283. LVM_SETEXTENDEDLISTVIEWSTYLE,
  284. 0,
  285. dwExtendedStyle
  286. | LVS_EX_FULLROWSELECT
  287. | LVS_EX_HEADERDRAGDROP
  288. );
  289. } // Change list view control extended styles
  290. try
  291. {
  292. // Duplicate lists.
  293. DuplicateLists();
  294. // Insert all the columns.
  295. {
  296. int icol;
  297. int ncol;
  298. int nUpperBound = (int)m_aColumns.GetUpperBound();
  299. CString strColText;
  300. ASSERT(nUpperBound >= 0);
  301. for (icol = 0 ; icol <= nUpperBound ; icol++)
  302. {
  303. strColText.LoadString(m_aColumns[icol].m_idsText);
  304. ncol = m_lcLeft.InsertColumn(icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0);
  305. ASSERT(ncol == icol);
  306. ncol = m_lcRight.InsertColumn(icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0);
  307. ASSERT(ncol == icol);
  308. } // for: each column
  309. } // Insert all the columns
  310. } // try
  311. catch (CException * pe)
  312. {
  313. pe->Delete();
  314. } // catch: CException
  315. Pdlg()->UpdateData(FALSE /*bSaveAndValidate*/);
  316. // If read-only, set all controls to be either disabled or read-only.
  317. if (BReadOnly())
  318. {
  319. m_lcRight.EnableWindow(FALSE);
  320. m_lcLeft.EnableWindow(FALSE);
  321. } // if: sheet is read-only
  322. return TRUE; // return TRUE unless you set the focus to a control
  323. // EXCEPTION: OCX Property Pages should return FALSE
  324. } //*** CListCtrlPair::OnInitDialog()
  325. /////////////////////////////////////////////////////////////////////////////
  326. //++
  327. //
  328. // CListCtrlPair::OnSetActive
  329. //
  330. // Routine Description:
  331. // Handler for the PSN_SETACTIVE message.
  332. //
  333. // Arguments:
  334. // None.
  335. //
  336. // Return Value:
  337. // TRUE Page successfully initialized.
  338. // FALSE Page not initialized.
  339. //
  340. //--
  341. /////////////////////////////////////////////////////////////////////////////
  342. BOOL CListCtrlPair::OnSetActive(void)
  343. {
  344. UINT nSelCount;
  345. // Set the focus to the left list.
  346. m_lcLeft.SetFocus();
  347. m_plcFocusList = &m_lcLeft;
  348. // Enable/disable the Properties button.
  349. nSelCount = m_lcLeft.GetSelectedCount();
  350. if (BPropertiesButton())
  351. m_pbProperties.EnableWindow(nSelCount == 1);
  352. // Enable or disable the other buttons.
  353. if (!BReadOnly())
  354. {
  355. m_pbAdd.EnableWindow(nSelCount > 0);
  356. nSelCount = m_lcRight.GetSelectedCount();
  357. m_pbRemove.EnableWindow(nSelCount > 0);
  358. } // if: not read-only page
  359. return TRUE;
  360. } //*** CListCtrlPair::OnSetActive()
  361. /////////////////////////////////////////////////////////////////////////////
  362. //++
  363. //
  364. // CListCtrlPair::BSaveChanges
  365. //
  366. // Routine Description:
  367. // Handler for the BN_CLICKED message on the OK button.
  368. //
  369. // Arguments:
  370. // None.
  371. //
  372. // Return Value:
  373. // TRUE Changes saved successfully.
  374. // FALSE Error saving changes.
  375. //
  376. //--
  377. /////////////////////////////////////////////////////////////////////////////
  378. BOOL CListCtrlPair::BSaveChanges(void)
  379. {
  380. POSITION pos;
  381. CClusterItem * pci;
  382. ASSERT(!BIsStyleSet(LCPS_DONT_OUTPUT_RIGHT_LIST));
  383. ASSERT(!BReadOnly());
  384. // Update the data first.
  385. if (!Pdlg()->UpdateData(TRUE /*bSaveAndValidate*/))
  386. return FALSE;
  387. // Copy the Nodes list.
  388. PlpobjRight()->RemoveAll();
  389. pos = LpobjRight().GetHeadPosition();
  390. while (pos != NULL)
  391. {
  392. pci = LpobjRight().GetNext(pos);
  393. ASSERT_VALID(pci);
  394. VERIFY(PlpobjRight()->AddTail(pci) != NULL);
  395. } // while: more items in the list
  396. return TRUE;
  397. } //*** CListCtrlPair::BSaveChanges()
  398. /////////////////////////////////////////////////////////////////////////////
  399. //++
  400. //
  401. // CListCtrlPair::OnAdd
  402. //
  403. // Routine Description:
  404. // Handler for the BN_CLICKED message on the Add button.
  405. //
  406. // Arguments:
  407. // None.
  408. //
  409. // Return Value:
  410. // None.
  411. //
  412. //--
  413. /////////////////////////////////////////////////////////////////////////////
  414. void CListCtrlPair::OnAdd(void)
  415. {
  416. ASSERT(!BReadOnly());
  417. // Move selected items from the left list to the right list.
  418. MoveItems(m_lcRight, LpobjRight(), m_lcLeft, LpobjLeft());
  419. } //*** CListCtrlPair::OnAdd()
  420. /////////////////////////////////////////////////////////////////////////////
  421. //++
  422. //
  423. // CListCtrlPair::OnRemove
  424. //
  425. // Routine Description:
  426. // Handler for the BN_CLICKED message on the Remove button.
  427. //
  428. // Arguments:
  429. // None.
  430. //
  431. // Return Value:
  432. // None.
  433. //
  434. //--
  435. /////////////////////////////////////////////////////////////////////////////
  436. void CListCtrlPair::OnRemove(void)
  437. {
  438. ASSERT(!BReadOnly());
  439. // Move selected items from the right list to the left list.
  440. MoveItems(m_lcLeft, LpobjLeft(), m_lcRight, LpobjRight());
  441. } //*** CListCtrlPair::OnRemove()
  442. /////////////////////////////////////////////////////////////////////////////
  443. //++
  444. //
  445. // CListCtrlPair::OnProperties
  446. //
  447. // Routine Description:
  448. // Handler for the BN_CLICKED message on the Properties button.
  449. //
  450. // Arguments:
  451. // None.
  452. //
  453. // Return Value:
  454. // None.
  455. //
  456. //--
  457. /////////////////////////////////////////////////////////////////////////////
  458. void CListCtrlPair::OnProperties(void)
  459. {
  460. int iitem;
  461. CObject * pobj;
  462. ASSERT(m_plcFocusList != NULL);
  463. ASSERT(m_pfnDisplayProps != NULL);
  464. // Get the index of the item with the focus.
  465. iitem = m_plcFocusList->GetNextItem(-1, LVNI_FOCUSED);
  466. ASSERT(iitem != -1);
  467. // Get a pointer to the selected item.
  468. pobj = (CObject *) m_plcFocusList->GetItemData(iitem);
  469. ASSERT_VALID(pobj);
  470. if ((*m_pfnDisplayProps)(pobj))
  471. {
  472. // Update this item.
  473. {
  474. CString strText;
  475. int iimg;
  476. int icol;
  477. ASSERT(m_pfnGetColumn != NULL);
  478. ASSERT(Pdlg() != NULL);
  479. (*m_pfnGetColumn)(pobj, iitem, 0, Pdlg(), strText, &iimg);
  480. m_plcFocusList->SetItem(iitem, 0, LVIF_TEXT | LVIF_IMAGE, strText, iimg, 0, 0, 0);
  481. for (icol = 1 ; icol <= m_aColumns.GetUpperBound() ; icol++)
  482. {
  483. (*m_pfnGetColumn)(pobj, iitem, icol, Pdlg(), strText, NULL);
  484. m_plcFocusList->SetItemText(iitem, icol, strText);
  485. } // for: each column
  486. } // Update this item
  487. } // if: properties changed
  488. } //*** CListCtrlPair::OnProperties()
  489. /////////////////////////////////////////////////////////////////////////////
  490. //++
  491. //
  492. // CListCtrlPair::OnContextMenu
  493. //
  494. // Routine Description:
  495. // Handler for the WM_CONTEXTMENU method.
  496. //
  497. // Arguments:
  498. // pWnd Window in which the user right clicked the mouse.
  499. // point Position of the cursor, in screen coordinates.
  500. //
  501. // Return Value:
  502. // None.
  503. //
  504. //--
  505. /////////////////////////////////////////////////////////////////////////////
  506. BOOL CListCtrlPair::OnContextMenu(CWnd * pWnd, CPoint point)
  507. {
  508. BOOL bHandled = FALSE;
  509. CMenu * pmenu = NULL;
  510. CListCtrl * pListCtrl = (CListCtrl *) pWnd;
  511. CString strMenuName;
  512. CWaitCursor wc;
  513. // If focus is not in the list control, don't handle the message.
  514. if ( ( pWnd != &m_lcRight ) && ( pWnd != &m_lcLeft ) )
  515. {
  516. return FALSE;
  517. } // if: focus not in list control
  518. // Create the menu to display.
  519. try
  520. {
  521. pmenu = new CMenu;
  522. if ( pmenu == NULL )
  523. {
  524. AfxThrowMemoryException();
  525. } // if: error allocating the memory
  526. if ( pmenu->CreatePopupMenu() )
  527. {
  528. UINT nFlags = MF_STRING;
  529. // If there are no items in the list, disable the menu item.
  530. if ( pListCtrl->GetItemCount() == 0 )
  531. {
  532. nFlags |= MF_GRAYED;
  533. } // if: no items in the list
  534. // Add the Properties item to the menu.
  535. strMenuName.LoadString( IDS_MENU_PROPERTIES );
  536. if ( pmenu->AppendMenu( nFlags, ID_FILE_PROPERTIES, strMenuName ) )
  537. {
  538. m_plcFocusList = pListCtrl;
  539. bHandled = TRUE;
  540. } // if: successfully added menu item
  541. } // if: menu created successfully
  542. } // try
  543. catch ( CException * pe )
  544. {
  545. pe->ReportError();
  546. pe->Delete();
  547. } // catch: CException
  548. if ( bHandled )
  549. {
  550. // Display the menu.
  551. if ( ! pmenu->TrackPopupMenu(
  552. TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  553. point.x,
  554. point.y,
  555. Pdlg()
  556. ) )
  557. {
  558. } // if: unsuccessfully displayed the menu
  559. } // if: there is a menu to display
  560. delete pmenu;
  561. return bHandled;
  562. } //*** CListCtrlPair::OnContextMenu()
  563. /////////////////////////////////////////////////////////////////////////////
  564. //++
  565. //
  566. // CListCtrlPair::OnDblClkLeftList
  567. //
  568. // Routine Description:
  569. // Handler method for the NM_DBLCLK message for the left list.
  570. //
  571. // Arguments:
  572. // pNMHDR Notification message structure.
  573. // pResult Place in which to return the result.
  574. //
  575. // Return Value:
  576. // None.
  577. //
  578. //--
  579. /////////////////////////////////////////////////////////////////////////////
  580. void CListCtrlPair::OnDblClkLeftList(NMHDR * pNMHDR, LRESULT * pResult)
  581. {
  582. ASSERT(!BReadOnly());
  583. m_plcFocusList = &m_lcLeft;
  584. OnAdd();
  585. *pResult = 0;
  586. } //*** CListCtrlPair::OnDblClkLeftList()
  587. /////////////////////////////////////////////////////////////////////////////
  588. //++
  589. //
  590. // CListCtrlPair::OnDblClkRightList
  591. //
  592. // Routine Description:
  593. // Handler method for the NM_DBLCLK message for the right list.
  594. //
  595. // Arguments:
  596. // pNMHDR Notification message structure.
  597. // pResult Place in which to return the result.
  598. //
  599. // Return Value:
  600. // None.
  601. //
  602. //--
  603. /////////////////////////////////////////////////////////////////////////////
  604. void CListCtrlPair::OnDblClkRightList(NMHDR * pNMHDR, LRESULT * pResult)
  605. {
  606. ASSERT(!BReadOnly());
  607. m_plcFocusList = &m_lcRight;
  608. OnRemove();
  609. *pResult = 0;
  610. } //*** CListCtrlPair::OnDblClkRightList()
  611. /////////////////////////////////////////////////////////////////////////////
  612. //++
  613. //
  614. // CListCtrlPair::OnItemChangedLeftList
  615. //
  616. // Routine Description:
  617. // Handler method for the LVN_ITEMCHANGED message in the left list.
  618. //
  619. // Arguments:
  620. // pNMHDR [IN OUT] WM_NOTIFY structure.
  621. // pResult [OUT] LRESULT in which to return the result of this operation.
  622. //
  623. // Return Value:
  624. // None.
  625. //
  626. //--
  627. /////////////////////////////////////////////////////////////////////////////
  628. void CListCtrlPair::OnItemChangedLeftList(NMHDR * pNMHDR, LRESULT * pResult)
  629. {
  630. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR;
  631. m_plcFocusList = &m_lcLeft;
  632. // If the selection changed, enable/disable the Add button.
  633. if ((pNMListView->uChanged & LVIF_STATE)
  634. && ((pNMListView->uOldState & LVIS_SELECTED)
  635. || (pNMListView->uNewState & LVIS_SELECTED))
  636. && !BReadOnly())
  637. {
  638. UINT cSelected = m_plcFocusList->GetSelectedCount();
  639. // If there is a selection, enable the Add button. Otherwise disable it.
  640. m_pbAdd.EnableWindow((cSelected == 0) ? FALSE : TRUE);
  641. if (BPropertiesButton())
  642. m_pbProperties.EnableWindow((cSelected == 1) ? TRUE : FALSE);
  643. } // if: selection changed
  644. *pResult = 0;
  645. } //*** CListCtrlPair::OnItemChangedLeftList()
  646. /////////////////////////////////////////////////////////////////////////////
  647. //++
  648. //
  649. // CListCtrlPair::OnItemChangedRightList
  650. //
  651. // Routine Description:
  652. // Handler method for the LVN_ITEMCHANGED message in the right list.
  653. //
  654. // Arguments:
  655. // pNMHDR [IN OUT] WM_NOTIFY structure.
  656. // pResult [OUT] LRESULT in which to return the result of this operation.
  657. //
  658. // Return Value:
  659. // None.
  660. //
  661. //--
  662. /////////////////////////////////////////////////////////////////////////////
  663. void CListCtrlPair::OnItemChangedRightList(NMHDR * pNMHDR, LRESULT * pResult)
  664. {
  665. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR;
  666. m_plcFocusList = &m_lcRight;
  667. // If the selection changed, enable/disable the Remove button.
  668. if ((pNMListView->uChanged & LVIF_STATE)
  669. && ((pNMListView->uOldState & LVIS_SELECTED)
  670. || (pNMListView->uNewState & LVIS_SELECTED))
  671. && !BReadOnly())
  672. {
  673. UINT cSelected = m_plcFocusList->GetSelectedCount();
  674. // If there is a selection, enable the Remove button. Otherwise disable it.
  675. m_pbRemove.EnableWindow((cSelected == 0) ? FALSE : TRUE);
  676. if (BPropertiesButton())
  677. m_pbProperties.EnableWindow((cSelected == 1) ? TRUE : FALSE);
  678. } // if: selection changed
  679. *pResult = 0;
  680. } //*** CListCtrlPair::OnItemChangedRightList()
  681. /////////////////////////////////////////////////////////////////////////////
  682. //++
  683. //
  684. // CListCtrlPair::OnColumnClickLeftList
  685. //
  686. // Routine Description:
  687. // Handler method for the LVN_COLUMNCLICK message on the left list.
  688. //
  689. // Arguments:
  690. // None.
  691. //
  692. // Return Value:
  693. // None.
  694. //
  695. //--
  696. /////////////////////////////////////////////////////////////////////////////
  697. void CListCtrlPair::OnColumnClickLeftList(NMHDR * pNMHDR, LRESULT * pResult)
  698. {
  699. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR;
  700. ASSERT(m_pfnGetColumn != NULL);
  701. m_plcFocusList = &m_lcLeft;
  702. // Save the current sort column and direction.
  703. if (pNMListView->iSubItem == SiLeft().m_nColumn)
  704. SiLeft().m_nDirection ^= -1;
  705. else
  706. {
  707. SiLeft().m_nColumn = pNMListView->iSubItem;
  708. SiLeft().m_nDirection = 0;
  709. } // else: different column
  710. // Sort the list.
  711. m_psiCur = &SiLeft();
  712. VERIFY(m_lcLeft.SortItems(CompareItems, (LPARAM) this));
  713. *pResult = 0;
  714. } //*** CListCtrlPair::OnColumnClickLeftList()
  715. /////////////////////////////////////////////////////////////////////////////
  716. //++
  717. //
  718. // CListCtrlPair::OnColumnClickRightList
  719. //
  720. // Routine Description:
  721. // Handler method for the LVN_COLUMNCLICK message on the right list.
  722. //
  723. // Arguments:
  724. // None.
  725. //
  726. // Return Value:
  727. // None.
  728. //
  729. //--
  730. /////////////////////////////////////////////////////////////////////////////
  731. void CListCtrlPair::OnColumnClickRightList(NMHDR * pNMHDR, LRESULT * pResult)
  732. {
  733. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR;
  734. ASSERT(m_pfnGetColumn != NULL);
  735. m_plcFocusList = &m_lcRight;
  736. // Save the current sort column and direction.
  737. if (pNMListView->iSubItem == SiRight().m_nColumn)
  738. SiRight().m_nDirection ^= -1;
  739. else
  740. {
  741. SiRight().m_nColumn = pNMListView->iSubItem;
  742. SiRight().m_nDirection = 0;
  743. } // else: different column
  744. // Sort the list.
  745. m_psiCur = &SiRight();
  746. VERIFY(m_lcRight.SortItems(CompareItems, (LPARAM) this));
  747. *pResult = 0;
  748. } //*** CListCtrlPair::OnColumnClickRightList()
  749. /////////////////////////////////////////////////////////////////////////////
  750. //++
  751. //
  752. // CListCtrlPair::CompareItems [static]
  753. //
  754. // Routine Description:
  755. // Callback function for the CListCtrl::SortItems method.
  756. //
  757. // Arguments:
  758. // lparam1 First item to compare.
  759. // lparam2 Second item to compare.
  760. // lparamSort Sort parameter.
  761. //
  762. // Return Value:
  763. // -1 First parameter comes before second.
  764. // 0 First and second parameters are the same.
  765. // 1 First parameter comes after second.
  766. //
  767. //--
  768. /////////////////////////////////////////////////////////////////////////////
  769. int CALLBACK CListCtrlPair::CompareItems(
  770. LPARAM lparam1,
  771. LPARAM lparam2,
  772. LPARAM lparamSort
  773. )
  774. {
  775. CObject * pobj1 = (CObject *) lparam1;
  776. CObject * pobj2 = (CObject *) lparam2;
  777. CListCtrlPair * plcp = (CListCtrlPair *) lparamSort;
  778. int icol = plcp->PsiCur()->m_nColumn;
  779. int nResult;
  780. CString str1;
  781. CString str2;
  782. ASSERT_VALID(pobj1);
  783. ASSERT_VALID(pobj2);
  784. ASSERT(plcp != NULL);
  785. ASSERT(plcp->PsiCur()->m_nColumn >= 0);
  786. ASSERT(icol >= 0);
  787. (*plcp->m_pfnGetColumn)(pobj1, 0, icol, plcp->Pdlg(), str1, NULL);
  788. (*plcp->m_pfnGetColumn)(pobj2, 0, icol, plcp->Pdlg(), str2, NULL);
  789. // Compare the two strings.
  790. // Use CompareString() so that it will sort properly on localized builds.
  791. nResult = CompareString(
  792. LOCALE_USER_DEFAULT,
  793. 0,
  794. str1,
  795. str1.GetLength(),
  796. str2,
  797. str2.GetLength()
  798. );
  799. if ( nResult == CSTR_LESS_THAN )
  800. {
  801. nResult = -1;
  802. }
  803. else if ( nResult == CSTR_EQUAL )
  804. {
  805. nResult = 0;
  806. }
  807. else if ( nResult == CSTR_GREATER_THAN )
  808. {
  809. nResult = 1;
  810. }
  811. else
  812. {
  813. // An error occurred. Ignore it.
  814. nResult = 0;
  815. }
  816. // Return the result based on the direction we are sorting.
  817. if (plcp->PsiCur()->m_nDirection != 0)
  818. nResult = -nResult;
  819. return nResult;
  820. } //*** CListCtrlPair::CompareItems()
  821. /////////////////////////////////////////////////////////////////////////////
  822. //++
  823. //
  824. // CListCtrlPair::SetLists
  825. //
  826. // Routine Description:
  827. // Set the lists for the list control pair.
  828. //
  829. // Arguments:
  830. // plpobjRight [IN OUT] List for the right list box.
  831. // plpobjLeft [IN] List for the left list box.
  832. //
  833. // Return Value:
  834. // None.
  835. //
  836. //--
  837. /////////////////////////////////////////////////////////////////////////////
  838. void CListCtrlPair::SetLists(
  839. IN OUT CClusterItemList * plpobjRight,
  840. IN const CClusterItemList * plpobjLeft
  841. )
  842. {
  843. if (plpobjRight != NULL)
  844. m_plpobjRight = plpobjRight;
  845. if (plpobjLeft != NULL)
  846. m_plpobjLeft = plpobjLeft;
  847. DuplicateLists();
  848. } //*** CListCtrlPair::SetLists()
  849. /////////////////////////////////////////////////////////////////////////////
  850. //++
  851. //
  852. // CListCtrlPair::SetLists
  853. //
  854. // Routine Description:
  855. // Set the lists for the list control pair where the right list should
  856. // not be modified.
  857. //
  858. // Arguments:
  859. // plpobjRight [IN] List for the right list box.
  860. // plpobjLeft [IN] List for the left list box.
  861. //
  862. // Return Value:
  863. // None.
  864. //
  865. //--
  866. /////////////////////////////////////////////////////////////////////////////
  867. void CListCtrlPair::SetLists(
  868. IN const CClusterItemList * plpobjRight,
  869. IN const CClusterItemList * plpobjLeft
  870. )
  871. {
  872. m_dwStyle |= LCPS_DONT_OUTPUT_RIGHT_LIST;
  873. SetLists((CClusterItemList *) plpobjRight, plpobjLeft);
  874. } //*** CListCtrlPair::SetLists()
  875. /////////////////////////////////////////////////////////////////////////////
  876. //++
  877. //
  878. // CListCtrlPair::DuplicateLists
  879. //
  880. // Routine Description:
  881. // Duplicate the lists so that we have local copies.
  882. //
  883. // Arguments:
  884. // rlc [IN OUT] List control to fill.
  885. // rlpobj [IN] List to use to fill the control.
  886. //
  887. // Return Value:
  888. // None.
  889. //
  890. //--
  891. /////////////////////////////////////////////////////////////////////////////
  892. void CListCtrlPair::DuplicateLists(void)
  893. {
  894. LpobjRight().RemoveAll();
  895. LpobjLeft().RemoveAll();
  896. if ((PlpobjRight() == NULL) || (PlpobjLeft() == NULL))
  897. return;
  898. // Duplicate the right list.
  899. {
  900. POSITION pos;
  901. CClusterItem * pci;
  902. pos = PlpobjRight()->GetHeadPosition();
  903. while (pos != NULL)
  904. {
  905. // Get the item pointer.
  906. pci = PlpobjRight()->GetNext(pos);
  907. ASSERT_VALID(pci);
  908. // Add it to our list.
  909. LpobjRight().AddTail(pci);
  910. } // while: more items in the list
  911. } // Duplicate the right list
  912. // Duplicate the left list.
  913. {
  914. POSITION pos;
  915. CClusterItem * pci;
  916. pos = PlpobjLeft()->GetHeadPosition();
  917. while (pos != NULL)
  918. {
  919. // Get the item pointer.
  920. pci = PlpobjLeft()->GetNext(pos);
  921. ASSERT_VALID(pci);
  922. // If the item is not already in the other list,
  923. // add it to the left list.
  924. if (LpobjRight().Find(pci) == NULL)
  925. LpobjLeft().AddTail(pci);
  926. } // while: more items in the list
  927. } // Duplicate the left list
  928. } //*** CListCtrlPair::DuplicateLists()
  929. /////////////////////////////////////////////////////////////////////////////
  930. //++
  931. //
  932. // CListCtrlPair::FillList
  933. //
  934. // Routine Description:
  935. // Fill a list control.
  936. //
  937. // Arguments:
  938. // rlc [IN OUT] List control to fill.
  939. // rlpobj [IN] List to use to fill the control.
  940. //
  941. // Return Value:
  942. // None.
  943. //
  944. //--
  945. /////////////////////////////////////////////////////////////////////////////
  946. void CListCtrlPair::FillList(
  947. IN OUT CListCtrl & rlc,
  948. IN const CClusterItemList & rlpobj
  949. )
  950. {
  951. POSITION pos;
  952. CObject * pobj;
  953. int iItem;
  954. // Initialize the control.
  955. VERIFY(rlc.DeleteAllItems());
  956. rlc.SetItemCount((int)rlpobj.GetCount());
  957. // Add the items to the list.
  958. pos = rlpobj.GetHeadPosition();
  959. for (iItem = 0 ; pos != NULL ; iItem++)
  960. {
  961. pobj = rlpobj.GetNext(pos);
  962. ASSERT_VALID(pobj);
  963. NInsertItemInListCtrl(iItem, pobj, rlc);
  964. } // for: each string in the list
  965. // If there are any items, set the focus on the first one.
  966. if (rlc.GetItemCount() != 0)
  967. rlc.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
  968. } //*** CListCtrlPair::FillList()
  969. /////////////////////////////////////////////////////////////////////////////
  970. //++
  971. //
  972. // CListCtrlPair::NInsertItemInListCtrl
  973. //
  974. // Routine Description:
  975. // Insert an item in a list control.
  976. //
  977. // Arguments:
  978. // iitem [IN] Index of the item in the list.
  979. // pobj [IN OUT] Item to add.
  980. // rlc [IN OUT] List control in which to insert the item.
  981. //
  982. // Return Value:
  983. // iRetItem Index of the new item in the list control.
  984. //
  985. //--
  986. /////////////////////////////////////////////////////////////////////////////
  987. int CListCtrlPair::NInsertItemInListCtrl(
  988. IN int iitem,
  989. IN OUT CObject * pobj,
  990. IN OUT CListCtrl & rlc
  991. )
  992. {
  993. int iRetItem;
  994. CString strText;
  995. int iimg;
  996. int icol;
  997. ASSERT(m_pfnGetColumn != NULL);
  998. ASSERT(Pdlg() != NULL);
  999. // Insert the first column.
  1000. (*m_pfnGetColumn)(pobj, iitem, 0, Pdlg(), strText, &iimg);
  1001. iRetItem = rlc.InsertItem(
  1002. LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, // nMask
  1003. iitem, // nItem
  1004. strText, // lpszItem
  1005. 0, // nState
  1006. 0, // nStateMask
  1007. iimg, // nImage
  1008. (LPARAM) pobj // lParam
  1009. );
  1010. ASSERT(iRetItem != -1);
  1011. for (icol = 1 ; icol <= m_aColumns.GetUpperBound() ; icol++)
  1012. {
  1013. (*m_pfnGetColumn)(pobj, iRetItem, icol, Pdlg(), strText, NULL);
  1014. rlc.SetItemText(iRetItem, icol, strText);
  1015. } // for: each column
  1016. return iRetItem;
  1017. } //*** CListCtrlPair::NInsertItemInListCtrl()
  1018. /////////////////////////////////////////////////////////////////////////////
  1019. //++
  1020. //
  1021. // CListCtrlPair::MoveItems
  1022. //
  1023. // Routine Description:
  1024. // Move an item from one list to the other.
  1025. //
  1026. // Arguments:
  1027. // rlcDst [IN OUT] Destination list control.
  1028. // rlpobjDst [IN OUT] Destination list.
  1029. // rlcSrc [IN OUT] Source list control.
  1030. // rlpobjSrc [IN OUT] Source list.
  1031. //
  1032. // Return Value:
  1033. // None.
  1034. //
  1035. //--
  1036. /////////////////////////////////////////////////////////////////////////////
  1037. void CListCtrlPair::MoveItems(
  1038. IN OUT CListCtrl & rlcDst,
  1039. IN OUT CClusterItemList & rlpobjDst,
  1040. IN OUT CListCtrl & rlcSrc,
  1041. IN OUT CClusterItemList & rlpobjSrc
  1042. )
  1043. {
  1044. int iSrcItem;
  1045. int iDstItem;
  1046. int nItem = -1;
  1047. CClusterItem * pci;
  1048. POSITION pos;
  1049. ASSERT(!BReadOnly());
  1050. iDstItem = rlcDst.GetItemCount();
  1051. while ((iSrcItem = rlcSrc.GetNextItem(-1, LVNI_SELECTED)) != -1)
  1052. {
  1053. // Get the item pointer.
  1054. pci = (CClusterItem *) rlcSrc.GetItemData(iSrcItem);
  1055. ASSERT_VALID(pci);
  1056. // Remove the item from the source list.
  1057. pos = rlpobjSrc.Find(pci);
  1058. ASSERT(pos != NULL);
  1059. rlpobjSrc.RemoveAt(pos);
  1060. // Add the item to the destination list.
  1061. rlpobjDst.AddTail(pci);
  1062. // Remove the item from the source list control and
  1063. // add it to the destination list control.
  1064. VERIFY(rlcSrc.DeleteItem(iSrcItem));
  1065. nItem = NInsertItemInListCtrl(iDstItem++, pci, rlcDst);
  1066. rlcDst.SetItemState(
  1067. nItem,
  1068. LVIS_SELECTED | LVIS_FOCUSED,
  1069. LVIS_SELECTED | LVIS_FOCUSED
  1070. );
  1071. } // while: more items
  1072. ASSERT(nItem != -1);
  1073. rlcDst.EnsureVisible(nItem, FALSE /*bPartialOK*/);
  1074. rlcDst.SetFocus();
  1075. // Indicate that the data has changed.
  1076. Pdlg()->GetParent()->SendMessage(PSM_CHANGED, (WPARAM)Pdlg()->m_hWnd);
  1077. } //*** CListCtrlPair::MoveItems()