www.pudn.com > sqlcommand.zip > AutoListCtrl.cpp


//@doc 
//@module AutoListCtrl.cpp | Implementation of CAutoListCtrl class 
 
//------------------------------------------------------------------- 
// CAutoListCtrl implementation file 
//------------------------------------------------------------------- 
//  
// Copyright ©2000 Virtual Office Systems Incorporated 
// All Rights Reserved                       
// 
// This code may be used in compiled form in any way you desire. This 
// file may be redistributed unmodified by any means PROVIDING it is  
// not sold for profit without the authors written consent, and  
// providing that this notice and the authors name is included. 
// 
// This code can be compiled, modified and distributed freely, providing 
// that this copyright information remains intact in the distribution. 
// 
// This code may be compiled in original or modified form in any private  
// or commercial application. 
// 
// This file is provided "as is" with no expressed or implied warranty. 
// The author accepts no liability for any damage, in any form, caused 
// by this code. Use it at your own risk. 
//------------------------------------------------------------------- 
 
#include "commctrl.h" 
#include "stdafx.h" 
#include "AutoListCtrl.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
class CAutoListItemData 
{ 
public: 
	CAutoListItemData(DWORD dwUser = 0); 
	~CAutoListItemData(); 
 
	CMapWordToPtr&	GetTextMap()	{ return m_Map; } 
	DWORD			GetData()		{ return m_dwUser; } 
	BOOL			SetData(DWORD dwUser)	{ m_dwUser = dwUser; return TRUE; } 
 
private: 
	CMapWordToPtr	m_Map; 
	DWORD			m_dwUser; 
}; 
 
CAutoListItemData::CAutoListItemData(DWORD dwUser) 
{ 
	m_dwUser = dwUser; 
} 
 
CAutoListItemData::~CAutoListItemData() 
{ 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CAutoListCtrl 
 
//@mfunc Constructor for CAutoListCtrl class 
CAutoListCtrl::CAutoListCtrl() 
{ 
	m_uColumnCount = 0; 
	m_dwImageWidth = 0; 
	m_fLocked = FALSE; 
	m_nSortColumn = -1; 
} 
 
//@mfunc Destructor for CAutoListCtrl class 
CAutoListCtrl::~CAutoListCtrl() 
{ 
} 
 
BEGIN_MESSAGE_MAP(CAutoListCtrl, CListCtrl) 
	//{{AFX_MSG_MAP(CAutoListCtrl) 
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick) 
	ON_WM_DESTROY() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CAutoListCtrl message handlers 
 
//@mfunc Insert a column into the list control 
//@rdesc Returns the index of the new column, or -1 if there is an error. 
int CAutoListCtrl::InsertColumn(  
		int nCol,					//@parm Index of the column to insert before. 
									// @flag -1 | Add column at end of list 
		LPCTSTR pszColumnHeading,	//@parm Title of the column 
		int nFormat,				//@parm Format of the column.   See CListCtrl 
									//		for details. 
		int nWidth,					//@parm Width of the column in pixels. 
									// @flag -1 (default) | Autosize the column to  
									//						the header text 
		int nSubItem)				//@parm Index of the subitem associated with  
									//		the column.   Default is -1. 
									// @flag -1 (default) | No subitem is associatied  
									//						with the column. 
 
{ 
	ASSERT(AfxIsValidString(pszColumnHeading)); 
 
	if(nCol == -1) 
	{ 
		nCol = m_uColumnCount; 
	} 
 
	int iNew = CListCtrl::InsertColumn(nCol, pszColumnHeading, nFormat, nWidth, nSubItem); 
 
	if(iNew != -1) 
	{ 
		if(nWidth == -1) 
		{ 
			CListCtrl::SetColumnWidth(iNew, LVSCW_AUTOSIZE_USEHEADER); 
			nWidth = CListCtrl::GetColumnWidth(iNew); 
		} 
 
		if((int)m_uColumnCount <= nCol) 
		{ 
			m_uColumnCount = nCol + 1; 
			m_HeaderWidth.SetAtGrow(nCol, nWidth); 
			m_ColumnType.SetAtGrow(nCol, CAutoListCtrl::TextCol); 
		} 
		else 
			SetMinColumnWidth(nCol, nWidth); 
	} 
 
	return iNew; 
} 
 
