2020-09-30 16:53:49 +02:00

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;
}