///////////////////////////////////////////////////////////////////////////////
// ReportCtrl.cpp
//
// CReportCtrl, a CListCtrl derived class that is specialized on "Report View"
// style.
//
// Features:
//
// 1, Item sorting by clicking on column header.
// 2, Sub-item text edit.
// 3, Item repositioning.
// 4, Customizing checkbox styles, including "single" and "disabled".
// 5, Sending a message to parent window when user clicks on a checkbox.
// 6, Convenient item insertion, deletion, moving, and sub-item text changing.
// 7, Sub-item images and color
// 8, And much more...
//
// 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. If the source code in this file is used in any commercial application
// then acknowledgement must be made to the author of this file .
//
// This file is provided "as is" with no expressed or implied warranty.
//
// Written by Bin Liu (abinn32@yahoo.com)
//
// History
//
// Nov. 26, 2003 - Initial release.
// Dec. 03, 2003 - Fixed a bug in "EndEdit" where item text were not preperly committed.
// - Completed the implementation of the "Sort-Separator" feature.
// Jan. 01, 2004 - Fixed a bug in "SetItemData".
// - Added message "WM_EDIT_COMMITTED" which is sent to the parent window
// when an item text editing is committed.
// - Fixed a bug in "SetItemText"(double type).
// - Fixed a bug where item sorting does not work properly when there
// are multiple CReportCtrl objects on same window.
//
///////////////////////////////////////////////////////////////////////////////
// enhence by Left and popo for hyperlink function and editable cell.
#include "stdafx.h"
#include "ReportCtrl.h"
#include <afxtempl.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Below styles MUST be present in a report ctrl
#define MUST_STYLE (WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | LVS_REPORT)
#define MUST_EX_STYLE (LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES)
// Below styles MUST NOT be present in a report ctrl
#define MUST_NOT_STYLE (LVS_EDITLABELS | LVS_ICON | LVS_SMALLICON | LVS_LIST | LVS_NOSCROLL)
#define MUST_NOT_EX_STYLE (0)
struct ROWINFO
{
DWORD dwData;
DWORD dwStates;
CArray<int, int> aImages;
CStringArray aTexts;
};
//////////////////////////////////////////////////////////////////////////
// CItemData class is used for store extra information
//////////////////////////////////////////////////////////////////////////
class CItemData
{
public:
CItemData() { dwData = 0; }
void InsertColumn(int nColumn);
void DeleteColumn(int nColumn);
DWORD dwData; // The actual 32-bit user data stores here
CArray<COLORREF, COLORREF> aTextColors; // Sub item text colors
CArray<COLORREF, COLORREF> aBkColors; // Sub item backgroud colors
//add by liuxiao for HyperLink 2007.11.30 begin
CArray<BOOL, BOOL> arIsHyperLink;
CArray<BOOL, BOOL> arIsHoverOn;
CArray<CString, CString&> arStrUrl;
CArray<CString, CString&> arStrTooltip;
CArray<BOOL, BOOL> arIsEditable;
//add by liuxiao for HyperLink 2007.11.30 end
////add by popo 2007.12.1 begin
//void SetEditable(int nColumn, BOOL IsEditable);
//BOOL GetEditable(int nColumn);
////add by popo 2007.12.1 end
};
void CItemData::InsertColumn(int nColumn)
{
aTextColors.InsertAt(nColumn, ::GetSysColor(COLOR_WINDOWTEXT));
aBkColors.InsertAt(nColumn, ::GetSysColor(COLOR_WINDOW));
arIsEditable.InsertAt(nColumn, FALSE);
}
void CItemData::DeleteColumn(int nColumn)
{
aTextColors.RemoveAt(nColumn);
aBkColors.RemoveAt(nColumn);
arIsEditable.RemoveAt(nColumn);
}
//////add by popo 2007.12.1 begin
//void CItemData::SetEditable(int nColumn, BOOL IsEditable)
//{
// arIsEditable.InsertAt(nColumn, IsEditable);
//}
//BOOL CItemData::GetEditable(int nColumn)
//{
// BOOL IsEditable = arIsEditable.GetAt(nColumn);
// arIsEditable.RemoveAt(nColumn);
// return IsEditable;
//}
//////add by popo 2007.12.1 end
///////////////////////////////////////////////////////////////////////
// A set of functions used for item text format determining
///////////////////////////////////////////////////////////////////////
namespace _ITEM_COMPARE_FUNCS
{
BOOL _IsDecNumber(const CString& str, double& f);
int _DecNumberCompare(double f1, double f2);
BOOL _IsHexNumber(const CString& str, DWORD& dw);
int _HexNumberCompare(DWORD dw1, DWORD dw2);
BOOL _IsDate(const CString& str, COleDateTime& date);
int _DateCompare(const COleDateTime& date1, const COleDateTime& date2);
};
BOOL _ITEM_COMPARE_FUNCS::_IsDecNumber(const CString& str, double& f)
{
if (str.IsEmpty())
return FALSE;
LPTSTR p;
f = _tcstod(str, &p);
return (*p == _T('\0') || (*p == _T('%') && p[1] == _T('\0')));
}
int _ITEM_COMPARE_FUNCS::_DecNumberCompare(double f1, double f2)
{
if(f1 < f2)
return -1;
if(f1 > f2)
return 1;
return 0;
}
BOOL _ITEM_COMPARE_FUNCS::_IsHexNumber(const CString& str, DWORD& dw)
{
if (str.IsEmpty())
return FALSE;
LPTSTR p;
dw = _tcstoul(str, &p, 16);
return *p == _T('\0');
}
int _ITEM_COMPARE_FUNCS::_HexNumberCompare(DWORD dw1, DWORD dw2)
{
if (dw1 > dw2)
return 1;
if (dw1 < dw2)
return -1;
return 0;
}
BOOL _ITEM_COMPARE_FUNCS::_IsDate(const CString& str, COleDateTime& date)
{
return date.ParseDateTime(str);
}
int _ITEM_COMPARE_FUNCS::_DateCompare(const COleDateTime& date1, const COleDateTime& date2)
{
if (date1 < date2)
return -1;
if (date1 > date2)
return 1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl Implementation
/////////////////////////////////////////////////////////////////////////////
CReportCtrl::CReportCtrl(): m_pWndEdit(NULL)
{
m_pWndEdit = new CEdit;
VERIFY(m_pWndEdit != NULL);
m_pszSeparator = NULL;
m_ptEditting.x = -1;
m_ptEditting.y = -1;
m_nChkStyle = RC_CHKBOX_NORMAL;
m_dwPrevEditFmt = ES_LEFT;
m_nSortCol = -1;
m_bSortAscending = TRUE;
}
CReportCtrl::~CReportCtrl()
{
if (m_pszSeparator != NULL)
delete [] m_pszSeparator;
if (m_pWndEdit != NULL)
delete m_pWndEdit;
}
BEGIN_MESSAGE_MAP(CReportCtrl, CListCtrl)
//{{AFX_MSG_MAP(CReportCtrl)
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
ON_WM_LBUTTONDOWN()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_LBUTTONDBLCLK()
ON_WM_MBUTTONDOWN()
ON_WM_MBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONDBLCLK()
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
//}}AFX_MSG_MAP
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl message handlers
void CReportCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR;
if (lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
{
*pResult = CDRF_NOTIFYITEMDRAW;
}
else if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW;
}
else if (lplvcd->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(lplvcd->nmcd.dwItemSpec));
ASSERT(p != NULL);
ASSERT(lplvcd->iSubItem >= 0 && lplvcd->iSubItem < p->aTextColors.GetSize());
lplvcd->clrText = p->aTextColors[lplvcd->iSubItem];
lplvcd->clrTextBk = p->aBkColors[lplvcd->iSubItem];
*pResult = CDRF_DODEFAULT;
//add by liuxiao for HyperLink 2007.11.30 begin
if (p->arIsHyperLink[lplvcd->iSubItem])
{
if (p->arIsHoverOn[lplvcd->iSubItem])
{
::SelectObject(lplvcd->nmcd.hdc, m_ftUnderline.m_hObject