|
|
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2002 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 typename 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 < (int) 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 int 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 int 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 int 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 int 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 int 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 < (int) 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 int 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 int 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 int 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
BOOL fReturn = FALSE;
//
// 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; size_t nUpperBound = m_aColumns.size(); CString strColText;
ATLASSERT( nUpperBound > 0 );
for ( icol = 0 ; icol < static_cast< int >( 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.
//
fReturn = static_cast< BOOL >( BaseT::OnInitDialog() );
return fReturn;
} //*** 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( static_cast< int >( 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_
|