484 lines
9.1 KiB
C++
484 lines
9.1 KiB
C++
// GenListCtrl.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "GenListCtrl.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGenListCtrl
|
|
|
|
CGenListCtrl::CGenListCtrl()
|
|
{
|
|
m_lNumOfColumns = 0;
|
|
m_lCurrentColumn = -1L;
|
|
m_pColumnHdrArr = NULL;
|
|
}
|
|
|
|
CGenListCtrl::~CGenListCtrl()
|
|
{
|
|
if(m_pColumnHdrArr) delete [] m_pColumnHdrArr;
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGenListCtrl, CListCtrl)
|
|
//{{AFX_MSG_MAP(CGenListCtrl)
|
|
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclickRef)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGenListCtrl message handlers
|
|
void
|
|
CGenListCtrl::ResizeColumnsFitScreen()
|
|
{
|
|
CRect rcListCtrl;
|
|
int cCtrlWidth = 0;
|
|
int nColWidth = 0;
|
|
int nNumCols = 0;
|
|
int nIdx = 0;
|
|
CHeaderCtrl *pHdrCtl = NULL;
|
|
|
|
do
|
|
{
|
|
if(::IsWindow(m_hWnd) == FALSE) break;
|
|
|
|
GetClientRect(&rcListCtrl);
|
|
cCtrlWidth = rcListCtrl.right - rcListCtrl.left;
|
|
|
|
//
|
|
// Remember to take care of the Vertical scroll
|
|
// bar when calculating the width of the control.
|
|
//
|
|
if(GetScrollBarCtrl(SB_VERT) != NULL){
|
|
cCtrlWidth -= GetSystemMetrics(SM_CXVSCROLL);
|
|
}
|
|
|
|
pHdrCtl = GetHeaderCtrl();
|
|
if(pHdrCtl == NULL) break;
|
|
|
|
nNumCols = pHdrCtl->GetItemCount();
|
|
if(nNumCols == 0) break; // No columns are as yet
|
|
// inserted..
|
|
|
|
//
|
|
// This gives the width (new) of each column.
|
|
//
|
|
nColWidth = cCtrlWidth / nNumCols;
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
while(nIdx < nNumCols){
|
|
SetColumnWidth(nIdx++, nColWidth);
|
|
}
|
|
|
|
SetRedraw(TRUE);
|
|
InvalidateRect(NULL);
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::ResizeColumnsWithRatio()
|
|
{
|
|
int nNumColumns = 0;
|
|
int *pWidths = NULL;
|
|
int nTotalColumnWidth = 0;
|
|
int nIdx = 0;
|
|
CHeaderCtrl *pHdrCtl = NULL;
|
|
RECT rectList;
|
|
|
|
do
|
|
{
|
|
if(::IsWindow(m_hWnd) == FALSE) break;
|
|
|
|
pHdrCtl = GetHeaderCtrl();
|
|
if(pHdrCtl == NULL) break;
|
|
|
|
nNumColumns = pHdrCtl->GetItemCount();
|
|
|
|
//
|
|
// To store the widths of each column.
|
|
//
|
|
pWidths = new int[nNumColumns];
|
|
if(pWidths == NULL) break;
|
|
|
|
nIdx = 0;
|
|
while(nIdx < nNumColumns){
|
|
pWidths[nIdx] = GetColumnWidth(nIdx);
|
|
|
|
//
|
|
// We need to calculate the sum of
|
|
// all the column widths for finding
|
|
// the %widths of each column.
|
|
//
|
|
nTotalColumnWidth += pWidths[nIdx++];
|
|
}
|
|
|
|
//
|
|
// 1. No columns are inserted as yet
|
|
// 2. Or, all the columns have been
|
|
// reduced to 0 width.
|
|
//
|
|
if(nTotalColumnWidth == 0) break;
|
|
|
|
//
|
|
// This is the new width, to which the
|
|
// columns have to be distributed..
|
|
//
|
|
GetClientRect(&rectList);
|
|
nIdx = 0;
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
while(nIdx < nNumColumns){
|
|
SetColumnWidth(nIdx, (pWidths[nIdx++] * (rectList.right - rectList.left)) / nTotalColumnWidth);
|
|
}
|
|
|
|
SetRedraw(TRUE);
|
|
InvalidateRect(NULL);
|
|
}
|
|
while(FALSE);
|
|
|
|
if(pWidths)delete[] pWidths;
|
|
}
|
|
|
|
BOOL
|
|
CGenListCtrl::SelectItem
|
|
(
|
|
IN LONG nIndex
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// This ensures the items are scrolled as
|
|
// needed to make the item at nIndex visible..
|
|
//
|
|
bRet = EnsureVisible(nIndex, FALSE);
|
|
|
|
//
|
|
// This selects the item.
|
|
//
|
|
if( bRet )
|
|
bRet = SetItemState(nIndex,
|
|
LVIS_SELECTED | LVIS_FOCUSED,
|
|
LVIS_SELECTED | LVIS_FOCUSED
|
|
);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::BeginSetColumn
|
|
(
|
|
IN LONG nCols
|
|
)
|
|
{
|
|
if(nCols == 0) return;
|
|
|
|
m_lNumOfColumns = nCols;
|
|
|
|
//
|
|
// Allocate enough memory to store header data..
|
|
//
|
|
m_pColumnHdrArr = new GenListCtrlHeader[nCols];
|
|
if(m_pColumnHdrArr == NULL) /* ? */ return;
|
|
|
|
//
|
|
// Starting from the first column..
|
|
//
|
|
m_lCurrentColumn = 0L;
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::AddColumn
|
|
(
|
|
IN LPCTSTR pszColumn,
|
|
IN short nType
|
|
)
|
|
{
|
|
do
|
|
{
|
|
if(m_lCurrentColumn >= m_lNumOfColumns) break;
|
|
|
|
//
|
|
// BeginSetColumn, not called yet?
|
|
//
|
|
if(m_pColumnHdrArr == NULL) break;
|
|
|
|
if(pszColumn == NULL) break;
|
|
|
|
m_pColumnHdrArr[m_lCurrentColumn].csText = pszColumn;
|
|
m_pColumnHdrArr[m_lCurrentColumn].nType = nType;
|
|
|
|
//
|
|
// Will be pointing to the next column, next
|
|
// time AddColumn is called.. This will also
|
|
// be an indicator to the number of columns
|
|
// actually added..
|
|
//
|
|
++m_lCurrentColumn;
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::EndSetColumn()
|
|
{
|
|
int nIdx = 0;
|
|
|
|
do
|
|
{
|
|
SetRedraw(FALSE);
|
|
|
|
//
|
|
// Insert all the columns when EndSetColumn is
|
|
// called. This helps in avoiding the flicker
|
|
// that is experienced if we insert one column
|
|
// at a time..
|
|
//
|
|
while(nIdx < m_lCurrentColumn){
|
|
InsertColumn(nIdx, m_pColumnHdrArr[nIdx++].csText);
|
|
}
|
|
|
|
SetRedraw(TRUE);
|
|
InvalidateRect(NULL);
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
LONG
|
|
CGenListCtrl::SetItemText
|
|
(
|
|
IN LONG nRow,
|
|
IN LONG nCol,
|
|
IN LPCTSTR pszText
|
|
)
|
|
{
|
|
LONG lRet = -1L;
|
|
LONG lNumItems = 0L;
|
|
|
|
lNumItems = GetItemCount();
|
|
|
|
//
|
|
// New Item is being inserted..
|
|
//
|
|
if( nRow == lNumItems ||
|
|
nRow == -1L){
|
|
lRet = InsertItem(lNumItems, pszText);
|
|
}
|
|
//
|
|
// SubItem text is being set..
|
|
//
|
|
else if(nRow < lNumItems &&
|
|
(nCol >= 1 && nCol < m_lCurrentColumn)){
|
|
lRet = CListCtrl::SetItemText(nRow, nCol, pszText);
|
|
lRet == 0 ? lRet = -1 : lRet = nRow;
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
int CALLBACK
|
|
CGenListCtrl::CompareItems
|
|
(
|
|
IN LPARAM lParam1,
|
|
IN LPARAM lParam2,
|
|
IN LPARAM lParamSort
|
|
)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::OnColumnclickRef
|
|
(
|
|
IN NMHDR *pNMHDR,
|
|
IN LRESULT *pResult
|
|
)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
// TODO: Add your control notification handler code here
|
|
|
|
static int nEarlierColumn = pNMListView->iSubItem;
|
|
|
|
if(nEarlierColumn == pNMListView->iSubItem){
|
|
m_bAscending = !m_bAscending;
|
|
}
|
|
else{
|
|
m_bAscending = TRUE;
|
|
}
|
|
|
|
nEarlierColumn = pNMListView->iSubItem;
|
|
BubbleSortItems(nEarlierColumn, m_bAscending, m_pColumnHdrArr[nEarlierColumn].nType);
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
int
|
|
CGenListCtrl::GenCompareFunc
|
|
(
|
|
IN LPARAM lParam1,
|
|
IN LPARAM lParam2
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
CGenListCtrl::BubbleSortItems
|
|
(
|
|
IN int nCol,
|
|
IN BOOL bAscending,
|
|
IN short nType,
|
|
IN int nLo,
|
|
IN int nHi
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
CHeaderCtrl *pHdrCtl = GetHeaderCtrl();
|
|
LONG nNumCols = 0L;
|
|
CString csTextLo = _T("");
|
|
CString csTextHi = _T("");
|
|
|
|
do
|
|
{
|
|
if(!(pHdrCtl == NULL) &&
|
|
((nNumCols = pHdrCtl->GetItemCount()) == 0L) &&
|
|
(nCol >= nNumCols)
|
|
) break;
|
|
|
|
if(nHi == -1) nHi = GetItemCount();
|
|
|
|
for(int i = nLo; i < nHi; i++){
|
|
for(int j = i + 1; j < nHi; j++){
|
|
csTextLo = GetItemText(i, nCol);
|
|
csTextHi = GetItemText(j, nCol);
|
|
|
|
switch(nType)
|
|
{
|
|
case VT_BSTR:
|
|
if(bAscending == TRUE){
|
|
if(csTextLo.CompareNoCase(csTextHi) > 0){
|
|
SwapRows(i, j);
|
|
}
|
|
}
|
|
else{
|
|
if(csTextLo.CompareNoCase(csTextHi) < 0){
|
|
SwapRows(i, j);
|
|
}
|
|
}
|
|
break;
|
|
case VT_I4:
|
|
if(bAscending == TRUE){
|
|
if(_ttol(csTextLo) > _ttol(csTextHi)){
|
|
SwapRows(i, j);
|
|
}
|
|
}
|
|
else{
|
|
if(_ttol(csTextLo) < _ttol(csTextHi)){
|
|
SwapRows(i, j);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while(FALSE);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void
|
|
CGenListCtrl::SwapRows
|
|
(
|
|
IN LONG lRowLo,
|
|
IN LONG lRowHi
|
|
)
|
|
{
|
|
LVITEM lviLo, lviHi;
|
|
CStringArray arrAllColumnsText;
|
|
LONG nNumCols = GetHeaderCtrl()->GetItemCount();
|
|
|
|
arrAllColumnsText.SetSize(nNumCols);
|
|
|
|
lviLo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_INDENT;
|
|
lviLo.iItem = lRowLo;
|
|
|
|
lviLo.iSubItem = 0;
|
|
lviLo.stateMask = -1; // All state masks...
|
|
|
|
lviHi = lviLo;
|
|
lviHi.iItem = lRowHi;
|
|
|
|
GetItem( &lviLo );
|
|
GetItem( &lviHi );
|
|
|
|
CString csTest = GetItemText(lRowLo, 0);
|
|
csTest = GetItemText(lRowLo, 1);
|
|
csTest = GetItemText(lRowLo, 2);
|
|
|
|
for(int i = 0; i < nNumCols; i++)
|
|
arrAllColumnsText[i] = GetItemText(lRowLo, i);
|
|
|
|
for(i = 0; i < nNumCols; i++)
|
|
CListCtrl::SetItemText(lRowLo, i, GetItemText(lRowHi, i));
|
|
|
|
lviHi.iItem = lRowLo;
|
|
SetItem( &lviHi );
|
|
|
|
for(i = 0; i < nNumCols; i++)
|
|
CListCtrl::SetItemText(lRowHi, i, arrAllColumnsText[i]);
|
|
|
|
lviLo.iItem = lRowHi;
|
|
SetItem( &lviLo );
|
|
}
|
|
|
|
|
|
BOOL CGenListCtrl::IsAscending()
|
|
{
|
|
return m_bAscending;
|
|
}
|
|
|
|
PGenListCtrlHeader CGenListCtrl::GetListCtrlHeader()
|
|
{
|
|
return m_pColumnHdrArr;
|
|
}
|
|
|
|
HRESULT CGenListCtrl::ResetListCtrl()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
do {
|
|
//Count the number of rows and delete them all
|
|
CGenListCtrl::DeleteAllItems();
|
|
|
|
//Count the number of columns and delete them all
|
|
int nColumnCount = GetHeaderCtrl()->GetItemCount();
|
|
|
|
// Delete all of the columns.
|
|
for (int i=0;i < nColumnCount;i++)
|
|
{
|
|
DeleteColumn(0);
|
|
}
|
|
//Reset the member variables to their initial values
|
|
m_bAscending = FALSE;
|
|
m_lColumnClicked = 0;
|
|
m_lCurrentColumn = -1L;
|
|
m_lNumOfColumns = 0;
|
|
|
|
//We need to delete the hdrarray
|
|
if(m_pColumnHdrArr) delete [] m_pColumnHdrArr;
|
|
m_pColumnHdrArr = NULL;
|
|
} while (FALSE);
|
|
|
|
return hr;
|
|
}
|