Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1234 lines
35 KiB

/////////////////////////////////////////////////////////////////////////////
//
// 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()