//@mfunc Insert a column into the list control 
//@rdesc Returns the index of the new column, or -1 if there is an error. 
int CAutoListCtrl::InsertColumn(  
		int nCol,					//@parm Index of the column to insert before. 
									// @flag -1 | Add column at end of list 
		const LV_COLUMN* pColumn )	//@parm Pointer to  structure 
									//		containing parameters for new column. 
{ 
	ASSERT(AfxIsValidAddress(pColumn, sizeof(LV_COLUMN), FALSE)); 
 
	if(nCol == -1) 
		nCol = m_uColumnCount; 
 
	int iNew = CListCtrl::InsertColumn(nCol, pColumn); 
 
	if(iNew != -1) 
	{ 
		if( pColumn->cx == -1) 
		{ 
			CListCtrl::SetColumnWidth(iNew, LVSCW_AUTOSIZE_USEHEADER); 
			((LV_COLUMN*)pColumn)->cx = CListCtrl::GetColumnWidth(iNew); 
		} 
 
		if((int)m_uColumnCount <= nCol) 
		{ 
			m_uColumnCount = nCol + 1; 
			m_HeaderWidth.SetAtGrow(nCol, pColumn->cx); 
			m_ColumnType.SetAtGrow(nCol, CAutoListCtrl::TextCol); 
		} 
		else 
			SetMinColumnWidth(nCol, pColumn->cx); 
	} 
 
	return iNew; 
} 
 
//@mfunc Remove a column from the list 
//@rdesc TRUE | Column Removed 
//@rdesc FALSE | Unable to remove column or column does not exist. 
BOOL CAutoListCtrl::DeleteColumn(  
		int nCol )					//@parm Zero based index of column to remove. 
{ 
	BOOL fSuccess = CListCtrl::DeleteColumn(nCol); 
 
	if(fSuccess) 
	{ 
		if(m_uColumnCount) 
			m_uColumnCount--; 
	} 
 
	return fSuccess; 
} 
 
//@mfunc Insert a new item into the list 
//@rdesc Returns the index of the new item. 
//@rvalue -1 | Unable to insert item 
int CAutoListCtrl::InsertItem(  
		const LV_ITEM* pItem )	//@parm Pointer to  structure containing 
								//		parameters for the new item. 
{ 
	ASSERT(AfxIsValidAddress(pItem, sizeof(LV_ITEM), FALSE)); 
 
	if(GetSortColumn() == -1) 
	{ 
		if(pItem->iItem == -1) 
			(int)pItem->iItem = GetItemCount(); 
	} 
 
	int iNew = CListCtrl::InsertItem(pItem); 
 
	if(iNew != -1) 
	{ 
		CListCtrl::SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);	// LVSCW_AUTOSIZE 
 
		int iNewWidth = CListCtrl::GetColumnWidth(0); 
 
		SetMinColumnWidth(0, iNewWidth); 
		 
		CAutoListItemData* pData = new CAutoListItemData; 
 
		CString*	pstrCur; 
		if(pData->GetTextMap().Lookup(0, (PVOID&)pstrCur)) 
		{ 
			pData->GetTextMap().RemoveKey(0); 
			delete pstrCur; 
		} 
 
		pData->GetTextMap().SetAt(0, new CString( GetItemText(iNew, 0) )); 
		for(int iCol = 1; iCol < GetColumnCount(); iCol++) 
			pData->GetTextMap().SetAt(iCol, new CString("")); 
 
		CListCtrl::SetItemData(iNew, (DWORD)pData); 
	} 
 
	return iNew; 
} 
 
