///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1996-2000 Microsoft Corporation // // Module Name: // LCPair.cpp // // Abstract: // Implementation of the CListCtrlPair class. // // Author: // David Potter (davidp) August 8, 1996 // // Revision History: // // Notes: // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "CluAdmin.h" #include "LCPair.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CListCtrlPair ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CListCtrlPair, CCmdTarget) ///////////////////////////////////////////////////////////////////////////// // Message Maps BEGIN_MESSAGE_MAP(CListCtrlPair, CCmdTarget) //{{AFX_MSG_MAP(CListCtrlPair) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_LCP_ADD, OnAdd) ON_BN_CLICKED(IDC_LCP_REMOVE, OnRemove) ON_BN_CLICKED(IDC_LCP_PROPERTIES, OnProperties) ON_NOTIFY(NM_DBLCLK, IDC_LCP_LEFT_LIST, OnDblClkLeftList) ON_NOTIFY(NM_DBLCLK, IDC_LCP_RIGHT_LIST, OnDblClkRightList) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LCP_LEFT_LIST, OnItemChangedLeftList) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LCP_RIGHT_LIST, OnItemChangedRightList) ON_NOTIFY(LVN_COLUMNCLICK, IDC_LCP_LEFT_LIST, OnColumnClickLeftList) ON_NOTIFY(LVN_COLUMNCLICK, IDC_LCP_RIGHT_LIST, OnColumnClickRightList) ON_COMMAND(ID_FILE_PROPERTIES, OnProperties) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::CListCtrlPair // // Routine Description: // Default constructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CListCtrlPair::CListCtrlPair(void) { CommonConstruct(); } //*** CListCtrlPair::CListCtrlPair() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::CListCtrlPair // // Routine Description: // Cconstructor. // // Arguments: // pdlg [IN OUT] Dialog to which controls belong. // plpobjRight [IN OUT] List for the right list control. // plpobjLeft [IN] List for the left list control. // dwStyle [IN] Style: // LCPS_SHOW_IMAGES Show images to left of items. // LCPS_ALLOW_EMPTY Allow right list to be empty. // pfnGetColumn [IN] Function pointer for retrieving columns. // pfnDisplayProps [IN] Function pointer for displaying properties. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CListCtrlPair::CListCtrlPair( IN OUT CDialog * pdlg, IN OUT CClusterItemList * plpobjRight, IN const CClusterItemList * plpobjLeft, IN DWORD dwStyle, IN PFNLCPGETCOLUMN pfnGetColumn, IN PFNLCPDISPPROPS pfnDisplayProps ) { ASSERT(pfnGetColumn != NULL); ASSERT(pfnDisplayProps != NULL); CommonConstruct(); m_pdlg = pdlg; if (plpobjRight != NULL) m_plpobjRight = plpobjRight; if (plpobjLeft != NULL) m_plpobjLeft = plpobjLeft; m_dwStyle = dwStyle; m_pfnGetColumn = pfnGetColumn; m_pfnDisplayProps = pfnDisplayProps; } //*** CListCtrlPair::CListCtrlPair() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::CommonConstruct // // Routine Description: // Common construction. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::CommonConstruct(void) { m_pdlg = NULL; m_plpobjLeft = NULL; m_plpobjRight = NULL; m_dwStyle = LCPS_ALLOW_EMPTY; m_pfnGetColumn = NULL; m_plcFocusList = NULL; // Set the sort info. SiLeft().m_nDirection = -1; SiLeft().m_nColumn = -1; SiRight().m_nDirection = -1; SiRight().m_nColumn = -1; } //*** CListCtrlPair::CommonConstruct() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::NAddColumn // // Routine Description: // Add a column to the list of columns displayed in each list control. // // Arguments: // idsText [IN] String resource ID for text to display on column. // nWidth [IN] Initial width of the column. // // Return Value: // icol Index of the column. // // Exceptions Thrown: // Any exceptions thrown by CArray::Add. //-- ///////////////////////////////////////////////////////////////////////////// int CListCtrlPair::NAddColumn(IN IDS idsText, IN int nWidth) { CColumn col; ASSERT(idsText != 0); ASSERT(nWidth > 0); ASSERT(LpobjRight().GetCount() == 0); col.m_idsText = idsText; col.m_nWidth = nWidth; return (int)m_aColumns.Add(col); } //*** CListCtrlPair::NAddColumn() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::DoDataExchange // // Routine Description: // Do data exchange between the dialog and the class. // // Arguments: // pDX [IN OUT] Data exchange object // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::DoDataExchange(CDataExchange * pDX) { DDX_Control(pDX, IDC_LCP_RIGHT_LIST, m_lcRight); DDX_Control(pDX, IDC_LCP_LEFT_LIST, m_lcLeft); DDX_Control(pDX, IDC_LCP_ADD, m_pbAdd); DDX_Control(pDX, IDC_LCP_REMOVE, m_pbRemove); if (BPropertiesButton()) DDX_Control(pDX, IDC_LCP_PROPERTIES, m_pbProperties); if (pDX->m_bSaveAndValidate) { // Verify that the list is not empty. if (!BAllowEmpty() && (m_lcRight.GetItemCount() == 0)) { CString strMsg; CString strLabel; TCHAR * pszLabel; TCHAR szStrippedLabel[1024]; int iSrc; int iDst; TCHAR ch; DDX_Text(pDX, IDC_LCP_RIGHT_LABEL, strLabel); // Remove ampersands (&) and colons (:). pszLabel = strLabel.GetBuffer(1); for (iSrc = 0, iDst = 0 ; pszLabel[iSrc] != _T('\0') ; iSrc++) { ch = pszLabel[iSrc]; if ((ch != _T('&')) && (ch != _T(':'))) szStrippedLabel[iDst++] = ch; } // for: each character in the label szStrippedLabel[iDst] = _T('\0'); strMsg.FormatMessage(IDS_EMPTY_RIGHT_LIST, szStrippedLabel); ::AfxMessageBox(strMsg, MB_OK | MB_ICONWARNING); strMsg.Empty(); pDX->Fail(); } // if: list is empty and isn't allowed to be } // if: saving data from the dialog else { // Fill the lists. if (m_plpobjRight != NULL) FillList(m_lcRight, LpobjRight()); if (m_plpobjLeft != NULL) FillList(m_lcLeft, LpobjLeft()); } // else: setting data to the dialog } //*** CListCtrlPair::DoDataExchange() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnInitDialog // // Routine Description: // Handler for the WM_INITDIALOG message. // // Arguments: // None. // // Return Value: // TRUE Focus needs to be set. // FALSE Focus already set. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CListCtrlPair::OnInitDialog(void) { ASSERT_VALID(Pdlg()); ASSERT(PlpobjRight() != NULL); ASSERT(PlpobjLeft() != NULL); Pdlg()->UpdateData(FALSE /*bSaveAndValidate*/); if (BShowImages()) { CClusterAdminApp * papp = GetClusterAdminApp(); m_lcLeft.SetImageList(papp->PilSmallImages(), LVSIL_SMALL); m_lcRight.SetImageList(papp->PilSmallImages(), LVSIL_SMALL); } // if: showing images // Disable buttons by default. m_pbAdd.EnableWindow(FALSE); m_pbRemove.EnableWindow(FALSE); if (BPropertiesButton()) m_pbProperties.EnableWindow(FALSE); // Set the right list to sort. Set both to show selection always. m_lcRight.ModifyStyle(0, LVS_SHOWSELALWAYS | LVS_SORTASCENDING, 0); m_lcLeft.ModifyStyle(0, LVS_SHOWSELALWAYS, 0); // Change list view control extended styles. { DWORD dwExtendedStyle; // Left control. dwExtendedStyle = (DWORD)m_lcLeft.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE); m_lcLeft.SendMessage( LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwExtendedStyle | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP ); // Right control. dwExtendedStyle = (DWORD)m_lcRight.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE); m_lcRight.SendMessage( LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwExtendedStyle | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP ); } // Change list view control extended styles try { // Duplicate lists. DuplicateLists(); // Insert all the columns. { int icol; int ncol; int nUpperBound = (int)m_aColumns.GetUpperBound(); CString strColText; ASSERT(nUpperBound >= 0); for (icol = 0 ; icol <= nUpperBound ; icol++) { strColText.LoadString(m_aColumns[icol].m_idsText); ncol = m_lcLeft.InsertColumn(icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0); ASSERT(ncol == icol); ncol = m_lcRight.InsertColumn(icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0); ASSERT(ncol == icol); } // for: each column } // Insert all the columns } // try catch (CException * pe) { pe->Delete(); } // catch: CException Pdlg()->UpdateData(FALSE /*bSaveAndValidate*/); // If read-only, set all controls to be either disabled or read-only. if (BReadOnly()) { m_lcRight.EnableWindow(FALSE); m_lcLeft.EnableWindow(FALSE); } // if: sheet is read-only return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } //*** CListCtrlPair::OnInitDialog() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnSetActive // // Routine Description: // Handler for the PSN_SETACTIVE message. // // Arguments: // None. // // Return Value: // TRUE Page successfully initialized. // FALSE Page not initialized. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CListCtrlPair::OnSetActive(void) { UINT nSelCount; // Set the focus to the left list. m_lcLeft.SetFocus(); m_plcFocusList = &m_lcLeft; // Enable/disable the Properties button. nSelCount = m_lcLeft.GetSelectedCount(); if (BPropertiesButton()) m_pbProperties.EnableWindow(nSelCount == 1); // Enable or disable the other buttons. if (!BReadOnly()) { m_pbAdd.EnableWindow(nSelCount > 0); nSelCount = m_lcRight.GetSelectedCount(); m_pbRemove.EnableWindow(nSelCount > 0); } // if: not read-only page return TRUE; } //*** CListCtrlPair::OnSetActive() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::BSaveChanges // // Routine Description: // Handler for the BN_CLICKED message on the OK button. // // Arguments: // None. // // Return Value: // TRUE Changes saved successfully. // FALSE Error saving changes. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CListCtrlPair::BSaveChanges(void) { POSITION pos; CClusterItem * pci; ASSERT(!BIsStyleSet(LCPS_DONT_OUTPUT_RIGHT_LIST)); ASSERT(!BReadOnly()); // Update the data first. if (!Pdlg()->UpdateData(TRUE /*bSaveAndValidate*/)) return FALSE; // Copy the Nodes list. PlpobjRight()->RemoveAll(); pos = LpobjRight().GetHeadPosition(); while (pos != NULL) { pci = LpobjRight().GetNext(pos); ASSERT_VALID(pci); VERIFY(PlpobjRight()->AddTail(pci) != NULL); } // while: more items in the list return TRUE; } //*** CListCtrlPair::BSaveChanges() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnAdd // // Routine Description: // Handler for the BN_CLICKED message on the Add button. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnAdd(void) { ASSERT(!BReadOnly()); // Move selected items from the left list to the right list. MoveItems(m_lcRight, LpobjRight(), m_lcLeft, LpobjLeft()); } //*** CListCtrlPair::OnAdd() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnRemove // // Routine Description: // Handler for the BN_CLICKED message on the Remove button. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnRemove(void) { ASSERT(!BReadOnly()); // Move selected items from the right list to the left list. MoveItems(m_lcLeft, LpobjLeft(), m_lcRight, LpobjRight()); } //*** CListCtrlPair::OnRemove() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnProperties // // Routine Description: // Handler for the BN_CLICKED message on the Properties button. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnProperties(void) { int iitem; CObject * pobj; ASSERT(m_plcFocusList != NULL); ASSERT(m_pfnDisplayProps != NULL); // Get the index of the item with the focus. iitem = m_plcFocusList->GetNextItem(-1, LVNI_FOCUSED); ASSERT(iitem != -1); // Get a pointer to the selected item. pobj = (CObject *) m_plcFocusList->GetItemData(iitem); ASSERT_VALID(pobj); if ((*m_pfnDisplayProps)(pobj)) { // Update this item. { CString strText; int iimg; int icol; ASSERT(m_pfnGetColumn != NULL); ASSERT(Pdlg() != NULL); (*m_pfnGetColumn)(pobj, iitem, 0, Pdlg(), strText, &iimg); m_plcFocusList->SetItem(iitem, 0, LVIF_TEXT | LVIF_IMAGE, strText, iimg, 0, 0, 0); for (icol = 1 ; icol <= m_aColumns.GetUpperBound() ; icol++) { (*m_pfnGetColumn)(pobj, iitem, icol, Pdlg(), strText, NULL); m_plcFocusList->SetItemText(iitem, icol, strText); } // for: each column } // Update this item } // if: properties changed } //*** CListCtrlPair::OnProperties() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnContextMenu // // Routine Description: // Handler for the WM_CONTEXTMENU method. // // Arguments: // pWnd Window in which the user right clicked the mouse. // point Position of the cursor, in screen coordinates. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CListCtrlPair::OnContextMenu(CWnd * pWnd, CPoint point) { BOOL bHandled = FALSE; CMenu * pmenu = NULL; CListCtrl * pListCtrl = (CListCtrl *) pWnd; CString strMenuName; CWaitCursor wc; // If focus is not in the list control, don't handle the message. if ( ( pWnd != &m_lcRight ) && ( pWnd != &m_lcLeft ) ) { return FALSE; } // if: focus not in list control // Create the menu to display. try { pmenu = new CMenu; if ( pmenu == NULL ) { AfxThrowMemoryException(); } // if: error allocating the memory if ( pmenu->CreatePopupMenu() ) { UINT nFlags = MF_STRING; // If there are no items in the list, disable the menu item. if ( pListCtrl->GetItemCount() == 0 ) { nFlags |= MF_GRAYED; } // if: no items in the list // Add the Properties item to the menu. strMenuName.LoadString( IDS_MENU_PROPERTIES ); if ( pmenu->AppendMenu( nFlags, ID_FILE_PROPERTIES, strMenuName ) ) { m_plcFocusList = pListCtrl; bHandled = TRUE; } // if: successfully added menu item } // if: menu created successfully } // try catch ( CException * pe ) { pe->ReportError(); pe->Delete(); } // catch: CException if ( bHandled ) { // Display the menu. if ( ! pmenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, Pdlg() ) ) { } // if: unsuccessfully displayed the menu } // if: there is a menu to display delete pmenu; return bHandled; } //*** CListCtrlPair::OnContextMenu() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnDblClkLeftList // // Routine Description: // Handler method for the NM_DBLCLK message for the left list. // // Arguments: // pNMHDR Notification message structure. // pResult Place in which to return the result. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnDblClkLeftList(NMHDR * pNMHDR, LRESULT * pResult) { ASSERT(!BReadOnly()); m_plcFocusList = &m_lcLeft; OnAdd(); *pResult = 0; } //*** CListCtrlPair::OnDblClkLeftList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnDblClkRightList // // Routine Description: // Handler method for the NM_DBLCLK message for the right list. // // Arguments: // pNMHDR Notification message structure. // pResult Place in which to return the result. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnDblClkRightList(NMHDR * pNMHDR, LRESULT * pResult) { ASSERT(!BReadOnly()); m_plcFocusList = &m_lcRight; OnRemove(); *pResult = 0; } //*** CListCtrlPair::OnDblClkRightList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnItemChangedLeftList // // Routine Description: // Handler method for the LVN_ITEMCHANGED message in the left list. // // Arguments: // pNMHDR [IN OUT] WM_NOTIFY structure. // pResult [OUT] LRESULT in which to return the result of this operation. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnItemChangedLeftList(NMHDR * pNMHDR, LRESULT * pResult) { NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR; m_plcFocusList = &m_lcLeft; // If the selection changed, enable/disable the Add button. if ((pNMListView->uChanged & LVIF_STATE) && ((pNMListView->uOldState & LVIS_SELECTED) || (pNMListView->uNewState & LVIS_SELECTED)) && !BReadOnly()) { UINT cSelected = m_plcFocusList->GetSelectedCount(); // If there is a selection, enable the Add button. Otherwise disable it. m_pbAdd.EnableWindow((cSelected == 0) ? FALSE : TRUE); if (BPropertiesButton()) m_pbProperties.EnableWindow((cSelected == 1) ? TRUE : FALSE); } // if: selection changed *pResult = 0; } //*** CListCtrlPair::OnItemChangedLeftList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnItemChangedRightList // // Routine Description: // Handler method for the LVN_ITEMCHANGED message in the right list. // // Arguments: // pNMHDR [IN OUT] WM_NOTIFY structure. // pResult [OUT] LRESULT in which to return the result of this operation. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnItemChangedRightList(NMHDR * pNMHDR, LRESULT * pResult) { NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR; m_plcFocusList = &m_lcRight; // If the selection changed, enable/disable the Remove button. if ((pNMListView->uChanged & LVIF_STATE) && ((pNMListView->uOldState & LVIS_SELECTED) || (pNMListView->uNewState & LVIS_SELECTED)) && !BReadOnly()) { UINT cSelected = m_plcFocusList->GetSelectedCount(); // If there is a selection, enable the Remove button. Otherwise disable it. m_pbRemove.EnableWindow((cSelected == 0) ? FALSE : TRUE); if (BPropertiesButton()) m_pbProperties.EnableWindow((cSelected == 1) ? TRUE : FALSE); } // if: selection changed *pResult = 0; } //*** CListCtrlPair::OnItemChangedRightList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnColumnClickLeftList // // Routine Description: // Handler method for the LVN_COLUMNCLICK message on the left list. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnColumnClickLeftList(NMHDR * pNMHDR, LRESULT * pResult) { NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR; ASSERT(m_pfnGetColumn != NULL); m_plcFocusList = &m_lcLeft; // Save the current sort column and direction. if (pNMListView->iSubItem == SiLeft().m_nColumn) SiLeft().m_nDirection ^= -1; else { SiLeft().m_nColumn = pNMListView->iSubItem; SiLeft().m_nDirection = 0; } // else: different column // Sort the list. m_psiCur = &SiLeft(); VERIFY(m_lcLeft.SortItems(CompareItems, (LPARAM) this)); *pResult = 0; } //*** CListCtrlPair::OnColumnClickLeftList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::OnColumnClickRightList // // Routine Description: // Handler method for the LVN_COLUMNCLICK message on the right list. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::OnColumnClickRightList(NMHDR * pNMHDR, LRESULT * pResult) { NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pNMHDR; ASSERT(m_pfnGetColumn != NULL); m_plcFocusList = &m_lcRight; // Save the current sort column and direction. if (pNMListView->iSubItem == SiRight().m_nColumn) SiRight().m_nDirection ^= -1; else { SiRight().m_nColumn = pNMListView->iSubItem; SiRight().m_nDirection = 0; } // else: different column // Sort the list. m_psiCur = &SiRight(); VERIFY(m_lcRight.SortItems(CompareItems, (LPARAM) this)); *pResult = 0; } //*** CListCtrlPair::OnColumnClickRightList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::CompareItems [static] // // Routine Description: // Callback function for the CListCtrl::SortItems method. // // Arguments: // lparam1 First item to compare. // lparam2 Second item to compare. // lparamSort Sort parameter. // // Return Value: // -1 First parameter comes before second. // 0 First and second parameters are the same. // 1 First parameter comes after second. // //-- ///////////////////////////////////////////////////////////////////////////// int CALLBACK CListCtrlPair::CompareItems( LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort ) { CObject * pobj1 = (CObject *) lparam1; CObject * pobj2 = (CObject *) lparam2; CListCtrlPair * plcp = (CListCtrlPair *) lparamSort; int icol = plcp->PsiCur()->m_nColumn; int nResult; CString str1; CString str2; ASSERT_VALID(pobj1); ASSERT_VALID(pobj2); ASSERT(plcp != NULL); ASSERT(plcp->PsiCur()->m_nColumn >= 0); ASSERT(icol >= 0); (*plcp->m_pfnGetColumn)(pobj1, 0, icol, plcp->Pdlg(), str1, NULL); (*plcp->m_pfnGetColumn)(pobj2, 0, icol, plcp->Pdlg(), str2, NULL); // Compare the two strings. // Use CompareString() so that it will sort properly on localized builds. nResult = CompareString( LOCALE_USER_DEFAULT, 0, str1, str1.GetLength(), str2, str2.GetLength() ); if ( nResult == CSTR_LESS_THAN ) { nResult = -1; } else if ( nResult == CSTR_EQUAL ) { nResult = 0; } else if ( nResult == CSTR_GREATER_THAN ) { nResult = 1; } else { // An error occurred. Ignore it. nResult = 0; } // Return the result based on the direction we are sorting. if (plcp->PsiCur()->m_nDirection != 0) nResult = -nResult; return nResult; } //*** CListCtrlPair::CompareItems() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::SetLists // // Routine Description: // Set the lists for the list control pair. // // Arguments: // plpobjRight [IN OUT] List for the right list box. // plpobjLeft [IN] List for the left list box. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::SetLists( IN OUT CClusterItemList * plpobjRight, IN const CClusterItemList * plpobjLeft ) { if (plpobjRight != NULL) m_plpobjRight = plpobjRight; if (plpobjLeft != NULL) m_plpobjLeft = plpobjLeft; DuplicateLists(); } //*** CListCtrlPair::SetLists() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::SetLists // // Routine Description: // Set the lists for the list control pair where the right list should // not be modified. // // Arguments: // plpobjRight [IN] List for the right list box. // plpobjLeft [IN] List for the left list box. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::SetLists( IN const CClusterItemList * plpobjRight, IN const CClusterItemList * plpobjLeft ) { m_dwStyle |= LCPS_DONT_OUTPUT_RIGHT_LIST; SetLists((CClusterItemList *) plpobjRight, plpobjLeft); } //*** CListCtrlPair::SetLists() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::DuplicateLists // // Routine Description: // Duplicate the lists so that we have local copies. // // Arguments: // rlc [IN OUT] List control to fill. // rlpobj [IN] List to use to fill the control. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::DuplicateLists(void) { LpobjRight().RemoveAll(); LpobjLeft().RemoveAll(); if ((PlpobjRight() == NULL) || (PlpobjLeft() == NULL)) return; // Duplicate the right list. { POSITION pos; CClusterItem * pci; pos = PlpobjRight()->GetHeadPosition(); while (pos != NULL) { // Get the item pointer. pci = PlpobjRight()->GetNext(pos); ASSERT_VALID(pci); // Add it to our list. LpobjRight().AddTail(pci); } // while: more items in the list } // Duplicate the right list // Duplicate the left list. { POSITION pos; CClusterItem * pci; pos = PlpobjLeft()->GetHeadPosition(); while (pos != NULL) { // Get the item pointer. pci = PlpobjLeft()->GetNext(pos); ASSERT_VALID(pci); // If the item is not already in the other list, // add it to the left list. if (LpobjRight().Find(pci) == NULL) LpobjLeft().AddTail(pci); } // while: more items in the list } // Duplicate the left list } //*** CListCtrlPair::DuplicateLists() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::FillList // // Routine Description: // Fill a list control. // // Arguments: // rlc [IN OUT] List control to fill. // rlpobj [IN] List to use to fill the control. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::FillList( IN OUT CListCtrl & rlc, IN const CClusterItemList & rlpobj ) { POSITION pos; CObject * pobj; int iItem; // Initialize the control. VERIFY(rlc.DeleteAllItems()); rlc.SetItemCount((int)rlpobj.GetCount()); // Add the items to the list. pos = rlpobj.GetHeadPosition(); for (iItem = 0 ; pos != NULL ; iItem++) { pobj = rlpobj.GetNext(pos); ASSERT_VALID(pobj); NInsertItemInListCtrl(iItem, pobj, rlc); } // for: each string in the list // If there are any items, set the focus on the first one. if (rlc.GetItemCount() != 0) rlc.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); } //*** CListCtrlPair::FillList() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::NInsertItemInListCtrl // // Routine Description: // Insert an item in a list control. // // Arguments: // iitem [IN] Index of the item in the list. // pobj [IN OUT] Item to add. // rlc [IN OUT] List control in which to insert the item. // // Return Value: // iRetItem Index of the new item in the list control. // //-- ///////////////////////////////////////////////////////////////////////////// int CListCtrlPair::NInsertItemInListCtrl( IN int iitem, IN OUT CObject * pobj, IN OUT CListCtrl & rlc ) { int iRetItem; CString strText; int iimg; int icol; ASSERT(m_pfnGetColumn != NULL); ASSERT(Pdlg() != NULL); // Insert the first column. (*m_pfnGetColumn)(pobj, iitem, 0, Pdlg(), strText, &iimg); iRetItem = rlc.InsertItem( LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, // nMask iitem, // nItem strText, // lpszItem 0, // nState 0, // nStateMask iimg, // nImage (LPARAM) pobj // lParam ); ASSERT(iRetItem != -1); for (icol = 1 ; icol <= m_aColumns.GetUpperBound() ; icol++) { (*m_pfnGetColumn)(pobj, iRetItem, icol, Pdlg(), strText, NULL); rlc.SetItemText(iRetItem, icol, strText); } // for: each column return iRetItem; } //*** CListCtrlPair::NInsertItemInListCtrl() ///////////////////////////////////////////////////////////////////////////// //++ // // CListCtrlPair::MoveItems // // Routine Description: // Move an item from one list to the other. // // Arguments: // rlcDst [IN OUT] Destination list control. // rlpobjDst [IN OUT] Destination list. // rlcSrc [IN OUT] Source list control. // rlpobjSrc [IN OUT] Source list. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CListCtrlPair::MoveItems( IN OUT CListCtrl & rlcDst, IN OUT CClusterItemList & rlpobjDst, IN OUT CListCtrl & rlcSrc, IN OUT CClusterItemList & rlpobjSrc ) { int iSrcItem; int iDstItem; int nItem = -1; CClusterItem * pci; POSITION pos; ASSERT(!BReadOnly()); iDstItem = rlcDst.GetItemCount(); while ((iSrcItem = rlcSrc.GetNextItem(-1, LVNI_SELECTED)) != -1) { // Get the item pointer. pci = (CClusterItem *) rlcSrc.GetItemData(iSrcItem); ASSERT_VALID(pci); // Remove the item from the source list. pos = rlpobjSrc.Find(pci); ASSERT(pos != NULL); rlpobjSrc.RemoveAt(pos); // Add the item to the destination list. rlpobjDst.AddTail(pci); // Remove the item from the source list control and // add it to the destination list control. VERIFY(rlcSrc.DeleteItem(iSrcItem)); nItem = NInsertItemInListCtrl(iDstItem++, pci, rlcDst); rlcDst.SetItemState( nItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); } // while: more items ASSERT(nItem != -1); rlcDst.EnsureVisible(nItem, FALSE /*bPartialOK*/); rlcDst.SetFocus(); // Indicate that the data has changed. Pdlg()->GetParent()->SendMessage(PSM_CHANGED, (WPARAM)Pdlg()->m_hWnd); } //*** CListCtrlPair::MoveItems()