windows-nt/Source/XPSP1/NT/base/cluster/admin/common/atllcpair.h
2020-09-26 16:20:57 +08:00

1280 lines
37 KiB
C++

/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2000 Microsoft Corporation
//
// Module Name:
// AtlLCPair.h
//
// Implementation File:
// None.
//
// Description:
// Definition of the CListCtrlPair dialog.
// Derive from CDialogImpl<> or CPropertyPageImpl<>.
//
// Author:
// David Potter (davidp) August 8, 1996
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#ifndef __ATLLCPAIR_H_
#define __ATLLCPAIR_H_
/////////////////////////////////////////////////////////////////////////////
// Forward Class Declarations
/////////////////////////////////////////////////////////////////////////////
template < class T, class ObjT, class BaseT > class CListCtrlPair;
/////////////////////////////////////////////////////////////////////////////
// External Class Declarations
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Include Files
/////////////////////////////////////////////////////////////////////////////
#ifndef __ADMCOMMONRES_H_
#include "AdmCommonRes.h" // for ADMC_IDC_LCP_xxx
#endif
#ifndef __ATLUTIL_H_
#include "AtlUtil.h" // for DDX_xxx
#endif
/////////////////////////////////////////////////////////////////////////////
// Type Definitions
/////////////////////////////////////////////////////////////////////////////
struct CLcpColumn
{
UINT m_idsText;
int m_nWidth;
};
#define LCPS_SHOW_IMAGES 0x1
#define LCPS_ALLOW_EMPTY 0x2
#define LCPS_CAN_BE_ORDERED 0x4
#define LCPS_ORDERED 0x8
#define LCPS_DONT_OUTPUT_RIGHT_LIST 0x10
#define LCPS_READ_ONLY 0x20
#define LCPS_PROPERTIES_BUTTON 0x40
#define LCPS_MAX 0x40
/////////////////////////////////////////////////////////////////////////////
//++
//
// class CListCtrlPair
//
// Description:
// Class to support dual list box.
//
// Inheritance:
// CListCtrlPair< T, ObjT, BaseT >
// <BaseT>
// ...
// CDialogImpl< T >
//
//--
/////////////////////////////////////////////////////////////////////////////
template < class T, class ObjT, class BaseT >
class CListCtrlPair : public BaseT
{
// friend class CListCtrlPairDlg;
// friend class CListCtrlPairPage;
// friend class CListCtrlPairWizPage;
typedef CListCtrlPair< T, ObjT, BaseT > thisClass;
typedef std::list< ObjT * > _objptrlist;
typedef std::list< ObjT * >::iterator _objptrlistit;
protected:
// Column structure and collection.
typedef std::vector< CLcpColumn > CColumnArray;
CColumnArray m_aColumns;
// Sort information.
struct SortInfo
{
int m_nDirection;
int m_nColumn;
};
public:
//
// Construction
//
// Default constructor
CListCtrlPair( void )
{
CommonConstruct();
} //*** CListCtrlPair()
// Constructor with style specified
CListCtrlPair(
IN DWORD dwStyle,
IN LPCTSTR lpszTitle = NULL
)
: BaseT( lpszTitle )
{
CommonConstruct();
m_dwStyle = dwStyle;
} //*** CListCtrlPair( lpszTitle )
// Constructor with style specified
CListCtrlPair(
IN DWORD dwStyle,
IN UINT nIDTitle
)
: BaseT( nIDTitle )
{
CommonConstruct();
m_dwStyle = dwStyle;
} //*** CListCtrlPair( nIDTitle )
// Common object construction
void CommonConstruct( void )
{
m_dwStyle = LCPS_ALLOW_EMPTY;
m_plvcFocusList = NULL;
// Set the sort info.
SiLeft().m_nDirection = -1;
SiLeft().m_nColumn = -1;
SiRight().m_nDirection = -1;
SiRight().m_nColumn = -1;
} //*** CommonConstruct()
public:
//
// Functions that are required to be implemented by derived class.
//
// Return list of objects for right list control
_objptrlist * PlpobjRight( void ) const
{
ATLTRACE( _T("PlpobjRight() - Define in derived class\n") );
ATLASSERT( 0 );
return NULL;
} //*** PlpobjRight()
// Return list of objects for left list control
const _objptrlist * PlpobjLeft( void ) const
{
ATLTRACE( _T("PlpobjLeft() - Define in derived class\n") );
ATLASSERT( 0 );
return NULL;
} //*** PlpobjLeft()
// Get column text and image
void GetColumnInfo(
IN OUT ObjT * pobj,
IN int iItem,
IN int icol,
OUT CString & rstr,
OUT int * piimg
)
{
ATLTRACE( _T("GetColumnInfo() - Define in derived class\n") );
ATLASSERT( 0 );
} //*** GetColumnInfo()
// Display properties for the object
int BDisplayProperties( IN OUT ObjT * pobj )
{
ATLTRACE( _T("BDisplayProperties() - Define in derived class\n") );
ATLASSERT( 0 );
return FALSE;
} //*** BDisplayProperties()
// Display an application-wide message box
virtual int AppMessageBox( LPCWSTR lpszText, UINT fuStyle )
{
ATLTRACE( _T("BDisplayProperties() - Define in derived class\n") );
ATLASSERT( 0 );
return MessageBox( lpszText, _T(""), fuStyle );
} //*** AppMessageBox()
// Display an application-wide message box
int AppMessageBox( UINT nID, UINT fuStyle )
{
CString strMsg;
strMsg.LoadString( nID );
return AppMessageBox( strMsg, fuStyle );
} //*** AppMessageBox()
protected:
//
// List control pair style.
//
DWORD m_dwStyle;
BOOL BIsStyleSet( IN DWORD dwStyle ) const { return (m_dwStyle & dwStyle) == dwStyle; }
void ModifyStyle( IN DWORD dwRemove, IN DWORD dwAdd )
{
ATLASSERT( (dwRemove & dwAdd) == 0 );
if ( dwRemove != 0 )
{
m_dwStyle &= ~dwRemove;
} // if: removing some styles
if ( dwAdd != 0 )
{
m_dwStyle |= dwAdd;
} // if: adding some styles
} //*** ModifyStyle()
DWORD DwStyle( void ) const { return m_dwStyle; }
BOOL BShowImages( void ) const { return BIsStyleSet( LCPS_SHOW_IMAGES ); }
BOOL BAllowEmpty( void ) const { return BIsStyleSet( LCPS_ALLOW_EMPTY ); }
BOOL BCanBeOrdered( void ) const { return BIsStyleSet( LCPS_CAN_BE_ORDERED ); }
BOOL BOrdered( void ) const { return BIsStyleSet( LCPS_ORDERED ); }
BOOL BReadOnly( void ) const { return BIsStyleSet( LCPS_READ_ONLY ); }
BOOL BPropertiesButton( void ) const { return BIsStyleSet( LCPS_PROPERTIES_BUTTON ); }
// Operations
public:
// Add column to list of columns displayed in each list control
void AddColumn( IN UINT idsText, IN int nWidth )
{
CLcpColumn col;
ATLASSERT( idsText != 0 );
ATLASSERT( nWidth > 0 );
ATLASSERT( LpobjRight().empty() );
col.m_idsText = idsText;
col.m_nWidth = nWidth;
m_aColumns.insert( m_aColumns.end(), col );
} //*** AddColumn()
// Insert an item in a list control
int NInsertItemInListCtrl(
IN int iitem,
IN OUT ObjT * pobj,
IN OUT CListViewCtrl & rlc
)
{
int iRetItem;
CString strText;
int iimg = 0;
int icol;
// Insert the first column.
((T *) this)->GetColumnInfo( pobj, iitem, 0, 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
);
ATLASSERT( iRetItem != -1 );
for ( icol = 1 ; icol < m_aColumns.size() ; icol++ )
{
((T *) this)->GetColumnInfo( pobj, iRetItem, icol, strText, NULL );
rlc.SetItemText( iRetItem, icol, strText );
} // for: each column
return iRetItem;
} //*** NInsertItemInListCtrl()
// Update data on or from the dialog
BOOL UpdateData( IN BOOL bSaveAndValidate )
{
BOOL bSuccess = TRUE;
if ( bSaveAndValidate )
{
//
// Verify that the list is not empty.
//
if ( ! BAllowEmpty() && (m_lvcRight.GetItemCount() == 0) )
{
CString strMsg;
CString strLabel;
TCHAR * pszLabel;
DDX_GetText( m_hWnd, ADMC_IDC_LCP_RIGHT_LABEL, strLabel );
//
// Remove ampersands (&) and colons (:).
//
pszLabel = strLabel.GetBuffer( 1 );
CleanupLabel( pszLabel );
strLabel.ReleaseBuffer();
//
// Display an error message.
//
strMsg.FormatMessage( ADMC_IDS_EMPTY_RIGHT_LIST, pszLabel );
AppMessageBox( strMsg, MB_OK | MB_ICONWARNING );
bSuccess = FALSE;
} // if: list is empty and isn't allowed to be
} // if: saving data from the dialog
else
{
} // else: setting data to the dialog
return bSuccess;
} //*** UpdateData()
// Apply changes made on this dialog
BOOL BApplyChanges( void )
{
ATLASSERT( ! BIsStyleSet( LCPS_DONT_OUTPUT_RIGHT_LIST ) );
ATLASSERT( ! BReadOnly() );
T * pT = static_cast< T * >( this );
//
// Copy the Nodes list.
//
*pT->PlpobjRight() = LpobjRight();
//
// Call the base class method.
//
return BaseT::BApplyChanges();
} //*** BApplyChanges()
// Implementation
protected:
_objptrlist m_lpobjRight;
_objptrlist m_lpobjLeft;
CListViewCtrl m_lvcRight;
CListViewCtrl m_lvcLeft;
CListViewCtrl * m_plvcFocusList;
CButton m_pbAdd;
CButton m_pbRemove;
CButton m_pbMoveUp;
CButton m_pbMoveDown;
CButton m_pbProperties;
public:
//
// Message map.
//
BEGIN_MSG_MAP( thisClass )
MESSAGE_HANDLER( WM_CONTEXTMENU, OnContextMenu )
COMMAND_HANDLER( ADMC_IDC_LCP_ADD, BN_CLICKED, OnAdd )
COMMAND_HANDLER( ADMC_IDC_LCP_REMOVE, BN_CLICKED, OnRemove )
COMMAND_HANDLER( ADMC_IDC_LCP_MOVE_UP, BN_CLICKED, OnMoveUp )
COMMAND_HANDLER( ADMC_IDC_LCP_MOVE_DOWN, BN_CLICKED, OnMoveDown )
COMMAND_HANDLER( ADMC_IDC_LCP_PROPERTIES, BN_CLICKED, OnProperties )
COMMAND_HANDLER( IDOK, BN_CLICKED, OnOK )
COMMAND_HANDLER( IDCANCEL, BN_CLICKED, OnCancel )
COMMAND_HANDLER( ADMC_ID_MENU_PROPERTIES, 0, OnProperties )
NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, NM_DBLCLK, OnDblClkList )
NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, NM_DBLCLK, OnDblClkList )
NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, LVN_ITEMCHANGED, OnItemChangedList )
NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, LVN_ITEMCHANGED, OnItemChangedList )
NOTIFY_HANDLER( ADMC_IDC_LCP_LEFT_LIST, LVN_COLUMNCLICK, OnColumnClickList )
NOTIFY_HANDLER( ADMC_IDC_LCP_RIGHT_LIST, LVN_COLUMNCLICK, OnColumnClickList )
CHAIN_MSG_MAP( BaseT )
END_MSG_MAP()
//
// Message handler functions.
//
// Handler for WM_CONTEXTMENU
LRESULT OnContextMenu(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam,
IN OUT BOOL & bHandled
)
{
BOOL bDisplayed = FALSE;
CMenu * pmenu = NULL;
HWND hWnd = (HWND) wParam;
WORD xPos = LOWORD( lParam );
WORD yPos = HIWORD( lParam );
CListViewCtrl * plvc;
CString strMenuName;
CWaitCursor wc;
//
// If focus is not in a list control, don't handle the message.
//
if ( hWnd == m_lvcLeft.m_hWnd )
{
plvc = &m_lvcLeft;
} // if: context menu on left list
else if ( hWnd == m_lvcRight.m_hWnd )
{
plvc = &m_lvcRight;
} // else if: context menu on right list
else
{
bHandled = FALSE;
return 0;
} // else: focus not in a list control
ATLASSERT( plvc != NULL );
//
// If the properties button is not enabled, don't display a menu.
//
if ( ! BPropertiesButton() )
{
bHandled = FALSE;
return 0;
} // if: no properties button
//
// Create the menu to display.
//
pmenu = new CMenu;
ATLASSERT( pmenu != NULL );
if ( pmenu == NULL )
{
bHandled = FALSE;
return 0;
} // if: error allocating memory for the new menu
if ( pmenu->CreatePopupMenu() )
{
UINT nFlags = MF_STRING;
//
// If there are no items in the list, disable the menu item.
//
if ( plvc->GetItemCount() == 0 )
{
nFlags |= MF_GRAYED;
} // if: no items in the list
//
// Add the Properties item to the menu.
//
strMenuName.LoadString( ADMC_ID_MENU_PROPERTIES );
if ( pmenu->AppendMenu( nFlags, ADMC_ID_MENU_PROPERTIES, strMenuName ) )
{
m_plvcFocusList = plvc;
bDisplayed = TRUE;
} // if: successfully added menu item
} // if: menu created successfully
if ( bDisplayed )
{
//
// Display the menu.
//
if ( ! pmenu->TrackPopupMenu(
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
xPos,
yPos,
m_hWnd
) )
{
} // if: unsuccessfully displayed the menu
} // if: there is a menu to display
delete pmenu;
return 0;
} //*** OnContextMenu()
// Handler for BN_CLICKED on ADMC_IDC_LCP_ADD
LRESULT OnAdd(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
ATLASSERT( ! BReadOnly() );
//
// Move selected items from the left list to the right list.
//
MoveItems( m_lvcRight, LpobjRight(), m_lvcLeft, LpobjLeft() );
return 0;
} //*** OnAdd()
// Handler for BN_CLICKED on ADMC_IDC_LCP_REMOVE
LRESULT OnRemove(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
ATLASSERT( ! BReadOnly() );
//
// Move selected items from the right list to the left list.
//
MoveItems( m_lvcLeft, LpobjLeft(), m_lvcRight, LpobjRight() );
return 0;
} //*** OnRemove()
// Handler for BN_CLICKED on ADMC_IDC_LCP_MOVE_UP
LRESULT OnMoveUp(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
int nItem;
ObjT * pobj;
//
// Find the index of the selected item.
//
nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
ATLASSERT( nItem != -1 );
//
// Get the item pointer.
//
pobj = (ObjT *) m_lvcRight.GetItemData( nItem );
ATLASSERT( pobj != NULL );
// Remove the selected item from the list and add it back in.
{
_objptrlistit itRemove;
_objptrlistit itAdd;
// Find the position of the item to be removed and the item before
// which the item is to be inserted.
itRemove = std::find( LpobjRight().begin(), LpobjRight().end(), pobj );
ATLASSERT( itRemove != LpobjRight().end() );
itAdd = itRemove--;
LpobjRight().insert( itAdd, pobj );
LpobjRight().erase( itRemove );
} // Remove the selected item from the list and add it back in
// Remove the selected item from the list control and add it back in.
m_lvcRight.DeleteItem( nItem );
NInsertItemInListCtrl( nItem - 1, pobj, m_lvcRight );
m_lvcRight.SetItemState(
nItem - 1,
LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED
);
m_lvcRight.EnsureVisible( nItem - 1, FALSE /*bPartialOK*/ );
m_lvcRight.SetFocus();
return 0;
} //*** OnMoveUp()
// Handler for BN_CLICKED on ADMC_IDC_LCP_MOVE_DOWN
LRESULT OnMoveDown(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
int nItem;
ObjT * pobj;
//
// Find the index of the selected item.
//
nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
ATLASSERT( nItem != -1 );
//
// Get the item pointer.
//
pobj = (ObjT *) m_lvcRight.GetItemData( nItem );
ATLASSERT( pobj != NULL );
// Remove the selected item from the list and add it back in.
{
_objptrlistit itRemove;
_objptrlistit itAdd;
// Find the position of the item to be removed and the item after
// which the item is to be inserted.
itRemove = std::find( LpobjRight().begin(), LpobjRight().end(), pobj );
ATLASSERT( itRemove != LpobjRight().end() );
itAdd = itRemove++;
LpobjRight().insert( itAdd, pobj );
LpobjRight().erase( itRemove );
} // Remove the selected item from the list and add it back in
// Remove the selected item from the list control and add it back in.
m_lvcRight.DeleteItem( nItem );
NInsertItemInListCtrl( nItem + 1, pobj, m_lvcRight );
m_lvcRight.SetItemState(
nItem + 1,
LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED
);
m_lvcRight.EnsureVisible( nItem + 1, FALSE /*bPartialOK*/ );
m_lvcRight.SetFocus();
return 0;
} //*** OnMoveDown()
// Handler for BN_CLICKED on ADMC_IDC_LCP_PROPERTIES
LRESULT OnProperties(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
int iitem;
ObjT * pobj;
ATLASSERT( m_plvcFocusList != NULL );
// Get the index of the item with the focus.
iitem = m_plvcFocusList->GetNextItem( -1, LVNI_FOCUSED );
ATLASSERT( iitem != -1 );
// Get a pointer to the selected item.
pobj = (ObjT *) m_plvcFocusList->GetItemData( iitem );
ATLASSERT( pobj != NULL );
T * pT = static_cast< T * >( this );
if ( pT->BDisplayProperties( pobj ) )
{
// Update this item.
{
CString strText;
int iimg = 0;
int icol;
pT->GetColumnInfo( pobj, iitem, 0, strText, &iimg );
m_plvcFocusList->SetItem( iitem, 0, LVIF_TEXT /*| LVIF_IMAGE*/, strText, iimg, 0, 0, 0 );
for ( icol = 1 ; icol < m_aColumns.size() ; icol++ )
{
pT->GetColumnInfo( pobj, iitem, icol, strText, NULL );
m_plvcFocusList->SetItemText( iitem, icol, strText );
} // for: each column
} // Update this item
} // if: properties changed
return 0;
} //*** OnProperties()
// Handler for BN_CLICKED on IDOK
LRESULT OnOK(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
//
// Save dialog data and exit the dialog.
//
if ( BSaveChanges() )
{
EndDialog( IDOK );
} // if: dialgo data saved
return 0;
} //*** OnOK()
// Handler for BN_CLICKED on IDCANCEL
LRESULT OnCancel(
IN WORD wNotifyCode,
IN WORD idCtrl,
IN HWND hwndCtrl,
IN OUT BOOL & bHandled
)
{
//
// Exit the dialog.
//
EndDialog( IDCANCEL );
return 0;
} //*** OnCancel()
// Handler for NM_DBLCLK on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
LRESULT OnDblClkList(
IN WORD idCtrl,
IN LPNMHDR pnmh,
IN OUT BOOL & bHandled
)
{
ATLASSERT( ! BReadOnly() );
LRESULT lResult;
if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
{
m_plvcFocusList = &m_lvcLeft;
lResult = OnAdd( BN_CLICKED, idCtrl, pnmh->hwndFrom, bHandled );
} // if: double-clicked in left list
else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
{
m_plvcFocusList = &m_lvcRight;
lResult = OnRemove( BN_CLICKED, idCtrl, pnmh->hwndFrom, bHandled );
} // else if: double-clicked in right list
else
{
ATLASSERT( 0 );
lResult = 0;
} // else: double-clicked in an unknown location
return lResult;
} //*** OnDblClkList()
// Handler for LVN_ITEMCHANGED on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
LRESULT OnItemChangedList(
IN int idCtrl,
IN LPNMHDR pnmh,
IN OUT BOOL & bHandled
)
{
NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pnmh;
BOOL bEnable;
CButton * ppb;
if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
{
m_plvcFocusList = &m_lvcLeft;
ppb = &m_pbAdd;
} // if: item changed in left list
else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
{
m_plvcFocusList = &m_lvcRight;
ppb = &m_pbRemove;
} // else if: item changed in right list
else
{
ATLASSERT( 0 );
bHandled = FALSE;
return 0;
} // else: unknown list
ATLASSERT( ppb != NULL );
// 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_plvcFocusList->GetSelectedCount();
//
// If there is a selection, enable the Add or Remove button.
// Otherwise disable it.
//
bEnable = (cSelected != 0);
ppb->EnableWindow( bEnable );
if ( BPropertiesButton() )
{
m_pbProperties.EnableWindow( (cSelected == 1) ? TRUE : FALSE );
} // if: dialog has Properties button
//
// If the right list is ordered, setup the state of the Up/Down buttons.
//
if ( BOrdered() )
{
SetUpDownState();
} // if: right list is ordered
} // if: selection changed
return 0;
} //*** OnItemChangedList()
// Handler for LVN_COLUMNCLICK on ADMC_IDC_LCP_LEFT_LIST & ADMC_IDC_LCP_RIGHT_LIST
LRESULT OnColumnClickList(
IN int idCtrl,
IN LPNMHDR pnmh,
IN OUT BOOL & bHandled
)
{
NM_LISTVIEW * pNMListView = (NM_LISTVIEW *) pnmh;
if ( idCtrl == ADMC_IDC_LCP_LEFT_LIST )
{
m_plvcFocusList = &m_lvcLeft;
m_psiCur = &SiLeft();
} // if: column clicked in left list
else if ( idCtrl == ADMC_IDC_LCP_RIGHT_LIST )
{
m_plvcFocusList = &m_lvcRight;
m_psiCur = &SiRight();
} // else if: column clicked in right list
else
{
ATLASSERT( 0 );
bHandled = FALSE;
return 0;
} // else: column clicked in unknown list
// Save the current sort column and direction.
if ( pNMListView->iSubItem == m_psiCur->m_nColumn )
{
m_psiCur->m_nDirection ^= -1;
} // if: sorting same column again
else
{
m_psiCur->m_nColumn = pNMListView->iSubItem;
m_psiCur->m_nDirection = 0;
} // else: different column
// Sort the list.
if ( ! m_plvcFocusList->SortItems( CompareItems, (LPARAM) this ) )
{
ATLASSERT( 0 );
} // if: error sorting items
return 0;
} //*** OnColumnClickList
//
// Message handler overrides.
//
// Handler for the WM_INITDIALOG message
BOOL OnInitDialog( void )
{
#if DBG
T * pT = static_cast< T * >( this );
ATLASSERT( pT->PlpobjRight() != NULL );
ATLASSERT( pT->PlpobjLeft() != NULL );
#endif // DBG
//
// Attach the controls to control member variables.
//
AttachControl( m_lvcRight, ADMC_IDC_LCP_RIGHT_LIST );
AttachControl( m_lvcLeft, ADMC_IDC_LCP_LEFT_LIST );
AttachControl( m_pbAdd, ADMC_IDC_LCP_ADD );
AttachControl( m_pbRemove, ADMC_IDC_LCP_REMOVE );
if ( BPropertiesButton() )
{
AttachControl( m_pbProperties, ADMC_IDC_LCP_PROPERTIES );
} // if: dialog has Properties button
if ( BCanBeOrdered() )
{
AttachControl( m_pbMoveUp, ADMC_IDC_LCP_MOVE_UP );
AttachControl( m_pbMoveDown, ADMC_IDC_LCP_MOVE_DOWN );
} // if: left list can be ordered
// if ( BShowImages() )
// {
// CClusterAdminApp * papp = GetClusterAdminApp();
//
// m_lvcLeft.SetImageList( papp->PilSmallImages(), LVSIL_SMALL );
// m_lvcRight.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 );
} // if: dialog has Properties button
//
// Set the right list to sort if not ordered. Set both to show selection always.
//
if ( BOrdered() )
{
m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
} // if: right list is ordered
else
{
m_lvcRight.ModifyStyle( 0, LVS_SHOWSELALWAYS | LVS_SORTASCENDING, 0 );
} // else: right list is not ordered
m_lvcLeft.ModifyStyle( 0, LVS_SHOWSELALWAYS, 0 );
//
// If this is an ordered list, show the Move buttons.
// Otherwise, hide them.
//
if ( BCanBeOrdered() )
{
SetUpDownState();
} // if: list can be ordered
//
// Change left list view control extended styles.
//
m_lvcLeft.SetExtendedListViewStyle(
LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
);
//
// Change right list view control extended styles.
//
m_lvcRight.SetExtendedListViewStyle(
LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP,
LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP
);
// Duplicate lists.
DuplicateLists();
//
// Insert all the columns.
//
{
int icol;
int ncol;
int nUpperBound = m_aColumns.size();
CString strColText;
ATLASSERT( nUpperBound > 0 );
for ( icol = 0 ; icol < nUpperBound ; icol++ )
{
strColText.LoadString( m_aColumns[icol].m_idsText );
ncol = m_lvcLeft.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
ATLASSERT( ncol == icol );
ncol = m_lvcRight.InsertColumn( icol, strColText, LVCFMT_LEFT, m_aColumns[icol].m_nWidth, 0 );
ATLASSERT( ncol == icol );
} // for: each column
} // Insert all the columns
//
// Fill the list controls.
//
FillList( m_lvcRight, LpobjRight() );
FillList( m_lvcLeft, LpobjLeft() );
//
// If read-only, set all controls to be either disabled or read-only.
//
if ( BReadOnly() )
{
m_lvcRight.EnableWindow( FALSE );
m_lvcLeft.EnableWindow( FALSE );
} // if: sheet is read-only
//
// Call the base class method.
//
return BaseT::OnInitDialog();
} //*** OnInitDialog()
// Handler for PSN_SETACTIVE
BOOL OnSetActive( void )
{
UINT nSelCount;
// Set the focus to the left list.
m_lvcLeft.SetFocus();
m_plvcFocusList = &m_lvcLeft;
// Enable/disable the Properties button.
nSelCount = m_lvcLeft.GetSelectedCount();
if ( BPropertiesButton() )
{
m_pbProperties.EnableWindow( nSelCount == 1 );
} // if: dialog has Properties button
// Enable or disable the other buttons.
if ( ! BReadOnly() )
{
m_pbAdd.EnableWindow( nSelCount > 0 );
nSelCount = m_lvcRight.GetSelectedCount();
m_pbRemove.EnableWindow( nSelCount > 0 );
SetUpDownState();
} // if: not read-only page
return TRUE;
} //*** OnSetActive()
public:
_objptrlist & LpobjRight( void ) { return m_lpobjRight; }
_objptrlist & LpobjLeft( void ) { return m_lpobjLeft; }
protected:
void DuplicateLists( void )
{
LpobjRight().erase( LpobjRight().begin(), LpobjRight().end() );
LpobjLeft().erase( LpobjLeft().begin(), LpobjLeft().end() );
T * pT = static_cast< T * >( this );
if ( (pT->PlpobjRight() == NULL) || (pT->PlpobjLeft() == NULL) )
{
return;
} // if: either list is empty
//
// Duplicate the lists.
//
LpobjRight() = *pT->PlpobjRight();
LpobjLeft() = *pT->PlpobjLeft();
//
// Remove all the items that are in the right list from
// the left list.
//
_objptrlistit itRight;
_objptrlistit itLeft;
for ( itRight = LpobjRight().begin()
; itRight != LpobjRight().end()
; itRight++ )
{
//
// Find the item in the left list.
//
itLeft = std::find( LpobjLeft().begin(), LpobjLeft().end(), *itRight );
if ( itLeft != LpobjLeft().end() )
{
LpobjLeft().erase( itLeft );
} // if: object found in left list
} // for: each item in the right list
} //*** DuplicateLists()
// Fill a list control
void FillList( IN OUT CListViewCtrl & rlvc, IN const _objptrlist & rlpobj )
{
_objptrlistit itpobj;
ObjT * pobj;
int iItem;
// Initialize the control.
if ( ! rlvc.DeleteAllItems() )
{
ATLASSERT( 0 );
} // if: error deleting all items
rlvc.SetItemCount( rlpobj.size() );
// Add the items to the list.
itpobj = rlpobj.begin();
for ( iItem = 0 ; itpobj != rlpobj.end() ; iItem++, itpobj++ )
{
pobj = *itpobj;
NInsertItemInListCtrl( iItem, pobj, rlvc );
} // for: each string in the list
// If there are any items, set the focus on the first one.
if ( rlvc.GetItemCount() != 0)
{
rlvc.SetItemState( 0, LVIS_FOCUSED, LVIS_FOCUSED );
} // if: items were added to the list
} //*** FillList()
// Move items from one list to another
void MoveItems(
IN OUT CListViewCtrl & rlvcDst,
IN OUT _objptrlist & rlpobjDst,
IN OUT CListViewCtrl & rlvcSrc,
IN OUT _objptrlist & rlpobjSrc
)
{
int iSrcItem;
int iDstItem;
int nItem = -1;
ObjT * pobj;
_objptrlistit itpobj;
ATLASSERT( ! BReadOnly() );
iDstItem = rlvcDst.GetItemCount();
while ( (iSrcItem = rlvcSrc.GetNextItem( -1, LVNI_SELECTED )) != -1 )
{
// Get the item pointer.
pobj = (ObjT *) rlvcSrc.GetItemData( iSrcItem );
ATLASSERT( pobj );
// Remove the item from the source list.
itpobj = std::find( rlpobjSrc.begin(), rlpobjSrc.end(), pobj );
ATLASSERT( itpobj != rlpobjSrc.end() );
rlpobjSrc.remove( *itpobj );
// Add the item to the destination list.
rlpobjDst.insert( rlpobjDst.end(), pobj );
// Remove the item from the source list control and
// add it to the destination list control.
if ( ! rlvcSrc.DeleteItem( iSrcItem ) )
{
ATLASSERT( 0 );
} // if: error deleting the item
nItem = NInsertItemInListCtrl( iDstItem++, pobj, rlvcDst );
rlvcDst.SetItemState(
nItem,
LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED
);
} // while: more items
ATLASSERT( nItem != -1 );
rlvcDst.EnsureVisible( nItem, FALSE /*bPartialOK*/ );
rlvcDst.SetFocus();
// Indicate that the data has changed.
::SendMessage( GetParent(), PSM_CHANGED, (WPARAM) m_hWnd, NULL );
} //*** MoveItems()
BOOL BSaveChanges( void )
{
ATLASSERT( ! BIsStyleSet( LCPS_DONT_OUTPUT_RIGHT_LIST ) );
ATLASSERT( ! BReadOnly() );
T * pT = static_cast< T * >( this );
//
// Update the data first.
//
if ( ! pT->UpdateData( TRUE /*bSaveAndValidate*/ ) )
{
return FALSE;
} // if: error updating data
//
// Copy the object list.
//
*pT->PlpobjRight() = LpobjRight();
return TRUE;
} //*** BSaveChanges()
// Set the state of the Up/Down buttons based on the selection.
void SetUpDownState( void )
{
BOOL bEnableUp;
BOOL bEnableDown;
if ( BOrdered()
&& ! BReadOnly()
&& (m_lvcRight.GetSelectedCount() == 1) )
{
int nItem;
bEnableUp = TRUE;
bEnableDown = TRUE;
//
// Find the index of the selected item.
//
nItem = m_lvcRight.GetNextItem( -1, LVNI_SELECTED );
ATLASSERT( nItem != -1 );
//
// If the first item is selected, can't move up.
//
if ( nItem == 0 )
{
bEnableUp = FALSE;
} // if: first item is selected
//
// If the last item is selected, can't move down.
//
if ( nItem == m_lvcRight.GetItemCount() - 1 )
{
bEnableDown = FALSE;
} // if: last item is selected
} // if: only one item selected
else
{
bEnableUp = FALSE;
bEnableDown = FALSE;
} // else: zero or more than one item selected
m_pbMoveUp.EnableWindow( bEnableUp );
m_pbMoveDown.EnableWindow( bEnableDown );
} //*** SetUpDownState()
static int CALLBACK CompareItems( LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort )
{
ObjT * pobj1 = reinterpret_cast< ObjT * >( lparam1 );
ObjT * pobj2 = reinterpret_cast< ObjT * >( lparam2 );
T * plcp = reinterpret_cast< T * >( lparamSort );
SortInfo * psiCur = plcp->PsiCur();
int icol = psiCur->m_nColumn;
int nResult;
CString str1;
CString str2;
ATLASSERT( pobj1 != NULL );
ATLASSERT( pobj2 != NULL );
ATLASSERT( plcp != NULL );
ATLASSERT( psiCur->m_nColumn >= 0 );
ATLASSERT( icol >= 0 );
plcp->GetColumnInfo( pobj1, 0, icol, str1, NULL );
plcp->GetColumnInfo( pobj2, 0, icol, str2, NULL );
nResult = str1.Compare( str2 );
// Return the result based on the direction we are sorting.
if ( psiCur->m_nDirection != 0 )
{
nResult = -nResult;
} // if: sorting in reverse direction
return nResult;
} //*** CompareItems()
SortInfo m_siLeft;
SortInfo m_siRight;
SortInfo * m_psiCur;
SortInfo & SiLeft( void ) { return m_siLeft; }
SortInfo & SiRight( void ) { return m_siRight; }
public:
SortInfo * PsiCur( void ) const { return m_psiCur; }
}; //*** class CListCtrlPair
/////////////////////////////////////////////////////////////////////////////
#endif // __ATLLCPAIR_H_