//@mfunc Insert a new item into the list 
//@rdesc Returns the index of the new item. 
//@rvalue -1 | Unable to insert item 
int CAutoListCtrl::InsertItem(  
		int nItem,			//@parm Index where item is to be inserted 
		LPCTSTR pszItem )	//@parm Name of the item 
{ 
	ASSERT(AfxIsValidString(pszItem)); 
 
	LV_ITEM	Item; 
 
	Item.mask = LVIF_TEXT; 
	Item.iItem = nItem; 
	Item.iSubItem = 0; 
	Item.pszText = (LPTSTR)pszItem; 
 
	return InsertItem(&Item); 
 
} 
 
//@mfunc Insert a new item into the list 
//@rdesc Returns the index of the new item. 
//@rvalue -1 | Unable to insert item 
int CAutoListCtrl::InsertItem(  
		int nItem,			//@parm Index where item is to be inserted 
		LPCTSTR pszItem,	//@parm Name of the item 
		int nImage )		//@parm Image in imagemap to use for this item 
{ 
	ASSERT(AfxIsValidString(pszItem)); 
 
	LV_ITEM	Item; 
 
	Item.mask = LVIF_TEXT | LVIF_IMAGE; 
	Item.iItem = nItem; 
	Item.iSubItem = 0; 
	Item.pszText = (LPTSTR)pszItem; 
	Item.iImage = nImage; 
 
	return InsertItem(&Item); 
} 
 
//@mfunc Insert a new item into the list 
//@rdesc Returns the index of the new item. 
//@rvalue -1 | Unable to insert item 
int CAutoListCtrl::InsertItem(  
		UINT nMask,			//@parm See  for details 
		int nItem,			//@parm Index where item is to be inserted 
		LPCTSTR pszItem,	//@parm Name of the item 
		UINT nState,		//@parm See  for details 
		UINT nStateMask,	//@parm See  for details 
		int nImage,			//@parm Image from image map to use for this item 
		LPARAM lParam )		//@parm 32-bit value to associate with this item 
{ 
	ASSERT(AfxIsValidString(pszItem)); 
 
	LV_ITEM	Item; 
 
	Item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; 
	Item.iItem = nItem; 
	Item.iSubItem = 0; 
	Item.state = nState; 
	Item.stateMask = nStateMask; 
	Item.pszText = (LPTSTR)pszItem; 
	Item.iImage = nImage; 
	Item.lParam = lParam; 
 
	return InsertItem(&Item); 
} 
 
//@mfunc Set or change the text for a specified column in an item. 
//@rvalue TRUE | Text set successfully 
//@rvalue FALSE | Unable to set text for the specified item or column. 
BOOL CAutoListCtrl::SetItemText( 
		int nItem,		//@parm Index of item to set 
		int nSubItem,	//@parm 0 based column number 
		LPCTSTR pszText)	//@parm New text value for the column 
{ 
	ASSERT(AfxIsValidString(pszText)); 
 
	BOOL fSuccess = CListCtrl::SetItemText(nItem, nSubItem, pszText); 
 
	if(fSuccess) 
	{ 
		CListCtrl::SetColumnWidth(nSubItem, LVSCW_AUTOSIZE_USEHEADER);	// LVSCW_AUTOSIZE 
 
		int iNewWidth = CListCtrl::GetColumnWidth(nSubItem); 
 
		SetMinColumnWidth(nSubItem, iNewWidth); 
		 
		CAutoListItemData	*pData = (CAutoListItemData*)CListCtrl::GetItemData(nItem); 
 
		CString*	pstrCur; 
		if(pData->GetTextMap().Lookup(nSubItem, (PVOID&)pstrCur)) 
		{ 
			pData->GetTextMap().RemoveKey(nSubItem); 
			delete pstrCur; 
		} 
 
		pData->GetTextMap().SetAt(nSubItem, new CString(pszText)); 
 
		CString strName = GetItemText(nItem, 0); 
	} 
 
	return fSuccess; 
} 
 
//@mfunc Retrieve an array of the indexes of all selected items in the list 
//@rvalue Returns the number of elements returned. 
int CAutoListCtrl::GetSelectedItems( 
		int iMaxCount,		// Size of 

int *pIndexArray) // Array of integers to hold item indexes { ASSERT(AfxIsValidAddress(pIndexArray, sizeof(int) * iMaxCount)); int iCount = 0; for(int i = 0; i < GetItemCount(); i++) { if(GetItemState(i, LVIS_SELECTED)) { if(iCount >= iMaxCount) break; pIndexArray[iCount++] = i; } } return iCount; } //@mfunc Change the text of a column header //@rvalue TRUE | Column text set successfully //@rvalue FALSE | Unable to set column text BOOL CAutoListCtrl::SetColumnText( int nCol, //@parm Zero based column number to set. LPCTSTR pszHeading) //@parm New column header text { ASSERT(AfxIsValidString(pszHeading)); LV_COLUMN ColumnInfo; BOOL fSuccess; ColumnInfo.mask = LVCF_TEXT; ColumnInfo.pszText = (LPTSTR)pszHeading; ColumnInfo.cchTextMax = _tcslen(pszHeading); fSuccess = SetColumn(nCol, &ColumnInfo); if(fSuccess) { if(*pszHeading == 0) { m_HeaderWidth[nCol] = 0; SetColumnWidth(nCol, 0); } else { ListView_SetColumnWidth(m_hWnd, nCol, LVSCW_AUTOSIZE_USEHEADER); // LVSCW_AUTOSIZE if(GetColumnWidth(nCol) < GetHeaderWidth(nCol)) SetColumnWidth(nCol, GetHeaderWidth(nCol)); } } return fSuccess; } //@mfunc Assigns an image list to a list view control. //@rdesc Returns a pointer to the previous image list. CImageList* CAutoListCtrl::SetImageList( CImageList* pImageList, //@parm Pointer to the image list to assign int nImageList ) //@parm Type of image list. See // for // details. { ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList), FALSE)); if(pImageList) { IMAGEINFO ImageInfo; memset(&ImageInfo, 0, sizeof(IMAGEINFO)); pImageList->GetImageInfo(0, &ImageInfo); m_dwImageWidth = ImageInfo.rcImage.right - ImageInfo.rcImage.left; } ModifyStyle(0, LVS_SHOWSELALWAYS, 0); return CListCtrl::SetImageList(pImageList, nImageList); } //@mfunc Notification from list control that the user has clicked // on the header of a column. void CAutoListCtrl::OnColumnclick( NMHDR* pNMHDR, //@parm Pointer to structure LRESULT* pResult) //@parm Pointer to result. // @flag 0 | Message processed { ASSERT(AfxIsValidAddress(pNMHDR, sizeof(NMHDR), FALSE)); ASSERT(AfxIsValidAddress(pResult, sizeof(LRESULT), TRUE)); NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; SortOnColumn(pNMListView->iSubItem); *pResult = 0; } //@mfunc Callback function used by list control for sorting. //@rvalue 1 | Item 1 should be placed before Item 2 //@rvalue 0 | Item 1 and Item 2 are identical //@rvalue 1 | Item 2 should be placed before Item 1 int CALLBACK CAutoListCtrl::CompareItems( LPARAM lParam1, //@parm Pointer to containing // text values for each column in item 1 LPARAM lParam2, //@parm Pointer to containing // text values for each column in item 2 LPARAM lParamSort) //@parm Pointer to the list control being sorted. //@devnote Required since this is a static // function which therefore does not have a // this pointer. { CMapWordToPtr *pMap1 = (CMapWordToPtr*)lParam1; CMapWordToPtr *pMap2 = (CMapWordToPtr*)lParam2; CAutoListCtrl *pThis = (CAutoListCtrl*)lParamSort; ASSERT(pMap1); ASSERT(pMap2); CString *pValue1; CString *pValue2; VERIFY( pMap1->Lookup(pThis->GetSortColumn(), (PVOID&)pValue1) ); VERIFY( pMap2->Lookup(pThis->GetSortColumn(), (PVOID&)pValue2) ); int iResult; switch(pThis->GetColumnType(pThis->GetSortColumn() )) { case CAutoListCtrl::TextCol: iResult = pValue1->Compare(*pValue2); break; case CAutoListCtrl::NumberCol: { ASSERT(pThis->GetSortColumn() != 0); int nVal1 = atoi((char*)(LPCTSTR)pValue1); int nVal2 = atoi((char*)(LPCTSTR)pValue2); iResult = (nVal2 - nVal1); break; } case CAutoListCtrl::FileSizeCol: { ASSERT(pThis->GetSortColumn() != 0); int nVal1 = atoi((char*)(LPCTSTR)*pValue1); int nVal2 = atoi((char*)(LPCTSTR)*pValue2); if(pValue1->Right(1) == "K") nVal1 *= 1024; else if(pValue1->Right(1) == "M") nVal1 *= 1024000; if(pValue2->Right(1) == "K") nVal2 *= 1024; else if(pValue2->Right(1) == "M") nVal2 *= 1024000; iResult = nVal2 - nVal1; break; } case CAutoListCtrl::DateCol: { ASSERT(pThis->GetSortColumn() != 0); COleDateTime Date1, Date2; Date1.ParseDateTime((LPCTSTR)*pValue1, VAR_DATEVALUEONLY); Date2.ParseDateTime((LPCTSTR)*pValue2, VAR_DATEVALUEONLY); if(Date1 < Date2) iResult = -1; else if (Date1 > Date2) iResult = 1; else iResult = 0; break; } default: ASSERT(FALSE); } if(!pThis->IsSortAscending()) iResult = -iResult; if((iResult == 0) && (pThis->GetSortColumn() != 0)) { // Use name as a secondary key for identical primary keys VERIFY( pMap1->Lookup(0, (PVOID&)pValue1) ); VERIFY( pMap2->Lookup(0, (PVOID&)pValue2) ); iResult = pValue1->Compare(*pValue2); if(!pThis->IsSortAscending()) iResult = -iResult; } return iResult; } //@mfunc Sort contents of list on specified column. Initially, // the column will be sorted ascending. If the list is // already sorted on the specified column, the sort will // toggle between ascending and descending sort order on // each subsequent call. void CAutoListCtrl::SortOnColumn( int nCol) //@parm Zero based column number. { if(nCol == -1) return; ASSERT(nCol < GetColumnCount()); if(nCol == m_nSortColumn) m_fSortAscending = !m_fSortAscending; else { m_nSortColumn = nCol; m_fSortAscending = TRUE; } SortItems(CompareItems, (DWORD)this); } //@mfunc Delete an item from the list //@rvalue TRUE | Item deleted successfully //@rvalue FALSE | Item could not be deleted BOOL CAutoListCtrl::DeleteItem( int nItem ) //@parm Index of item to delete { CAutoListItemData* pData = (CAutoListItemData*)CListCtrl::GetItemData(nItem); if(pData) { POSITION pos = pData->GetTextMap().GetStartPosition(); WORD wKey; CString* pstrValue; while(pos) { pData->GetTextMap().GetNextAssoc(pos, wKey, (PVOID&)pstrValue); delete pstrValue; } delete pData; } BOOL fSuccess = CListCtrl::DeleteItem(nItem); return fSuccess; } //@mfunc Delete all items in the list //@rvalue TRUE | All items deleted //@rvalue FALSE | No items in the list BOOL CAutoListCtrl::DeleteAllItems( ) { CAutoListItemData* pData = NULL; POSITION pos; WORD wKey; CString* pstrValue; for(int nItem = 0; nItem < GetItemCount(); nItem++) { pData = (CAutoListItemData*)CListCtrl::GetItemData(nItem); if(pData) { pos = pData->GetTextMap().GetStartPosition(); while(pos) { pData->GetTextMap().GetNextAssoc(pos, wKey, (PVOID&)pstrValue); delete pstrValue; } delete pData; } } BOOL fSuccess = CListCtrl::DeleteAllItems(); return fSuccess; } //@mfunc Set the type of data in the specified column. Used // for sorting to determine proper sorting method to use. //@rvalue TRUE | Column type set successfully //@rvalue FALSE | Column type could not be set. BOOL CAutoListCtrl::SetColumnType( int nCol, //@parm Zero based index of column to set int nType) //@parm Type of data. Default is // CAutoListCtrl::TextCol. // @flag TextCol | Text // @flag NumberCol | Numeric Value // @flag FileSizeCol | File Size. Supports // terminology such as 45.3k and 3.2Meg // for sorting purposes. // @flag DateCol | Values are dates (international) { if(nCol > GetColumnCount()) return FALSE; switch(nType) { case CAutoListCtrl::TextCol: case CAutoListCtrl::NumberCol: case CAutoListCtrl::FileSizeCol: case CAutoListCtrl::DateCol: m_ColumnType.SetAt(nCol, nType); return TRUE; default: return FALSE; } } //@mfunc Determine the type of a column //@rdesc Type of the column. See // for details. int CAutoListCtrl::GetColumnType( int nCol) // @parm Zero based column number { if((nCol < 0) || (nCol > GetColumnCount() )) return -1; return m_ColumnType[nCol]; } void CAutoListCtrl::OnDestroy() { DeleteAllItems(); CListCtrl::OnDestroy(); } //@mfunc Set extended list view style //@rdesc Returns TRUE if style was set successfully BOOL CAutoListCtrl::SetExtendedStyle( DWORD dwStyle) //@parm Style to set // @flag CAutoListCtrl::Gridlines | Display the list with gridlines // @flag CAutoListCtrl::SubitemImages | Display images on subitems as well as primary column // @flag CAutoListCtrl::CheckBoxes | Display checkboxes in the list // @flag CAutoListCtrl::TrackSelect | Selects item without clicking. Pausing over item causes selection. // @flag CAutoListCtrl::HeaderDragDrop | Support drag and drop column headers. // @flag CAutoListCtrl::FullRowSelect | Allow the user to click anywhere in the item to allow selection instead // of only over the text in the first column of the item. // @flag CAutoListCtrl::OneClickActivate | Clicking on an inactive list surfaces and selects an item // @flag CAutoListCtrl::TwoClickActivate | First click activates the list; second click selects. { if(!IsWindow(*this)) return FALSE; ListView_SetExtendedListViewStyle(*this, dwStyle); return TRUE; } int CAutoListCtrl::SetCurSel( int nSelect ) { ASSERT(nSelect != -1); if(GetItemCount() < nSelect + 1) return -1; // First deselect any selected items int iSelCount = (int)GetItemCount(); if(iSelCount) { int * pSelected = new int[iSelCount]; iSelCount = GetSelectedItems(iSelCount, pSelected); for(int iSelItem = 0; iSelItem < iSelCount; iSelItem++) SetItemState(pSelected[iSelItem], 0, LVIS_SELECTED); delete[] pSelected; // Select the new item if(!SetItemState(nSelect, LVIS_SELECTED, LVIS_SELECTED)) { ASSERT(FALSE); } } return 0; } DWORD CAutoListCtrl::GetItemData( int nItem ) const { CAutoListItemData* pData = (CAutoListItemData*)CListCtrl::GetItemData(nItem); if(!pData) return 0; return pData->GetData(); } BOOL CAutoListCtrl::SetItemData(int nItem, DWORD dwData) { CAutoListItemData* pData = (CAutoListItemData*)CListCtrl::GetItemData(nItem); if(!pData) return CListCtrl::SetItemData(nItem, (DWORD) new CAutoListItemData(dwData)); return pData->SetData(dwData); } int CAutoListCtrl::GetCurSel() { int iSel; int iCount = GetSelectedItems(1, &iSel); if(iCount == 0) return -1; return iSel; }