Files

4372 lines
97 KiB
C++

////////////////////////////////////////////////////////////////////////////
// File: CReportCtrl.cpp
// Version: 1.1.0
//
// Author: Maarten Hoeben
// E-mail: maarten.hoeben@nwn.com
//
// Implementation of the CReportCtrl and associated classes.
//
// 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 and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// Version history
//
// 1.0.1 - Initial release.
// 1.1.0 - Changed copyright notice.
// - Added RVN_LAYOUTCHANGED notification message.
// - Fixed SB_THUMBPOSITION and SB_THUMBTRACK problems.
// - Removed IDC_HEADERCTRL and IDC_REPORTCTRL definitions.
// Now hardcoded because conflicts with some implementations.
// - Added SortAllColumns(), contributed by Roger Parkinson.
// - Added Chris Hambleton's suggestion to sort on image.
// indices when the (sub)item does not have text.
// - Fixed DeleteAllItems(), as suggested by Paul Leung.
// - Fixed DeleteAllItems() focus problem, as suggested by Dmitry ??.
// - Fixed DeleteItem(), as noted by Eugenio Ciceri.
// - Added fixes and suggestions of Serge Weinstock:
// - Fixed GetNextSelectedItem().
// - Fixed "no items to show" position.
// - Added support for WS_BORDER style.
// - Added RVN_ITEMDELETED notification.
// - Added mouse-wheel support.
// - Added extended horizontal grid style and changed regular
// horizontal grid style.
// - Fixed selection inversion using space key.
// - Fixed focus selection using ctrl key.
// - Fixed focus on deleted items.
// - Added RVS_OWNERDATA style.
// - Changed notification structure to facilitate
// RVS_OWNERDATA style.
// - Changed hit test info structure to facilitate
// RVS_FOCUSSUBITEMS style.
// - Added RVS_FOCUSSUBITEMS style to enable focus on individual
// subitems to facilitate subitem editing.
// - Added dialog control ID to WPARAM of notification messages.
// - Added subitem editing functionality.
// - Added CReportEditCtrl edit control.
// - Added CReportComboCtrl edit control.
// - Added support for RVIM_TEXT on empty strings (required for
// editing).
// - Added RVIS_READONLY state.
// - Added rect member to RVHITTESTINFO structure.
// - Added RVS_EXPANDSUBITEMS style.
// - Added CReportTipCtrl, based on code by Zafir Anjum.
// - Added background image support, based on code contributed by
// Ernest Laurentin.
//
////////////////////////////////////////////////////////////////////////////
// ReportCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "ReportCtrl.h"
#include "MemDC.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
TCHAR* g_szSeparator = _T("|");
#define IsShiftDown() ( (GetKeyState(VK_SHIFT) & (1 << (sizeof(SHORT)*8-1))) != 0 )
#define IsCtrlDown() ( (GetKeyState(VK_CONTROL) & (1 << (sizeof(SHORT)*8-1))) != 0 )
/////////////////////////////////////////////////////////////////////////////
// CReportData
CReportData::CReportData()
{
}
CReportData::~CReportData()
{
}
BOOL CReportData::New(INT iSubItems)
{
for(INT i=0;i<iSubItems;i++)
{
CString str;
str.Format(_T("(-1,-1,-1,-1)%s"), g_szSeparator);
*this += str;
}
return TRUE;
}
BOOL CReportData::GetSubItem(INT iSubItem, LPINT lpiImage, LPINT lpiCheck, LPINT lpiColor, LPTSTR lpszText, LPINT lpiTextMax)
{
INT i, iPos, iText;
for(i=0,iPos=0;i<iSubItem&&iPos>=0;i++,iPos++)
iPos = Find(g_szSeparator, iPos);
if(iPos<0)
return FALSE;
LPTSTR lpsz = GetBuffer(0);
lpsz = &lpsz[iPos];
VERIFY(_stscanf(lpsz, _T("(%d,%d,%d,%d)"), lpiImage, lpiCheck, lpiColor, &iText));
if(iText < 0)
{
*lpiTextMax = -1;
return TRUE;
}
lpsz = _tcspbrk(lpsz, _T(")"))+1;
if(lpsz && lpszText)
{
for(INT iTextSize=0;iTextSize<(*lpiTextMax)-1 && *lpsz!=g_szSeparator[0];iTextSize++)
lpszText[iTextSize] = *lpsz++;
lpszText[iTextSize] = 0;
}
return TRUE;
}
BOOL CReportData::SetSubItem(INT iSubItem, INT iImage, INT iCheck, INT iColor, LPCTSTR lpszText)
{
if(!InsertSubItem(iSubItem, iImage, iCheck, iColor, lpszText))
return FALSE;
if(!DeleteSubItem(iSubItem+1))
return FALSE;
return TRUE;
}
BOOL CReportData::InsertSubItem(INT iSubItem, INT iImage, INT iCheck, INT iColor, LPCTSTR lpszText)
{
INT i, iPos, iText;
for(i=0,iPos=0;i<iSubItem&&iPos>=0;i++,iPos++)
iPos = Find(g_szSeparator, iPos);
if(iPos<0)
return FALSE;
if(lpszText == NULL)
{
lpszText = _T("");
iText = -1;
}
else
iText = _tcslen(lpszText);
CString str;
str.Format("(%d,%d,%d,%d)%s%s", iImage, iCheck, iColor, iText, lpszText, g_szSeparator);
Insert(iPos, str);
return TRUE;
}
BOOL CReportData::DeleteSubItem(INT iSubItem)
{
INT i, iPos1, iPos2;
for(i=0,iPos1=0;i<iSubItem&&iPos1>=0;i++,iPos1++)
iPos1 = Find(g_szSeparator, iPos1);
if(iPos1<0)
return FALSE;
iPos2 = Find(g_szSeparator, iPos1);
if(iPos2++<0)
return FALSE;
Delete(iPos1, iPos2-iPos1);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CReportView
IMPLEMENT_DYNCREATE(CReportView, CView)
CReportView::CReportView()
{
m_bCreated = FALSE;
}
CReportView::~CReportView()
{
}
void CReportView::OnInitialUpdate()
{
CView::OnInitialUpdate();
if(!m_bCreated)
{
CRect rect;
GetClientRect(rect);
if(m_wndReportCtrl.Create(WS_CHILD|WS_TABSTOP|WS_VISIBLE, rect, this, 0) == NULL)
AfxThrowMemoryException();
m_bCreated = TRUE;
}
}
BEGIN_MESSAGE_MAP(CReportView, CView)
//{{AFX_MSG_MAP(CReportView)
ON_WM_SIZE()
ON_WM_SETFOCUS()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportView drawing
void CReportView::OnDraw(CDC* pDC)
{
;
}
/////////////////////////////////////////////////////////////////////////////
// CReportView diagnostics
#ifdef _DEBUG
void CReportView::AssertValid() const
{
CView::AssertValid();
}
void CReportView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CReportView attributes
CReportCtrl& CReportView::GetReportCtrl()
{
return m_wndReportCtrl;
}
CReportCtrl* CReportView::GetReportCtrlPtr()
{
return &m_wndReportCtrl;
}
/////////////////////////////////////////////////////////////////////////////
// CReportView implementation
BOOL CReportView::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CReportView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if(m_wndReportCtrl.GetSafeHwnd())
{
CRect rect;
GetClientRect(rect);
m_wndReportCtrl.MoveWindow(rect);
}
}
void CReportView::OnSetFocus(CWnd* pOldWnd)
{
m_wndReportCtrl.SetFocus();
}
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl
IMPLEMENT_DYNCREATE(CReportCtrl, CWnd)
CReportCtrl::CReportCtrl()
{
// Register the window class if it has not already been registered.
WNDCLASS wndclass;
HINSTANCE hInst = AfxGetInstanceHandle();
if(!(::GetClassInfo(hInst, REPORTCTRL_CLASSNAME, &wndclass)))
{
// Otherwise we need to register a new class
wndclass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = ::DefWindowProc;
wndclass.cbClsExtra = wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(hInst, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = REPORTCTRL_CLASSNAME;
if (!AfxRegisterClass(&wndclass))
AfxThrowResourceException();
}
m_bSubclassFromCreate = FALSE;
m_bDoubleBuffer = TRUE;
m_iSpacing = 6;
m_nRowsPerWheelNotch = GetMouseScrollLines();
m_dwStyle = 0;
// Initially use the system message font for the ReportCtrl font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
m_font.CreateFontIndirect(&(ncm.lfMessageFont));
m_pImageList = NULL;
m_sizeImage.cx = 0;
m_sizeImage.cy = 0;
m_sizeCheck.cx = 8;
m_sizeCheck.cy = 8;
GetSysColors();
m_arrayColors.SetSize(0, 8);
m_iGridStyle = PS_SOLID;
m_strNoItems = _T("There are no items to show in this view.");
m_iDefaultWidth = 200;
m_iDefaultHeight = 10;
m_iVirtualWidth = 0;
m_iVirtualHeight = 0;
m_arraySubItems.SetSize(0, 8);
m_arrayItems.SetSize(0, 128);
m_bColumnsReordered = FALSE;
m_arrayColumns.SetSize(0, 8);
m_bFocus = FALSE;
m_iFocusRow = RVI_EDIT;
m_iFocusColumn = -1;
m_iSelectRow = 0;
m_arrayRows.SetSize(0, 128);
INT m_iEditItem = RVI_INVALID;
INT m_iEditSubItem = -1;
m_hEditWnd = NULL;
m_lprclc = NULL;
m_lpfnrvc = NULL;
}
CReportCtrl::~CReportCtrl()
{
m_wndHeader.DestroyWindow();
m_wndTip.DestroyWindow();
if(m_palette.m_hObject)
m_palette.DeleteObject();
if( m_bitmap.m_hObject != NULL )
m_bitmap.DeleteObject();
if(m_font.m_hObject)
m_font.DeleteObject();
if(m_fontBold.m_hObject)
m_fontBold.DeleteObject();
}
INT CReportCtrl::PreviewHeight(CFont* pFont, UINT nLines)
{
INT iHeight = -1;
ASSERT(pFont != NULL);
CDC* pDC = GetDC();
if(pDC)
{
CFont* pDCFont = pDC->SelectObject(pFont);
TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);
pDC->SelectObject(pDCFont);
ReleaseDC(pDC);
iHeight = (tm.tmHeight + tm.tmExternalLeading)*nLines;
}
return iHeight;
}
INT CReportCtrl::PreviewHeight(CFont* pFont, LPCTSTR lpszText, LPRECT lpRect)
{
INT iHeight = -1;
ASSERT(pFont != NULL);
CDC* pDC = GetDC();
if(pDC)
{
CRect rect( 0, 0, m_iVirtualWidth, 0);
if(lpRect != NULL)
rect = *lpRect;
CFont* pDCFont = pDC->SelectObject(pFont);
iHeight = pDC->DrawText( lpszText, -1, rect, DT_CALCRECT|DT_EXPANDTABS|DT_WORDBREAK|DT_NOCLIP );
ReleaseDC(pDC);
}
return iHeight;
}
BOOL CReportCtrl::Create()
{
CRect rect(0, 0, 0, 0);
DWORD dwStyle = HDS_HORZ|HDS_BUTTONS|HDS_FULLDRAG|HDS_DRAGDROP|CCS_TOP;
if(!m_wndHeader.Create(dwStyle, rect, this, 0))
return FALSE;
if(!m_wndTip.Create(this))
return FALSE;
CWnd* pWnd = GetParent();
if(pWnd)
{
CFont* pFont = pWnd->GetFont();
if(pFont)
{
LOGFONT lf;
pFont->GetLogFont(&lf);
m_font.DeleteObject();
m_font.CreateFontIndirect(&lf);
}
}
OnSetFont((WPARAM)((HFONT)m_font), FALSE);
m_wndHeader.SetFont(&m_font, FALSE);
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
m_dwStyle = GetStyle();
if(m_dwStyle&RVS_FOCUSSUBITEMS)
m_iFocusColumn = 0;
return TRUE;
}
BOOL CReportCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
m_bSubclassFromCreate = TRUE;
if(!CWnd::Create(REPORTCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext))
return FALSE;
return Create();
}
void CReportCtrl::PreSubclassWindow()
{
CWnd::PreSubclassWindow();
if(!m_bSubclassFromCreate)
if(!Create())
AfxThrowMemoryException();
}
void CReportCtrl::OnDestroy()
{
DeleteAllItems();
CWnd::OnDestroy();
}
BEGIN_MESSAGE_MAP(CReportCtrl, CWnd)
//{{AFX_MSG_MAP(CReportCtrl)
ON_WM_DESTROY()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_SYSCOLORCHANGE()
ON_WM_SETTINGCHANGE()
ON_NOTIFY(HDN_ITEMCHANGED, 0, OnHdnItemChanged)
ON_NOTIFY(HDN_ITEMCLICK, 0, OnHdnItemClick)
ON_NOTIFY(HDN_BEGINDRAG, 0, OnHdnBeginDrag)
ON_NOTIFY(HDN_ENDDRAG, 0, OnHdnEndDrag)
ON_NOTIFY(RVN_ENDITEMEDIT, 0, OnRvnEndItemEdit)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_KEYDOWN()
ON_WM_GETDLGCODE()
ON_WM_LBUTTONDBLCLK()
ON_WM_QUERYNEWPALETTE()
ON_WM_PALETTECHANGED()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_NCCALCSIZE()
ON_WM_NCPAINT()
ON_WM_MOUSEWHEEL()
ON_WM_CHAR()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_MESSAGE(WM_GETFONT, OnGetFont)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl attributes
BOOL CReportCtrl::ModifyProperty(WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case RVP_SPACING:
m_iSpacing = (INT)lParam;
break;
case RVP_CHECK:
m_sizeCheck.cx = LOWORD(lParam);
m_sizeCheck.cy = HIWORD(lParam);
break;
case RVP_NOITEMTEXT:
m_strNoItems = (LPCTSTR)lParam;
break;
case RVP_GRIDSTYLE:
switch(wParam)
{
case RVP_GRIDSTYLE_DOT: m_iGridStyle = PS_DOT; break;
case RVP_GRIDSTYLE_DASH: m_iGridStyle = PS_DASH; break;
case RVP_GRIDSTYLE_SOLID: m_iGridStyle = PS_SOLID; break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
CRect rect;
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
return TRUE;
}
INT CReportCtrl::ActivateColumn(INT iColumn, INT iOrder)
{
ASSERT(iColumn>=0);
ASSERT(iColumn<m_arraySubItems.GetSize()); // Specify a valid column
SUBITEM& subitem = m_arraySubItems[iColumn];
INT iResult = -1;
INT iHeaderItems = m_arrayColumns.GetSize();
HDITEM hdi;
hdi.mask = HDI_LPARAM;
for(INT iItem=0;iItem<iHeaderItems;iItem++)
if(m_wndHeader.GetItem(iItem, &hdi))
if(hdi.lParam == iColumn)
break;
if(iItem == iHeaderItems)
{
try
{
hdi.mask = HDI_FORMAT|HDI_WIDTH|HDI_LPARAM|HDI_ORDER;
hdi.fmt = subitem.nFormat&RVCF_MASK;
hdi.cxy = subitem.iWidth;
hdi.iOrder = iOrder;
hdi.lParam = (LPARAM)iColumn;
if(subitem.nFormat&RVCF_IMAGE)
{
hdi.mask |= HDI_IMAGE;
hdi.iImage = subitem.iImage;
}
if(subitem.nFormat&RVCF_TEXT)
{
hdi.mask |= HDI_TEXT;
hdi.pszText = subitem.strText.GetBuffer(0);
}
iResult = m_wndHeader.InsertItem(iHeaderItems, &hdi);
if(iResult >= 0)
{
m_iVirtualWidth += subitem.iWidth;
HDITEMEX hditemex;
hditemex.nStyle = (subitem.nFormat&RVCF_EX_MASK)>>16;
hditemex.iMinWidth = subitem.iMinWidth;
hditemex.iMaxWidth = subitem.iMaxWidth;
if(hditemex.nStyle&HDF_EX_TOOLTIP)
hditemex.strToolTip.Format(_T("Sort by %s"), subitem.strText);
m_wndHeader.SetItemEx(iResult, &hditemex);
hdi.mask = HDI_WIDTH;
m_wndHeader.GetItem(iResult, &hdi);
subitem.iWidth = hdi.cxy;
m_bColumnsReordered = TRUE;
ScrollWindow(SB_HORZ, GetScrollPos32(SB_HORZ));
}
}
catch(CMemoryException* e)
{
e->Delete();
if(iResult >= 0)
m_wndHeader.DeleteItem(iResult);
}
}
return iResult;
}
BOOL CReportCtrl::DeactivateColumn(INT iColumn)
{
ASSERT(iColumn>=0);
ASSERT(iColumn<m_arraySubItems.GetSize()); // Specify a valid column
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
INT iHeaderItems = m_arrayColumns.GetSize();
for(INT iItem=0;iItem<iHeaderItems;iItem++)
if(m_wndHeader.GetItem(iItem, &hdi))
if(hdi.lParam == iColumn)
break;
if(iItem == iHeaderItems)
return FALSE;
ASSERT(iHeaderItems>0); // At least one column must be active
BOOL bResult = m_wndHeader.DeleteItem(iItem);
m_iVirtualWidth -= hdi.cxy;
m_bColumnsReordered = TRUE;
ScrollWindow(SB_HORZ, GetScrollPos32(SB_HORZ));
return bResult;
}
BOOL CReportCtrl::IsActiveColumn(INT iColumn)
{
INT iHeaderItems = m_arrayColumns.GetSize();
HDITEM hdi;
hdi.mask = HDI_LPARAM;
for(INT iItem=0;iItem<iHeaderItems;iItem++)
if(m_wndHeader.GetItem(iItem, &hdi))
if(hdi.lParam == iColumn)
break;
if(iItem == iHeaderItems)
return FALSE;
return TRUE;
}
BOOL CReportCtrl::GetItem(LPRVITEM lprvi)
{
ASSERT(lprvi->iItem > RVI_INVALID);
ASSERT(lprvi->iItem < GetItemCount()); // Specify item
ASSERT(lprvi->iSubItem < m_arraySubItems.GetSize()); // Specify subitem
UINT nMask = lprvi->nMask;
INT iTextMax = lprvi->iTextMax;
ITEM item = GetItemStruct(lprvi->iItem, lprvi->iSubItem, nMask);
lprvi->nMask = 0;
lprvi->nPreview = item.nPreview;
if(lprvi->nPreview > 0)
lprvi->nMask |= RVIM_PREVIEW;
lprvi->iBkColor = item.iBkColor;
if(lprvi->iBkColor >= 0)
lprvi->nMask |= RVIM_BKCOLOR;
lprvi->lpszText = nMask&RVIM_TEXT ? lprvi->lpszText:NULL;
item.rdData.GetSubItem(lprvi->iSubItem, &lprvi->iImage, &lprvi->iCheck, &lprvi->iTextColor, lprvi->lpszText, &iTextMax);
if(lprvi->lpszText && iTextMax >= 0)
lprvi->nMask |= RVIM_TEXT;
if(lprvi->iImage >= 0)
lprvi->nMask |= RVIM_IMAGE;
if(lprvi->iCheck >= 0)
lprvi->nMask |= RVIM_CHECK;
if(lprvi->iTextColor >= 0)
lprvi->nMask |= RVIM_TEXTCOLOR;
lprvi->nMask |= RVIM_STATE|RVIM_LPARAM;
lprvi->nState = item.nState;
lprvi->lParam = item.lParam;
return TRUE;
}
BOOL CReportCtrl::SetItem(LPRVITEM lprvi)
{
if(m_dwStyle&RVS_OWNERDATA)
return FALSE;
// Not supported when using this style
ASSERT(!(lprvi->iItem != RVI_EDIT && m_dwStyle&RVS_OWNERDATA));
m_wndTip.Hide();
TCHAR szText[REPORTCTRL_MAX_TEXT];
RVITEM rvi;
rvi.iItem = lprvi->iItem;
rvi.iSubItem = lprvi->iSubItem;
rvi.lpszText = szText;
rvi.iTextMax = REPORTCTRL_MAX_TEXT;
rvi.nMask = RVIM_TEXT|RVIM_STATE;
VERIFY(GetItem(&rvi));
if(lprvi->nMask&RVIM_TEXT)
{
if(lprvi->lpszText != NULL)
{
_tcsncpy(rvi.lpszText, lprvi->lpszText, REPORTCTRL_MAX_TEXT-1);
rvi.lpszText[REPORTCTRL_MAX_TEXT-1] = 0;
}
else
rvi.lpszText = NULL;
}
else if(!(rvi.nMask&RVIM_TEXT))
rvi.lpszText = NULL;
if(lprvi->nMask&RVIM_TEXTCOLOR)
rvi.iTextColor = lprvi->iTextColor;
if(lprvi->nMask&RVIM_IMAGE)
rvi.iImage = lprvi->iImage;
if(lprvi->nMask&RVIM_CHECK)
rvi.iCheck = lprvi->iCheck;
if(lprvi->nMask&RVIM_BKCOLOR)
rvi.iBkColor = lprvi->iBkColor;
ASSERT(!(lprvi->iItem == RVI_EDIT && lprvi->nMask&RVIM_PREVIEW)); // Preview not supported on edit row
if(lprvi->nMask&RVIM_PREVIEW)
rvi.nPreview = lprvi->nPreview;
// Note: focus and selection cannot be changed through this function
if(lprvi->nMask&RVIM_STATE)
{
rvi.nState &= RVIS_FOCUSED|RVIS_SELECTED;
rvi.nState |= lprvi->nState&~(RVIS_FOCUSED|RVIS_SELECTED);
}
if(lprvi->nMask&RVIM_LPARAM)
rvi.lParam = lprvi->lParam;
ITEM item = GetItemStruct(rvi.iItem, rvi.iSubItem);
VERIFY(item.rdData.InsertSubItem(rvi.iSubItem, rvi.iImage, rvi.iCheck, rvi.iTextColor, rvi.lpszText));
VERIFY(item.rdData.DeleteSubItem(rvi.iSubItem+1));
item.iBkColor = rvi.iBkColor;
item.nPreview = rvi.nPreview;
item.nState = rvi.nState;
item.lParam = rvi.lParam;
SetItemStruct(rvi.iItem, item);
ScrollWindow(SB_VERT, GetScrollPos32(SB_VERT));
RedrawItems(rvi.iItem);
return TRUE;
}
INT CReportCtrl::GetItemText(INT iItem, INT iSubItem, LPTSTR lpszText, INT iLen)
{
RVITEM rvi;
rvi.nMask = RVIM_TEXT;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
rvi.lpszText = lpszText;
rvi.iTextMax = iLen;
return GetItem(&rvi) ? _tcslen(rvi.lpszText):0;
}
CString CReportCtrl::GetItemText(INT iItem, INT iSubItem)
{
CString str;
TCHAR szText[REPORTCTRL_MAX_TEXT];
if(GetItemText(iItem, iSubItem, szText, REPORTCTRL_MAX_TEXT))
str = szText;
return str;
}
BOOL CReportCtrl::SetItemText(INT iItem, INT iSubItem, LPCTSTR lpszText)
{
RVITEM rvi;
rvi.nMask = RVIM_TEXT;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
rvi.lpszText = (LPTSTR)lpszText;
return SetItem(&rvi);
}
INT CReportCtrl::GetItemImage(INT iItem, INT iSubItem)
{
RVITEM rvi;
rvi.nMask = RVIM_IMAGE;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
return GetItem(&rvi) ? rvi.iImage:-1;
}
BOOL CReportCtrl::SetItemImage(INT iItem, INT iSubItem, INT iImage)
{
RVITEM rvi;
rvi.nMask = RVIM_IMAGE;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
rvi.iImage = iImage;
return SetItem(&rvi);
}
INT CReportCtrl::GetItemCheck(INT iItem, INT iSubItem)
{
RVITEM rvi;
rvi.nMask = RVIM_CHECK;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
return GetItem(&rvi) ? rvi.iCheck:-1;
}
BOOL CReportCtrl::SetItemCheck(INT iItem, INT iSubItem, INT iCheck)
{
RVITEM rvi;
rvi.nMask = RVIM_CHECK;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
rvi.iCheck = iCheck;
return SetItem(&rvi);
}
DWORD CReportCtrl::GetItemData(INT iItem)
{
RVITEM rvi;
rvi.nMask = RVIM_LPARAM;
rvi.iItem = iItem;
return GetItem(&rvi) ? rvi.lParam:0;
}
BOOL CReportCtrl::SetItemData(INT iItem, DWORD dwData)
{
RVITEM rvi;
rvi.nMask = RVIM_LPARAM;
rvi.iItem = iItem;
rvi.lParam = dwData;
return SetItem(&rvi);
}
BOOL CReportCtrl::GetItemRect(INT iItem, INT iSubItem, LPRECT lpRect, UINT nCode)
{
INT iRow = GetRowFromItem(iItem);
INT iColumn = GetColumnFromSubItem(iSubItem);
// Select a visible sub-item
if(iColumn == -1 && nCode != RVIR_BOUNDS)
return FALSE;
INT iFirst, iLast;
if(iRow != RVI_EDIT)
{
iFirst = GetScrollPos32(SB_VERT);
GetVisibleRows(TRUE, &iFirst, &iLast);
// Select a visible item
if(iFirst > iRow || iLast < iRow)
return FALSE;
*lpRect = m_rectReport;
for(;iFirst<iRow;iFirst++)
lpRect->top += m_iDefaultHeight + GetItemStruct(GetItemFromRow(iFirst), -1).nPreview;
}
else
*lpRect = m_rectEdit;
lpRect->bottom = lpRect->top + m_iDefaultHeight;
INT iPos = GetScrollPos32(SB_HORZ);
lpRect->left -= iPos;
lpRect->right -= iPos;
if(iSubItem == -1)
return TRUE;
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
for(iFirst=0;iFirst<iColumn;iFirst++)
{
m_wndHeader.GetItem(m_arrayColumns[iFirst], &hdi);
lpRect->left += hdi.cxy;
}
m_wndHeader.GetItem(m_arrayColumns[iColumn], &hdi);
lpRect->right = lpRect->left + hdi.cxy;
RVITEM rvi;
rvi.iItem = iItem;
rvi.iSubItem = iSubItem;
GetItem(&rvi);
switch(nCode)
{
case RVIR_BOUNDS:
return TRUE;
case RVIR_IMAGE:
if(!(rvi.nMask&RVIM_IMAGE))
return FALSE;
lpRect->left += m_iSpacing;
if(lpRect->left + m_sizeImage.cx > lpRect->right - m_iSpacing)
return FALSE;
lpRect->right = lpRect->left + m_sizeImage.cx;
return TRUE;
case RVIR_CHECK:
if(!(rvi.nMask&RVIM_CHECK))
return FALSE;
lpRect->left += m_iSpacing + (rvi.nMask&RVIM_IMAGE ? m_sizeImage.cx+m_iSpacing:0);
if(lpRect->left + m_sizeCheck.cx > lpRect->right - m_iSpacing)
return FALSE;
lpRect->right = lpRect->left + m_sizeCheck.cx;
return TRUE;
case RVIR_TEXT:
lpRect->left += m_iSpacing +
(rvi.nMask&RVIM_IMAGE ? m_sizeImage.cx+m_iSpacing:0) +
(rvi.nMask&RVIM_CHECK ? m_sizeCheck.cx+m_iSpacing:0);
if(lpRect->left > lpRect->right - m_iSpacing)
return FALSE;
lpRect->right -= m_iSpacing;
return TRUE;
default:
return FALSE;
}
}
void CReportCtrl::SetItemHeight(INT iHeight)
{
m_iDefaultHeight = iHeight;
CRect rect;
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
}
INT CReportCtrl::GetVisibleCount(BOOL bUnobstructed)
{
return GetVisibleRows(bUnobstructed);
}
INT CReportCtrl::GetItemCount()
{
return m_dwStyle&RVS_OWNERDATA ? m_iVirtualHeight:m_arrayItems.GetSize();
}
void CReportCtrl::SetItemCount(INT iCount)
{
ASSERT(m_dwStyle&RVS_OWNERDATA); // Only supported when using RVS_OWNERDATA style
ASSERT(iCount >= 0);
m_iVirtualHeight = iCount;
m_iFocusRow = m_iFocusRow>=m_iVirtualHeight ? m_iVirtualHeight-1:m_iFocusRow;
RedrawItems(RVI_EDIT, RVI_LAST);
ScrollWindow(SB_VERT, GetScrollPos32(SB_VERT));
}
INT CReportCtrl::GetFirstSelectedItem()
{
return GetNextSelectedItem(RVI_INVALID);
}
INT CReportCtrl::GetNextSelectedItem(INT iItem)
{
RVITEM rvi;
rvi.nMask = RVIM_STATE;
INT iItems = GetItemCount();
for(rvi.iItem=iItem+1;rvi.iItem<iItems;rvi.iItem++)
if(GetItem(&rvi) && rvi.nState&RVIS_SELECTED)
return rvi.iItem;
return RVI_INVALID;
}
void CReportCtrl::ClearSelection()
{
SelectRows(m_iFocusRow, m_iFocusRow, FALSE, FALSE, FALSE, FALSE);
}
void CReportCtrl::SetSelection(INT iItem, BOOL bKeepSelection)
{
ASSERT(iItem > RVI_INVALID && iItem < GetItemCount());
INT iRow = GetRowFromItem(iItem);
SelectRows(iRow, iRow, TRUE, bKeepSelection, FALSE, FALSE);
}
void CReportCtrl::SetSelection(LPINT lpiItems, INT iCount, BOOL bKeepSelection)
{
INT i, iRow;
for(i=0;i<iCount;i++)
{
ASSERT(lpiItems[i] > RVI_INVALID && lpiItems[i] < GetItemCount());
iRow = GetRowFromItem(lpiItems[i]);
SelectRows(iRow, iRow, TRUE, bKeepSelection|(i != 0), FALSE, FALSE);
}
}
BOOL CReportCtrl::SetImageList(CImageList* pImageList)
{
m_pImageList = pImageList;
m_wndHeader.SetImageList(pImageList);
IMAGEINFO info;
if(pImageList->GetImageInfo(0, &info))
{
m_sizeImage.cx = info.rcImage.right - info.rcImage.left;
m_sizeImage.cy = info.rcImage.bottom - info.rcImage.top;
m_iDefaultHeight = m_sizeImage.cy>m_iDefaultHeight ? m_sizeImage.cy:m_iDefaultHeight;
Invalidate();
return TRUE;
}
else
return FALSE;
}
CImageList* CReportCtrl::GetImageList(void)
{
return m_pImageList;
}
BOOL CReportCtrl::SetBkImage(UINT nIDResource)
{
return SetBkImage( (LPCTSTR)nIDResource );
}
BOOL CReportCtrl::SetBkImage(LPCTSTR lpszResourceName)
{
if(m_bitmap.m_hObject != NULL)
m_bitmap.DeleteObject();
HBITMAP hBitmap = (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION );
Invalidate();
if(hBitmap == NULL)
return FALSE;
m_bitmap.Attach(hBitmap);
BITMAP bitmap;
m_bitmap.GetBitmap(&bitmap);
m_sizeBitmap.cx = bitmap.bmWidth;
m_sizeBitmap.cy = bitmap.bmHeight;
CreatePalette();
return TRUE;
}
BOOL CReportCtrl::HasFocus()
{
return m_bFocus;
}
CFlatHeaderCtrl* CReportCtrl::GetHeaderCtrl()
{
return &m_wndHeader;
}
BOOL CReportCtrl::SetReportColumnListCtrl(CReportColumnListCtrl* lprclc)
{
if(m_lprclc != NULL)
{
m_wndHeader.ModifyProperty(FH_PROPERTY_DROPTARGET, NULL);
m_lprclc->SetReportCtrl(NULL);
}
m_lprclc = lprclc;
if(m_lprclc != NULL)
{
m_wndHeader.ModifyProperty(FH_PROPERTY_DROPTARGET, (LPARAM)m_lprclc->m_hWnd);
m_lprclc->SetReportCtrl(this);
}
return TRUE;
}
CReportColumnListCtrl* CReportCtrl::GetReportColumnListCtrl()
{
return m_lprclc;
}
BOOL CReportCtrl::SetSortCallback(LPFNRVCOMPARE lpfnrvc)
{
m_lpfnrvc = lpfnrvc;
return TRUE;
}
LPFNRVCOMPARE CReportCtrl::GetSortCallback()
{
return m_lpfnrvc;
}
//**********************************************
//************************************************
//************************************************
//create a profile string for saving
BOOL CReportCtrl::WriteProfile(CString* strpProfile)
{
CString str, strProfile;
INT i;
INT iSubItems = m_arraySubItems.GetSize();
INT iColumns = m_arrayColumns.GetSize();
strProfile.Format(_T("(%d,%d)"), iSubItems, iColumns);
for(i=0;i<iSubItems;i++)
{
str.Format(" %d", m_arraySubItems[i].iWidth);
strProfile += str;
}
for(i=0;i<iColumns;i++)
{
HDITEM hdi;
hdi.mask = HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[i], &hdi);
str.Format(" %d", hdi.lParam);
strProfile += str;
}
*strpProfile=strProfile;
return TRUE;
}
//SEt the control properties based on passed profile string
BOOL CReportCtrl::GetProfile(CString* strpProfile)
{
CString str, strProfile;
strProfile=*strpProfile;
if(strProfile.IsEmpty())
return FALSE;
LPTSTR lpsz = strProfile.GetBuffer(0);
INT i;
INT iSubItems;
INT iColumns;
iSubItems = _tcstol(++lpsz, &lpsz, 10);
iColumns = _tcstol(++lpsz, &lpsz, 10);
if(iSubItems != m_arraySubItems.GetSize())
return FALSE;
for(i=0;i<iSubItems;i++)
m_arraySubItems[i].iWidth = _tcstol(++lpsz, &lpsz, 10);
for(i=0;i<iColumns;i++)
ActivateColumn(_tcstol(++lpsz, &lpsz, 10), i);
return TRUE;
}
//********************************************************
//********************************************************
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl operations
BOOL CReportCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
DWORD dwStyle = GetStyle();
ASSERT(!(dwRemove&RVS_OWNERDATA)); // Can't dynamically remove this style
ASSERT(!(dwAdd&RVS_OWNERDATA)); // Can't dynamically add this style
if(CWnd::ModifyStyle(dwRemove, dwAdd, nFlags))
{
if(!(dwStyle&RVS_SHOWHGRID) && dwAdd&RVS_SHOWHGRID)
m_iDefaultHeight++;
if(dwStyle&RVS_SHOWHGRID && dwRemove&RVS_SHOWHGRID)
m_iDefaultHeight--;
if(!(dwStyle&RVS_FOCUSSUBITEMS) && dwAdd&RVS_FOCUSSUBITEMS)
m_iFocusColumn = 0;
if(dwStyle&RVS_FOCUSSUBITEMS && dwRemove&RVS_FOCUSSUBITEMS)
m_iFocusColumn = -1;
m_dwStyle = GetStyle();
CRect rect;
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
return TRUE;
}
return FALSE;
}
INT CReportCtrl::DefineColumn(INT iColumn, LPRVCOLUMN lprvc, BOOL bUpdateList)
{
INT i;
INT iColumns = m_arraySubItems.GetSize();
ASSERT(iColumn <= iColumns);
ASSERT(lprvc->lpszText != NULL); // Must supply (descriptive) text for subitem selector
ASSERT(_tcslen(lprvc->lpszText) < FLATHEADER_TEXT_MAX);
try
{
SUBITEM subitem;
subitem.nFormat = lprvc->nFormat;
subitem.iWidth = lprvc->iWidth<0 ? m_iDefaultWidth:lprvc->iWidth;
subitem.iMinWidth = lprvc->iMinWidth;
subitem.iMaxWidth = lprvc->iMaxWidth;
subitem.iImage = lprvc->nFormat&RVCF_IMAGE ? lprvc->iImage:0;
subitem.strText = lprvc->lpszText;
m_arraySubItems.InsertAt(iColumn, subitem);
HDITEM hdi;
hdi.mask = HDI_LPARAM;
INT iHeaderItems = m_arrayColumns.GetSize();
for(i=0;i<iHeaderItems;i++)
if(m_wndHeader.GetItem(i, &hdi))
if(hdi.lParam >= iColumn)
{
hdi.lParam++;
m_wndHeader.SetItem(i, &hdi);
}
VERIFY(m_itemEdit.rdData.InsertSubItem(iColumn, -1, -1, -1, NULL));
if(!(m_dwStyle&RVS_OWNERDATA))
{
INT iItems = GetItemCount();
for(i=0;i<iItems;i++)
VERIFY(m_arrayItems[i].rdData.InsertSubItem(iColumn, -1, -1, -1, NULL));
}
if(bUpdateList && m_lprclc != NULL)
m_lprclc->UpdateList();
return iColumn;
}
catch(CMemoryException* e)
{
e->Delete();
return -1;
}
}
BOOL CReportCtrl::UndefineColumn(INT iColumn)
{
ASSERT(iColumn >= 0);
ASSERT(iColumn < m_arraySubItems.GetSize()); // Specify a valid column
VERIFY(!DeactivateColumn(iColumn));
m_arraySubItems.RemoveAt(iColumn);
HDITEM hdi;
hdi.mask = HDI_LPARAM;
INT i;
INT iHeaderItems = m_arrayColumns.GetSize();
for(i=0;i<iHeaderItems;i++)
if(m_wndHeader.GetItem(i, &hdi))
if(hdi.lParam > iColumn)
{
hdi.lParam--;
m_wndHeader.SetItem(i, &hdi);
}
VERIFY(m_itemEdit.rdData.DeleteSubItem(iColumn));
if(!(m_dwStyle&RVS_OWNERDATA))
{
INT iItems = GetItemCount();
for(i=0;i<iItems;i++)
VERIFY(m_arrayItems[i].rdData.DeleteSubItem(iColumn));
}
if(m_lprclc != NULL)
m_lprclc->UpdateList();
return TRUE;
}
INT CReportCtrl::InsertItem(INT iItem, LPTSTR lpszText, INT iImage, INT iCheck, INT iTextColor)
{
RVITEM rvi;
rvi.nMask = RVIM_TEXT;
rvi.iItem = iItem;
rvi.iSubItem = 0;
rvi.lpszText = lpszText;
rvi.iTextColor = iTextColor;
rvi.iImage = iImage;
rvi.iCheck = iCheck;
if(iTextColor >= 0)
rvi.nMask |= RVIM_TEXTCOLOR;
if(iImage >= 0)
rvi.nMask |= RVIM_IMAGE;
if(iCheck >= 0)
rvi.nMask |= RVIM_CHECK;
return InsertItem(&rvi);
}
INT CReportCtrl::InsertItem(LPRVITEM lprvi)
{
if(m_dwStyle&RVS_OWNERDATA) // Use set SetItemCount() when using this style
return RVI_INVALID;
ASSERT(lprvi->iItem >= 0); // Use SetItem to set Edit row item
ASSERT(lprvi->iItem <= GetItemCount());
ASSERT(lprvi->iSubItem < m_arraySubItems.GetSize());
BOOL bInserted = FALSE;
try
{
ITEM item;
item.rdData.New(m_arraySubItems.GetSize());
m_arrayItems.InsertAt(lprvi->iItem, item); bInserted = TRUE;
m_arrayRows.InsertAt(lprvi->iItem, INT_MIN);
INT iItems = m_arrayRows.GetSize();
for(INT i=0;i<iItems;i++)
if(m_arrayRows[i]>=lprvi->iItem)
m_arrayRows[i]++;
m_arrayRows[lprvi->iItem] = lprvi->iItem;
m_iVirtualHeight++;
VERIFY(SetItem(lprvi));
ScrollWindow(SB_VERT, GetScrollPos32(SB_VERT));
return lprvi->iItem;
}
catch(CMemoryException* e)
{
if(bInserted)
m_arrayItems.RemoveAt(lprvi->iItem);
e->Delete();
return RVI_INVALID;
}
}
BOOL CReportCtrl::DeleteItem(INT iItem)
{
ASSERT(iItem <= GetItemCount());
if(m_dwStyle&RVS_OWNERDATA) // Use set SetItemCount() when using this style
return FALSE;
RVITEM rvi;
rvi.nMask = RVIM_LPARAM;
rvi.iItem = iItem;
GetItem(&rvi);
Notify(RVN_ITEMDELETED, iItem, 0, 0, rvi.lParam);
m_arrayItems.RemoveAt(iItem);
INT iRows = m_arrayRows.GetSize();
for(INT i=0;i<iRows;i++)
{
if(m_arrayRows[i] == iItem)
m_arrayRows.RemoveAt(i);
if(m_arrayRows[i] > iItem)
m_arrayRows[i]--;
}
m_iVirtualHeight--;
m_iFocusRow = m_iFocusRow >= m_iVirtualHeight ? m_iVirtualHeight-1 : m_iFocusRow;
INT iItems = GetItemCount();
INT iFirst = GetScrollPos32(SB_VERT), iLast;
GetVisibleRows(TRUE, &iFirst, &iLast);
if(iItem<=iFirst || iLast>=iItems-1)
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
ScrollWindow(SB_VERT, iFirst);
return TRUE;
}
BOOL CReportCtrl::DeleteAllItems()
{
if(m_dwStyle&RVS_OWNERDATA) // Use set SetItemCount() when using this style
return FALSE;
RVITEM rvi;
for (int iItem = 0; iItem < GetItemCount(); iItem++)
{
rvi.nMask = RVIM_LPARAM;
rvi.iItem = iItem;
GetItem(&rvi);
Notify(RVN_ITEMDELETED, iItem, 0, 0, rvi.lParam);
}
m_arrayRows.RemoveAll();
m_arrayItems.RemoveAll();
m_iVirtualHeight = 0;
m_iFocusRow = RVI_INVALID;
ScrollWindow(SB_VERT, 0);
return TRUE;
}
void CReportCtrl::RedrawItems(INT iFirst, INT iLast)
{
// TODO: Optimize to redraw indivual rows
// taking into account that the row height
// may have changed. Redrawing everything
// will work as well :)
if(iFirst == RVI_EDIT)
InvalidateRect(m_rectEdit);
InvalidateRect(m_rectReport);
}
BOOL CReportCtrl::EnsureVisible(INT iItem, BOOL bUnobstructed)
{
INT iFirst = GetScrollPos32(SB_VERT), iLast;
INT iRow = GetRowFromItem(iItem);
if(iRow < 0)
return FALSE;
GetVisibleRows(bUnobstructed, &iFirst, &iLast);
if(iRow<iFirst)
ScrollWindow(SB_VERT, iRow);
if(iRow>iLast)
{
iLast = iRow;
GetVisibleRows(bUnobstructed, &iFirst, &iLast, TRUE);
ScrollWindow(SB_VERT, iFirst);
}
return TRUE;
}
INT CReportCtrl::InsertColor(INT iIndex, COLORREF crColor)
{
try
{
m_arrayColors.InsertAt(iIndex, crColor);
if(CreatePalette())
return iIndex;
return -1;
}
catch(CMemoryException* e)
{
e->Delete();
return -1;
}
}
BOOL CReportCtrl::DeleteColor(INT iIndex)
{
if(iIndex >= m_arrayColors.GetSize())
return FALSE;
m_arrayColors.RemoveAt(iIndex);
CreatePalette();
return TRUE;
}
INT CReportCtrl::HitTest(LPRVHITTESTINFO lprvhti)
{
ASSERT(lprvhti);
lprvhti->nFlags = 0;
lprvhti->iItem = RVI_INVALID;
lprvhti->iSubItem = -1;
lprvhti->iRow = RVI_INVALID;
lprvhti->iColumn = -1;
CRect rectItem = m_rectEdit;
rectItem.bottom -= GetSystemMetrics(SM_CYFIXEDFRAME)*2;
if(
rectItem.PtInRect(lprvhti->point) ||
m_rectReport.PtInRect(lprvhti->point)
) {
INT iHPos = GetScrollPos32(SB_HORZ);
INT iFirst = GetScrollPos32(SB_VERT), iLast;
BOOL bCheckItem = FALSE;
if(rectItem.PtInRect(lprvhti->point))
{
lprvhti->iItem = RVI_EDIT;
lprvhti->nFlags |= RVHT_ONITEMEDIT;
bCheckItem = TRUE;
}
else if(!bCheckItem && GetVisibleRows(FALSE, &iFirst, &iLast))
{
ITEM item;
rectItem.SetRect(
m_rectReport.left-iHPos, m_rectReport.top,
m_rectReport.left-iHPos+m_iVirtualWidth, m_rectReport.top
);
for(;iFirst<=iLast;iFirst++)
{
GetItemFromRow(iFirst, item);
rectItem.bottom += m_iDefaultHeight+item.nPreview;
if(rectItem.PtInRect(lprvhti->point))
break;
rectItem.top = rectItem.bottom;
}
if(iFirst<=iLast)
{
lprvhti->iItem = GetItemFromRow(iFirst);
lprvhti->iRow = iFirst;
if(item.nPreview)
{
CRect rectPreview(rectItem);
rectPreview.top += m_iDefaultHeight;
if(rectPreview.PtInRect(lprvhti->point))
{
lprvhti->nFlags |= RVHT_ONITEMPREVIEW;
return lprvhti->iItem;
}
}
bCheckItem = TRUE;
}
}
if(bCheckItem)
{
INT iHeaderItem;
INT iHeaderItems = m_arrayColumns.GetSize();
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
rectItem.right = rectItem.left;
for(iHeaderItem=0;iHeaderItem<iHeaderItems;iHeaderItem++)
{
m_wndHeader.GetItem(m_arrayColumns[iHeaderItem], &hdi);
rectItem.right += hdi.cxy;
if(rectItem.PtInRect(lprvhti->point))
break;
rectItem.left = rectItem.right;
}
lprvhti->iSubItem = hdi.lParam;
lprvhti->iColumn = iHeaderItem;
if(iHeaderItem<iHeaderItems)
{
RVITEM rvi;
rvi.iItem = iFirst;
rvi.iSubItem = lprvhti->iSubItem;
GetItem(&rvi);
lprvhti->rect = rectItem;
lprvhti->rect.bottom = rectItem.top + m_iDefaultHeight;
rectItem.right = rectItem.left+m_iSpacing;
if(rvi.nMask&RVIM_IMAGE)
{
rectItem.right += m_sizeImage.cx+m_iSpacing;
if(lprvhti->point.x < rectItem.right)
{
lprvhti->nFlags |= RVHT_ONITEMIMAGE;
return lprvhti->iItem;
}
}
if(rvi.nMask&RVIM_CHECK)
{
rectItem.right += m_sizeCheck.cx+m_iSpacing;
if(lprvhti->point.x < rectItem.right)
{
lprvhti->nFlags |= RVHT_ONITEMCHECK;
return lprvhti->iItem;
}
}
lprvhti->nFlags |= RVHT_ONITEMTEXT;
}
else
lprvhti->nFlags = RVHT_NOWHERE;
}
else
lprvhti->nFlags = RVHT_NOWHERE;
}
else
{
lprvhti->nFlags |= lprvhti->point.y<m_rectReport.top ? RVHT_ABOVE:0;
lprvhti->nFlags |= lprvhti->point.y>m_rectReport.bottom ? RVHT_BELOW:0;
lprvhti->nFlags |= lprvhti->point.x<m_rectReport.left ? RVHT_TOLEFT:0;
lprvhti->nFlags |= lprvhti->point.x>m_rectReport.right ? RVHT_TORIGHT:0;
}
return lprvhti->iItem;
}
BOOL CReportCtrl::SortItems(INT iColumn, BOOL bAscending)
{
INT iHeaderColumn = FindColumnInHeader(iColumn);
if(iHeaderColumn < 0 || m_dwStyle&RVS_OWNERDATA)
return FALSE; // Can't sort on columns that are not active
// Can't sort if data is managed by owner
INT iFocusItem = GetItemFromRow(m_iFocusRow);
INT iRows = m_arrayRows.GetSize();
if(iRows>1)
{
for(INT i=0;i<iRows-1;i++)
{
for(INT j=i+1;j<iRows;j++)
{
INT iSort = CompareItems(iColumn, m_arrayRows[i], m_arrayRows[j]);
if((bAscending && iSort>0) ||
(!bAscending && iSort<0))
{
INT iItem = m_arrayRows[i];
m_arrayRows[i] = m_arrayRows[j];
m_arrayRows[j] = iItem;
}
}
}
}
m_wndHeader.SetSortColumn(m_arrayColumns[iHeaderColumn], bAscending);
if(iFocusItem>=0)
{
m_iFocusRow = GetRowFromItem(iFocusItem);
INT iFirst = m_iFocusRow, iLast;
GetVisibleRows(TRUE, &iFirst, &iLast);
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
ScrollWindow(SB_VERT, iFirst);
}
Invalidate();
return TRUE;
}
BOOL CReportCtrl::SortAllColumns(BOOL bAscending /*=TRUE*/)
{
if(m_dwStyle&RVS_OWNERDATA)
return FALSE; // Can't sort if data is managed by owner
// Save current position
INT iFocusItem = GetItemFromRow(m_iFocusRow);
// Scan all the rows.
INT iRows = m_arrayRows.GetSize();
if(iRows>1)
{
for(INT i=0;i<iRows-1;i++)
{
for(INT j=i+1;j<iRows;j++)
{
// Scan the visible columns and extract each internal column number
INT iColumns = m_arrayColumns.GetSize();
for(INT k=0;k<iColumns;k++)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[k], &hdi);
INT iInternalColumn = hdi.lParam;
INT iSort = CompareItems(iInternalColumn, m_arrayRows[i], m_arrayRows[j]);
if (iSort == 0)
continue; // ie try next column
if((bAscending && iSort>0) ||
(!bAscending && iSort<0))
{
INT iItem = m_arrayRows[i];
m_arrayRows[i] = m_arrayRows[j];
m_arrayRows[j] = iItem;
}
break;
}
}
}
}
if(iFocusItem>=0)
{
m_iFocusRow = GetRowFromItem(iFocusItem);
INT iFirst = m_iFocusRow, iLast;
GetVisibleRows(TRUE, &iFirst, &iLast);
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
ScrollWindow(SB_VERT, iFirst);
}
Invalidate();
return TRUE;
}
INT CReportCtrl::CompareItems(INT iColumn, INT iItem1, INT iItem2)
{
ASSERT(!(m_dwStyle&RVS_OWNERDATA)); // Can't sort if data is managed by owner
if(m_lpfnrvc == NULL)
{
RVITEM rvi1, rvi2;
TCHAR szText1[REPORTCTRL_MAX_TEXT], szText2[REPORTCTRL_MAX_TEXT];
rvi1.nMask = RVIM_TEXT;
rvi1.iItem = iItem1;
rvi1.iSubItem = iColumn;
rvi1.lpszText = szText1;
rvi1.iTextMax = REPORTCTRL_MAX_TEXT;
VERIFY(GetItem(&rvi1));
rvi2.nMask = RVIM_TEXT;
rvi2.iItem = iItem2;
rvi2.iSubItem = iColumn;
rvi2.lpszText = szText2;
rvi2.iTextMax = REPORTCTRL_MAX_TEXT;
VERIFY(GetItem(&rvi2));
if((!_tcslen(szText1)) && (!_tcslen(szText2)))
{
if(rvi1.iImage < rvi2.iImage)
return -1;
else if(rvi1.iImage > rvi2.iImage)
return 1;
else
return 0;
}
else
return _tcscmp(szText1, szText2);
}
else
return m_lpfnrvc(iColumn, iItem1, iItem2);
}
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl implementation
void CReportCtrl::GetSysColors()
{
m_crBackground = GetSysColor(COLOR_WINDOW);
m_crBkSelected = GetSysColor(COLOR_HIGHLIGHT);
m_crBkSelectedNoFocus = GetSysColor(COLOR_BTNFACE);
m_crText = GetSysColor(COLOR_WINDOWTEXT);
m_crTextSelected = GetSysColor(COLOR_HIGHLIGHTTEXT);
m_crTextSelectedNoFocus = GetSysColor(COLOR_WINDOWTEXT);
m_crGrid = GetSysColor(COLOR_BTNFACE);
m_cr3DFace = GetSysColor(COLOR_3DFACE);
m_cr3DHiLight = GetSysColor(COLOR_3DHILIGHT);
m_cr3DDkShadow = GetSysColor(COLOR_3DDKSHADOW);
}
UINT CReportCtrl::GetMouseScrollLines()
{
UINT nScrollLines = 3; // Reasonable default
HKEY hKey;
if(RegOpenKeyEx(
HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS
) {
TCHAR szData[128];
DWORD dwKeyDataType;
DWORD dwDataBufSize = sizeof(szData);
if(RegQueryValueEx(
hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
(LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS
)
nScrollLines = _tcstoul(szData, NULL, 10);
RegCloseKey(hKey);
}
return nScrollLines;
}
BOOL CReportCtrl::CreatePalette()
{
if(m_palette.m_hObject)
m_palette.DeleteObject();
INT iUserColors = m_arrayColors.GetSize();
INT iBitmapColors = 0;
DIBSECTION ds;
BITMAPINFOHEADER &bmInfo = ds.dsBmih;
if( (HBITMAP)m_bitmap != NULL )
{
m_bitmap.GetObject( sizeof(ds), &ds );
iBitmapColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount;
}
INT iColors = iUserColors + iBitmapColors;
if( !iColors )
return FALSE;
CClientDC cdc(NULL);
if( iColors <= 256 )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * iColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = iColors;
INT i;
for( i=0;i<iUserColors;i++ )
{
pLP->palPalEntry[i].peRed = GetRValue(m_arrayColors[i]);
pLP->palPalEntry[i].peGreen = GetGValue(m_arrayColors[i]);
pLP->palPalEntry[i].peBlue = GetBValue(m_arrayColors[i]);
pLP->palPalEntry[i].peFlags = 0;
}
if( iBitmapColors > 0 )
{
// Create the palette
RGBQUAD *pRGB = new RGBQUAD[iBitmapColors];
CDC dc;
dc.CreateCompatibleDC(&cdc);
dc.SelectObject( &m_bitmap );
::GetDIBColorTable( dc, 0, iColors, pRGB );
for( INT i=0;i<iBitmapColors;i++ )
{
pLP->palPalEntry[iUserColors+i].peRed = pRGB[i].rgbRed;
pLP->palPalEntry[iUserColors+i].peGreen = pRGB[i].rgbGreen;
pLP->palPalEntry[iUserColors+i].peBlue = pRGB[i].rgbBlue;
pLP->palPalEntry[iUserColors+i].peFlags = 0;
}
delete[] pRGB;
}
m_palette.CreatePalette( pLP );
delete[] pLP;
}
else
m_palette.CreateHalftonePalette( &cdc );
return TRUE;
}
BOOL CReportCtrl::Notify(UINT nCode, INT iItem, INT iSubItem, UINT nState, LPARAM lParam)
{
NMREPORTVIEW nmrv;
nmrv.hdr.hwndFrom = GetSafeHwnd();
nmrv.hdr.idFrom = GetDlgCtrlID();
nmrv.hdr.code = nCode;
nmrv.iItem = iItem;
nmrv.iSubItem = iSubItem;
nmrv.nState = nState;
nmrv.lParam = lParam;
CWnd* pWnd = GetParent();
if(pWnd)
return pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrv);
return FALSE;
}
BOOL CReportCtrl::Notify(UINT nCode, UINT nKeys, LPRVHITTESTINFO lprvhti)
{
NMREPORTVIEW nmrv;
nmrv.hdr.hwndFrom = GetSafeHwnd();
nmrv.hdr.idFrom = GetDlgCtrlID();
nmrv.hdr.code = nCode;
nmrv.nKeys = nKeys;
nmrv.point = lprvhti->point;
nmrv.nFlags = lprvhti->nFlags;
nmrv.iItem = lprvhti->iItem;
nmrv.iSubItem = lprvhti->iSubItem;
if(lprvhti->iItem >= 0 && (!(m_dwStyle&RVS_OWNERDATA)))
nmrv.lParam = GetItemStruct(lprvhti->iItem, -1).lParam;
CWnd* pWnd = GetParent();
if(pWnd)
return pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrv);
return FALSE;
}
void CReportCtrl::Layout(INT cx, INT cy)
{
HDLAYOUT hdl;
WINDOWPOS wpos;
hdl.prc = &m_rectReport;
hdl.pwpos = &wpos;
m_rectReport.SetRect(0, 0, cx, cy);
if(IsWindow(m_wndHeader.GetSafeHwnd()))
{
m_wndTip.Hide();
if(!(m_dwStyle&RVS_NOHEADER))
{
VERIFY(m_wndHeader.SendMessage(HDM_LAYOUT, 0, (LPARAM)&hdl));
m_rectHeader.SetRect(wpos.x, wpos.y, wpos.x+wpos.cx, wpos.y+wpos.cy);
}
else
m_rectHeader.SetRect(0, 0, cx, 0);
m_rectTop = m_rectHeader;
if(m_dwStyle&RVS_SHOWEDITROW)
{
UINT nFrameHeight = GetSystemMetrics(SM_CYFIXEDFRAME);
m_rectTop.bottom += m_iDefaultHeight + 2*nFrameHeight;
m_rectReport.top += m_iDefaultHeight + 2*nFrameHeight;
m_rectEdit = m_rectTop;
m_rectEdit.top = m_rectHeader.bottom;
}
else
m_rectEdit.SetRectEmpty();
ScrollWindow(SB_HORZ, GetScrollPos32(SB_HORZ));
ScrollWindow(SB_VERT, GetScrollPos32(SB_VERT));
}
}
CReportCtrl::ITEM& CReportCtrl::GetItemStruct(INT iItem, INT iSubItem, UINT nMask)
{
if(m_dwStyle&RVS_OWNERDATA)
{
INT iSubItems = m_arraySubItems.GetSize();
ITEM item;
item.rdData.New(iSubItems);
CWnd* pWnd = GetParent();
if(pWnd)
{
NMRVITEMCALLBACK nmrvic;
nmrvic.hdr.hwndFrom = GetSafeHwnd();
nmrvic.hdr.idFrom = GetDlgCtrlID();
nmrvic.hdr.code = RVN_ITEMCALLBACK;
nmrvic.item.iItem = iItem;
nmrvic.item.iSubItem = iSubItem;
nmrvic.item.nMask = nMask;
TCHAR szText[REPORTCTRL_MAX_TEXT+1];
memset(szText, 0, sizeof(szText));
if(iSubItem >= 0)
{
nmrvic.item.nMask |= RVIM_TEXT;
nmrvic.item.lpszText = szText;
nmrvic.item.iTextMax = REPORTCTRL_MAX_TEXT;
}
pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvic);
INT iColor = nmrvic.item.nMask&RVIM_TEXTCOLOR ? nmrvic.item.iTextColor:-1;
INT iImage = nmrvic.item.nMask&RVIM_IMAGE ? nmrvic.item.iImage:-1;
INT iCheck = nmrvic.item.nMask&RVIM_CHECK ? nmrvic.item.iCheck:-1;
if(iSubItem >= 0)
item.rdData.SetSubItem(iSubItem, iImage, iCheck, iColor, szText);
item.iBkColor = nmrvic.item.nMask&RVIM_BKCOLOR ? nmrvic.item.iBkColor:-1;
item.nPreview = nmrvic.item.nMask&RVIM_PREVIEW ? nmrvic.item.nPreview:0;
item.nState = nmrvic.item.nMask&RVIM_STATE ? nmrvic.item.nState:0;
}
m_itemCache = item;
return m_itemCache;
}
return iItem == RVI_EDIT ? m_itemEdit:m_arrayItems[iItem];
}
void CReportCtrl::SetItemStruct(INT iItem, ITEM& item)
{
if(m_dwStyle&RVS_OWNERDATA)
return;
if(iItem == RVI_EDIT)
m_itemEdit = item;
else
m_arrayItems[iItem] = item;
}
INT CReportCtrl::GetItemFromRow(INT iRow)
{
if(m_dwStyle&RVS_OWNERDATA)
return iRow;
if(iRow == RVI_INVALID)
return RVI_INVALID;
return iRow == RVI_EDIT ? RVI_EDIT:m_arrayRows[iRow];
}
INT CReportCtrl::GetItemFromRow(INT iRow, ITEM& item)
{
if(m_dwStyle&RVS_OWNERDATA)
return iRow;
if(iRow == RVI_INVALID)
return RVI_INVALID;
INT iItem = GetItemFromRow(iRow);
item = GetItemStruct(iItem, -1);
return iItem;
}
INT CReportCtrl::GetRowFromItem(INT iItem)
{
if(iItem == RVI_EDIT || m_dwStyle&RVS_OWNERDATA)
return iItem;
INT iRows = m_arrayRows.GetSize();
for(INT iRow=0;iRow<iRows;iRow++)
if(m_arrayRows[iRow] == iItem)
return iRow;
return RVI_INVALID;
}
INT CReportCtrl::GetSubItemFromColumn(INT iColumn)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[iColumn], &hdi);
return hdi.lParam;
}
INT CReportCtrl::GetColumnFromSubItem(INT iSubItem)
{
if(iSubItem == -1)
return -1;
INT iColumn, iColumns = m_arrayColumns.GetSize();
for(iColumn=0;iColumn<iColumns;iColumn++)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[iColumn], &hdi);
if(hdi.lParam == iSubItem)
return iColumn;
}
return -1;
}
void CReportCtrl::SetState(INT iRow, UINT nState, UINT nMask)
{
if(iRow == RVI_EDIT)
{
m_itemEdit.nState &= ~nMask;
m_itemEdit.nState |= nState&nMask;
}
else if(!(m_dwStyle&RVS_OWNERDATA))
{
m_arrayItems[m_arrayRows[iRow]].nState &= ~nMask;
m_arrayItems[m_arrayRows[iRow]].nState |= nState&nMask;
}
}
UINT CReportCtrl::GetState(INT iRow)
{
RVITEM rvi;
rvi.iItem = GetItemFromRow(iRow);
rvi.nMask = RVIM_STATE;
GetItem(&rvi);
ASSERT(rvi.nMask&RVIM_STATE); // Need to return state of the item
return rvi.nState;
}
INT CReportCtrl::FindColumnInHeader(INT iColumn)
{
INT iColumns = m_arrayColumns.GetSize();
for(INT i=0;i<iColumns;i++)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[i], &hdi);
if(hdi.lParam == iColumn)
return i;
}
return -1;
}
INT CReportCtrl::GetVisibleRows(BOOL bUnobstructed, LPINT lpiFirst, LPINT lpiLast, BOOL bReverse)
{
INT iHeight = m_rectReport.Height();
INT iRows = 0;
if(!bReverse)
{
INT iRow;
INT iMaxRows = m_iVirtualHeight;
if(lpiFirst)
iRow = *lpiFirst;
else
iRow = GetScrollPos32(SB_VERT);
for(;iRow<iMaxRows&&iHeight>0;iRow++,iRows++)
{
iHeight -= m_iDefaultHeight + GetItemStruct(GetItemFromRow(iRow), -1).nPreview;
if(bUnobstructed && iHeight<=0)
break;
}
if(lpiLast)
*lpiLast = iRow-1;
}
else
{
ASSERT(lpiFirst);
ASSERT(lpiLast);
for(*lpiFirst=*lpiLast;*lpiFirst>=0&&iHeight>0;*lpiFirst-=1,iRows++)
{
iHeight -= m_iDefaultHeight+GetItemStruct(GetItemFromRow(*lpiFirst), -1).nPreview;
if(bUnobstructed && iHeight<=0)
break;
}
*lpiFirst += 1;
}
return iRows;
}
void CReportCtrl::SelectRows(INT iFirst, INT iLast, BOOL bSelect, BOOL bKeepSelection, BOOL bInvert, BOOL bNotify)
{
INT i;
if(m_dwStyle&RVS_SINGLESELECT)
{
iLast = iFirst;
bKeepSelection = FALSE;
}
if(m_iFocusRow > RVI_INVALID && iFirst != m_iFocusRow)
{
SetState(m_iFocusRow, 0, RVIS_FOCUSED);
RedrawItems(m_iFocusRow);
}
m_iFocusRow = iFirst;
SetState(iFirst, RVIS_FOCUSED, RVIS_FOCUSED);
if(iFirst > iLast)
{
iLast += iFirst;
iFirst = iLast - iFirst;
iLast -= iFirst;
}
if(bSelect)
{
for(i=iFirst;i<=iLast;i++)
{
INT iItem = GetItemFromRow(i);
UINT nOldState, nNewState;
nOldState = nNewState = GetState(i);
if(bInvert)
nNewState ^= RVIS_SELECTED;
else
nNewState |= RVIS_SELECTED;
if(nNewState != nOldState)
{
if(bNotify && Notify(RVN_SELECTIONCHANGING, iItem, -1, nNewState))
continue;
SetState(i, nNewState, RVIS_SELECTED);
if(bNotify)
Notify(RVN_SELECTIONCHANGED, iItem, -1, nNewState);
}
}
RedrawItems(iFirst, iLast);
}
else
RedrawItems(iFirst);
if(!bKeepSelection && bSelect)
{
INT iRows = m_iVirtualHeight;
for(i=RVI_EDIT;i<iRows;i++)
{
INT iItem = GetItemFromRow(i);
UINT nOldState, nNewState;
nOldState = nNewState = GetState(i);
if((i<iFirst || i>iLast) && nOldState&RVIS_SELECTED)
{
nNewState &= ~RVIS_SELECTED;
if(nNewState != nOldState)
{
if(bNotify && Notify(RVN_SELECTIONCHANGING, iItem, -1, nNewState))
continue;
SetState(i, nNewState, RVIS_SELECTED);
if(bNotify)
Notify(RVN_SELECTIONCHANGED, iItem, -1, nNewState);
RedrawItems(i);
}
}
}
}
}
INT CReportCtrl::GetScrollPos32(INT iBar, BOOL bGetTrackPos)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
if(bGetTrackPos)
{
if(GetScrollInfo(iBar, &si, SIF_TRACKPOS))
return si.nTrackPos;
}
else
{
if(GetScrollInfo(iBar, &si, SIF_POS))
return si.nPos;
}
return 0;
}
BOOL CReportCtrl::SetScrollPos32(INT iBar, INT iPos, BOOL bRedraw)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = iPos;
return SetScrollInfo(iBar, &si, bRedraw);
}
void CReportCtrl::ScrollWindow(INT iBar, INT iPos)
{
if(m_rectReport.Width()<=0 || m_rectReport.Height()<=0)
return;
m_wndTip.Hide();
if(iBar == SB_HORZ)
{
SCROLLINFO si;
INT iWidth = m_rectReport.Width();
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
si.nPage = iWidth;
si.nMin = 0;
si.nMax = iWidth<m_iVirtualWidth ? m_iVirtualWidth-1:0;
si.nPos = iPos;
SetScrollInfo(SB_HORZ, &si, TRUE);
INT x = GetScrollPos32(SB_HORZ);
INT cx = iWidth<m_iVirtualWidth ? m_iVirtualWidth:iWidth;
VERIFY(m_wndHeader.SetWindowPos(&wndTop, -x, m_rectHeader.top, cx, m_rectHeader.Height(), m_dwStyle&RVS_NOHEADER ? SWP_HIDEWINDOW:SWP_SHOWWINDOW));
}
if(iBar == SB_VERT)
{
INT iItems = GetItemCount();
ASSERT(iPos >= 0 && iPos<=iItems);
INT iFirst = iPos, iLast;
GetVisibleRows(TRUE, &iFirst, &iLast);
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
si.nPage = (iLast - iFirst + 1);
si.nMin = 0;
si.nMax = (iLast - iFirst + 1)<iItems ? iItems-1:0;
si.nPos = iFirst;
SetScrollInfo(SB_VERT, &si, TRUE);
}
if(m_dwStyle&RVS_SHOWEDITROW)
InvalidateRect(m_rectEdit);
InvalidateRect(m_rectReport);
}
void CReportCtrl::EnsureVisibleColumn(INT iColumn)
{
if(iColumn > -1)
{
INT iWidth = m_rectReport.Width();
INT iPos = GetScrollPos(SB_HORZ);
INT iOffset = 0;
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
for(INT i=0;i<iColumn;i++)
{
m_wndHeader.GetItem(m_arrayColumns[i], &hdi);
iOffset += hdi.cxy;
}
m_wndHeader.GetItem(m_arrayColumns[i], &hdi);
if(iOffset + hdi.cxy > iPos+iWidth || iOffset < iPos)
ScrollWindow(SB_HORZ, iOffset);
}
}
void CReportCtrl::DrawCtrl(CDC* pDC)
{
CRect rectClip;
if (pDC->GetClipBox(&rectClip) == ERROR)
return;
INT iHPos = GetScrollPos32(SB_HORZ);
INT iVPos = GetScrollPos32(SB_VERT);
DrawBkgnd(pDC, rectClip, m_crBackground);
CPen pen(m_iGridStyle, 1, m_crGrid);
CPen* pPen = pDC->SelectObject(&pen);
CFont* pFont = pDC->SelectObject(GetFont());
pDC->SetBkMode(TRANSPARENT);
CRect rect;
CRect rectRow(m_rectReport.left-iHPos, m_rectReport.top, m_rectReport.left-iHPos+m_iVirtualWidth, m_rectReport.top);
TCHAR szText[REPORTCTRL_MAX_TEXT];
RVITEM rvi;
rvi.nMask = RVIM_TEXT;
rvi.lpszText = szText;
rvi.iTextMax = REPORTCTRL_MAX_TEXT;
NMRVDRAWPREVIEW nmrvdp;
nmrvdp.hdr.hwndFrom = GetSafeHwnd();
nmrvdp.hdr.idFrom = GetDlgCtrlID();
nmrvdp.hdr.code = RVN_ITEMDRAWPREVIEW;
nmrvdp.hDC = pDC->m_hDC;
CWnd* pwndParent = GetParent();
INT iRows = m_iVirtualHeight;
INT iColumns = m_wndHeader.GetItemCount();
ASSERT(iColumns>0); // Make sure that always one column is active
if(m_bColumnsReordered)
{
LPINT lpi;
m_iFocusColumn = m_iFocusColumn >= iColumns ? iColumns-1:m_iFocusColumn;
m_arrayColumns.SetSize(iColumns, 8);
lpi = m_arrayColumns.GetData();
if(!m_wndHeader.GetOrderArray(lpi, iColumns))
return;
if(m_lprclc != NULL)
m_lprclc->UpdateList();
m_bColumnsReordered = FALSE;
}
if(m_dwStyle&RVS_SHOWEDITROW)
{
GetClientRect(rect);
rect.bottom = m_rectEdit.bottom;
rect.top = rect.bottom - GetSystemMetrics(SM_CYFIXEDFRAME)*2;
pDC->FillSolidRect(rect, m_cr3DFace);
pDC->Draw3dRect(rect, m_cr3DHiLight, m_cr3DDkShadow);
rvi.iItem = -1;
rvi.nMask = RVIM_TEXT;
GetItem(&rvi);
rect = m_rectEdit;
rect.bottom -= GetSystemMetrics(SM_CYFIXEDFRAME)*2;
rect.OffsetRect(-iHPos, 0);
DrawRow(pDC, rect, rectClip, RVI_EDIT, &rvi, FALSE);
if(m_bFocus && m_hEditWnd == NULL && m_iFocusRow == RVI_EDIT && m_iFocusColumn == -1)
{
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
rect.DeflateRect(1, 0, 1, 0);
pDC->SetBkColor(m_crBackground);
pDC->SetTextColor(m_crText);
pDC->DrawFocusRect(rect);
}
}
if(!iRows)
{
rectRow.top += 2;
rectRow.bottom = rectRow.top + m_iDefaultHeight;
GetClientRect(rect);
rect.top = rectRow.top;
rect.bottom = rectRow.bottom;
if(rectRow.Width() < rect.Width())
rect = rectRow;
pDC->SetTextColor(m_crText);
pDC->DrawText(m_strNoItems, rect, DT_CENTER|DT_END_ELLIPSIS);
return;
}
INT iRow = iVPos;
while(iRow<iRows && rectRow.top<rectClip.bottom)
{
rvi.iItem = GetItemFromRow(iRow);
rvi.nMask = RVIM_TEXT;
VERIFY(GetItem(&rvi));
rectRow.bottom = rectRow.top + m_iDefaultHeight+rvi.nPreview;
if(rectRow.bottom >= rectClip.top)
{
DrawRow(pDC, rectRow, rectClip, iRow, &rvi, iRow&1);
if(rvi.nMask&RVIM_PREVIEW && rvi.nPreview && pwndParent)
{
nmrvdp.iItem = rvi.iItem;
nmrvdp.nState = rvi.nState;
nmrvdp.rect = rectRow;
nmrvdp.rect.top += m_iDefaultHeight;
nmrvdp.lParam = rvi.lParam;
pwndParent->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvdp);
}
if(m_dwStyle&RVS_SHOWHGRID)
{
pDC->MoveTo(rectRow.left, rectRow.bottom-1);
pDC->LineTo(rectRow.right, rectRow.bottom-1);
}
if(m_bFocus && m_hEditWnd == NULL && m_iFocusRow == iRow && m_iFocusColumn == -1)
{
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
rectRow.DeflateRect(1, 0, 1, 1);
pDC->SetBkColor(m_crBackground);
pDC->SetTextColor(m_crText);
pDC->DrawFocusRect(rectRow);
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
rectRow.InflateRect(1, 0, 1, 1);
}
}
rectRow.top = rectRow.bottom;
iRow++;
}
rectRow.top = m_rectReport.top;
rectRow.bottom =
m_rectReport.bottom<rectRow.bottom
?
m_rectReport.bottom:rectRow.bottom;
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
{
if(m_dwStyle&RVS_SHOWHGRIDEX)
{
pDC->MoveTo(rectRow.left, m_rectReport.top);
pDC->LineTo(rectRow.left, m_rectReport.bottom);
pDC->MoveTo(rectRow.right-1, m_rectReport.top);
pDC->LineTo(rectRow.right-1, m_rectReport.bottom);
}
else
{
pDC->MoveTo(rectRow.left, rectRow.top);
pDC->LineTo(rectRow.left, rectRow.bottom);
pDC->MoveTo(rectRow.right-1, rectRow.top);
pDC->LineTo(rectRow.right-1, rectRow.bottom);
}
}
if(m_dwStyle&RVS_SHOWHGRID && m_dwStyle&RVS_SHOWHGRIDEX && iRow>=iRows)
{
while(rectRow.bottom<rectClip.bottom)
{
pDC->MoveTo(rectRow.left, rectRow.bottom-1);
pDC->LineTo(rectRow.right, rectRow.bottom-1);
rectRow.bottom += m_iDefaultHeight;
}
}
if(m_dwStyle&RVS_SHOWVGRID)
{
for(INT iColumn=0;iColumn<iColumns&&rectRow.left<rectClip.right;iColumn++)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH;
m_wndHeader.GetItem(m_arrayColumns[iColumn], &hdi);
rectRow.left += hdi.cxy;
pDC->MoveTo(rectRow.left-1, rectRow.top);
pDC->LineTo(rectRow.left-1, rectRow.bottom);
}
}
pDC->SelectObject(pFont);
pDC->SelectObject(pPen);
pen.DeleteObject();
}
void CReportCtrl::DrawRow(CDC* pDC, CRect rectRow, CRect rectClip, INT iRow, LPRVITEM lprvi, BOOL bAlternate)
{
INT iColumns = m_wndHeader.GetItemCount();
// You have to insert at least 1 color to use color alternate style.
ASSERT(!(m_dwStyle&RVS_SHOWCOLORALTERNATE && !m_arrayColors.GetSize()));
COLORREF crItem;
crItem = (m_dwStyle&RVS_SHOWCOLORALTERNATE && bAlternate) ? m_arrayColors[0]:m_crBackground;
crItem = lprvi->iBkColor>=0 ? m_arrayColors[lprvi->iBkColor]:crItem;
if(lprvi->nState&RVIS_SELECTED)
{
if(m_bFocus)
crItem = m_crBkSelected;
else
if(m_dwStyle&RVS_SHOWSELALWAYS)
crItem = m_crBkSelectedNoFocus;
}
if(m_bitmap.m_hObject == NULL || crItem != m_crBackground || iRow == RVI_EDIT)
{
pDC->FillSolidRect(rectRow, crItem);
pDC->SetBkColor(crItem);
}
if(lprvi->nState&RVIS_BOLD)
pDC->SelectObject(&m_fontBold);
CRect rectItem(rectRow.left, rectRow.top, rectRow.left, rectRow.top+m_iDefaultHeight);
for(INT iColumn=0;iColumn<iColumns&&rectItem.left<rectClip.right;iColumn++)
{
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_LPARAM;
m_wndHeader.GetItem(m_arrayColumns[iColumn], &hdi);
lprvi->iSubItem = hdi.lParam;
rectItem.right = rectItem.left + hdi.cxy;
if(rectItem.right > rectClip.left)
{
lprvi->nMask = RVIM_TEXT;
VERIFY(GetItem(lprvi));
COLORREF crText = lprvi->nMask&RVIM_TEXTCOLOR ? m_arrayColors[lprvi->iTextColor]:m_crText;
if(lprvi->nState&RVIS_SELECTED)
{
if(m_bFocus)
crText = (m_dwStyle&RVS_SHOWCOLORALWAYS && lprvi->nMask&RVIM_TEXTCOLOR) ? crText:m_crTextSelected;
else
if(m_dwStyle&RVS_SHOWSELALWAYS)
crText = lprvi->nMask&RVIM_TEXTCOLOR && m_dwStyle&RVS_SHOWCOLORALWAYS ? crText:m_crTextSelectedNoFocus;
}
if(m_iFocusRow == iRow && m_iFocusColumn == iColumn)
{
pDC->FillSolidRect(rectItem, m_crBackground);
crText = m_crText;
}
pDC->SetTextColor(crText);
rectItem.DeflateRect(m_iSpacing, 0);
DrawItem(pDC, rectItem, lprvi);
rectItem.InflateRect(m_iSpacing, 0);
if(m_bFocus && m_hEditWnd == NULL && m_iFocusRow == iRow && m_iFocusColumn == iColumn)
{
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
rectItem.DeflateRect(1, 0, 1, 1);
pDC->SetBkColor(m_crBackground);
pDC->SetTextColor(m_crText);
pDC->DrawFocusRect(rectItem);
if(m_dwStyle&(RVS_SHOWHGRID|RVS_SHOWVGRID))
rectItem.InflateRect(1, 0, 1, 1);
}
}
rectItem.left = rectItem.right;
}
if(lprvi->nState&RVIS_BOLD)
pDC->SelectObject(GetFont());
}
void CReportCtrl::DrawItem(CDC* pDC, CRect rect, LPRVITEM lprvi)
{
INT iWidth = 0;
rect.left += (iWidth = DrawImage(pDC, rect, lprvi)) ? iWidth+m_iSpacing : 0;
if(lprvi->nMask&RVIM_IMAGE && !iWidth)
return;
rect.left += (iWidth = DrawCheck(pDC, rect, lprvi)) ? iWidth+m_iSpacing : 0;
if(lprvi->nMask&RVIM_CHECK && !iWidth)
return;
DrawText(pDC, rect, lprvi);
}
INT CReportCtrl::DrawImage(CDC* pDC, CRect rect, LPRVITEM lprvi)
{
CImageList* pImageList = GetImageList();
INT iWidth = 0;
if(lprvi->nMask&RVIM_IMAGE)
{
ASSERT(pImageList);
ASSERT(lprvi->iImage>=0 && lprvi->iImage<pImageList->GetImageCount());
if(rect.Width()>0)
{
POINT point;
point.y = rect.CenterPoint().y - (m_sizeImage.cy>>1);
point.x = rect.left;
SIZE size;
size.cx = rect.Width()<m_sizeImage.cx ? rect.Width():m_sizeImage.cx;
size.cy = m_sizeImage.cy;
pImageList->DrawIndirect(pDC, lprvi->iImage, point, size, CPoint(0, 0));
iWidth = m_sizeImage.cx;
}
}
else
iWidth = m_arraySubItems[lprvi->iSubItem].nFormat&RVCF_SUBITEM_IMAGE ? m_sizeImage.cx:0;
return iWidth;
}
INT CReportCtrl::DrawCheck(CDC* pDC, CRect rect, LPRVITEM lprvi)
{
INT iWidth = 0;
if(lprvi->nMask&RVIM_CHECK)
{
if(rect.Width()>m_sizeCheck.cx)
{
rect.top = rect.CenterPoint().y - (m_sizeCheck.cy>>1);
rect.left = rect.left;
rect.bottom = rect.top + m_sizeCheck.cx;
rect.right = rect.left + m_sizeCheck.cy;
pDC->FillSolidRect(rect, m_crBackground); // Fixes visual problem with bigger fonts
pDC->DrawFrameControl(
rect,
DFC_BUTTON,
DFCS_BUTTONCHECK|DFCS_FLAT|(lprvi->iCheck?DFCS_CHECKED:0)
);
iWidth = m_sizeCheck.cx;
}
}
else
iWidth = m_arraySubItems[lprvi->iSubItem].nFormat&RVCF_SUBITEM_CHECK ? m_sizeCheck.cx:0;
return iWidth;
}
INT CReportCtrl::DrawText(CDC* pDC, CRect rect, LPRVITEM lprvi)
{
CSize size;
if(rect.Width()>0 && lprvi->nMask&RVIM_TEXT)
{
size = pDC->GetTextExtent(lprvi->lpszText);
switch(m_arraySubItems[lprvi->iSubItem].nFormat&HDF_JUSTIFYMASK)
{
case HDF_LEFT:
case HDF_LEFT|HDF_RTLREADING:
pDC->DrawText(lprvi->lpszText, -1, rect, DT_LEFT|DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER);
break;
case HDF_CENTER:
case HDF_CENTER|HDF_RTLREADING:
pDC->DrawText(lprvi->lpszText, -1, rect, DT_CENTER|DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER);
break;
case HDF_RIGHT:
case HDF_RIGHT|HDF_RTLREADING:
pDC->DrawText(lprvi->lpszText, -1, rect, DT_RIGHT|DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER);
break;
}
}
size.cx = rect.Width()>size.cx ? size.cx:rect.Width();
return size.cx>0 ? size.cx:0;
}
BOOL CReportCtrl::DrawBkgnd(CDC* pDC, CRect rect, COLORREF crBackground)
{
if(m_bitmap.m_hObject != NULL)
{
CDC dc;
CRgn rgnBitmap;
CRect rectBitmap;
dc.CreateCompatibleDC(pDC);
dc.SelectObject(&m_bitmap);
rect.IntersectRect(rect, m_rectReport);
INT iHPos = GetScrollPos32(SB_HORZ);
rectBitmap.top = rect.top - rect.top%m_sizeBitmap.cy;
rectBitmap.bottom = rect.top + m_sizeBitmap.cy;
rectBitmap.left = rect.left - (rect.left+iHPos)%m_sizeBitmap.cx;
rectBitmap.right = rect.left + m_sizeBitmap.cx;
INT x, y;
for(x = rectBitmap.left; x < rect.right; x += m_sizeBitmap.cx)
for(y = rectBitmap.top; y < rect.bottom; y += m_sizeBitmap.cy)
pDC->BitBlt(x, y, m_sizeBitmap.cx, m_sizeBitmap.cy, &dc, 0, 0, SRCCOPY);
return TRUE;
}
pDC->FillSolidRect(rect, crBackground);
return FALSE;
}
BOOL CReportCtrl::BeginEdit(INT iRow, INT iColumn, UINT nKey)
{
if(iRow == RVI_INVALID || iColumn == -1)
return FALSE;
TCHAR szText[REPORTCTRL_MAX_TEXT];
m_iEditItem = GetItemFromRow(iRow);
m_iEditSubItem = GetSubItemFromColumn(iColumn);
// Make sure that the item to edit actually exists
ASSERT(m_iEditItem != RVI_INVALID && m_iEditSubItem != -1);
RVITEM rvi;
rvi.iItem = m_iEditItem;
rvi.iSubItem = m_iEditSubItem;
rvi.nMask = RVIM_TEXT|RVIM_STATE|RVIM_LPARAM;
rvi.lpszText = szText;
rvi.iTextMax = REPORTCTRL_MAX_TEXT;
GetItem(&rvi);
if(rvi.nState&RVIS_READONLY)
return FALSE;
NMRVITEMEDIT nmrvie;
nmrvie.hdr.hwndFrom = GetSafeHwnd();
nmrvie.hdr.idFrom = GetDlgCtrlID();
nmrvie.hdr.code = RVN_BEGINITEMEDIT;
nmrvie.iItem = m_iEditItem;
nmrvie.iSubItem = m_iEditSubItem;
nmrvie.hWnd = NULL;
if(!GetItemRect(m_iEditItem, m_iEditSubItem, &nmrvie.rect))
return FALSE;
nmrvie.nKey = nKey;
if(rvi.nMask&RVIM_TEXT)
nmrvie.lpszText = szText;
nmrvie.lParam = rvi.lParam;
BOOL bResult = FALSE;
CWnd* pWnd = GetParent();
if(pWnd != NULL)
bResult = pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvie);
if(!bResult)
{
if(!(rvi.nMask&RVIM_TEXT))
return FALSE;
if(!GetItemRect(m_iEditItem, m_iEditSubItem, &nmrvie.rect, RVIR_TEXT))
return FALSE;
CReportEditCtrl* pWnd= new CReportEditCtrl(m_iEditItem, m_iEditSubItem);
if(pWnd == NULL)
return FALSE;
if(!pWnd->Create(
WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,
nmrvie.rect,
this,
0)
) {
delete pWnd;
return FALSE;
}
pWnd->SetFont(
rvi.nMask&RVIM_STATE && rvi.nState&RVIS_BOLD
?
&m_fontBold:&m_font
);
pWnd->SetWindowText(szText);
switch (nKey){
case VK_LBUTTON:
case VK_RETURN:
pWnd->SetSel((INT)_tcslen(szText), -1);
break;
case VK_BACK:
pWnd->SetSel((INT)_tcslen(szText), -1);
pWnd->SendMessage(WM_CHAR, nKey);
break;
case VK_TAB:
case VK_DOWN:
case VK_UP:
case VK_RIGHT:
case VK_LEFT:
case VK_NEXT:
case VK_PRIOR:
case VK_HOME:
case VK_SPACE:
case VK_END:
pWnd->SetSel(0,-1);
break;
default:
pWnd->SetSel(0,-1);
pWnd->SendMessage(WM_CHAR, nKey);
break;
}
m_hEditWnd = pWnd->GetSafeHwnd();
}
else
{
if(nmrvie.hWnd == NULL)
return FALSE;
m_hEditWnd = nmrvie.hWnd;
}
if(m_hEditWnd != NULL)
::SetFocus(m_hEditWnd);
return TRUE;
}
void CReportCtrl::EndEdit(BOOL bUpdate, LPNMRVITEMEDIT lpnmrvie)
{
if(!(m_dwStyle&RVS_OWNERDATA) && bUpdate)
{
if(lpnmrvie == NULL)
{
TCHAR szText[REPORTCTRL_MAX_TEXT];
INT i = ::GetWindowText(m_hEditWnd, szText, REPORTCTRL_MAX_TEXT-1);
szText[REPORTCTRL_MAX_TEXT-1] = 0;
if(i || !::GetLastError())
SetItemText(m_iEditItem, m_iEditSubItem, szText);
}
else
SetItemText(m_iEditItem, m_iEditSubItem, lpnmrvie->lpszText);
}
if(IsWindow(m_hEditWnd))
::PostMessage(m_hEditWnd, WM_CLOSE, 0, 0);
m_hEditWnd = NULL;
CWnd* pWnd = GetFocus();
if(pWnd)
{
if(pWnd->GetSafeHwnd() != m_hWnd)
m_bFocus = FALSE;
}
RedrawItems(m_iFocusRow, m_iFocusRow);
}
/////////////////////////////////////////////////////////////////////////////
// CReportCtrl message handlers
BOOL CReportCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
SetCursor(::LoadCursor(NULL, IDC_ARROW));
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CReportCtrl::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
m_bFocus = TRUE;
Invalidate();
}
void CReportCtrl::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
if(pNewWnd)
{
if(pNewWnd->m_hWnd != m_hEditWnd)
m_bFocus = FALSE;
}
else
m_bFocus = FALSE;
Invalidate();
}
void CReportCtrl::OnSysColorChange()
{
CWnd::OnSysColorChange();
GetSysColors();
}
void CReportCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
CWnd::OnSettingChange(uFlags, lpszSection);
m_nRowsPerWheelNotch = GetMouseScrollLines();
}
BOOL CReportCtrl::OnQueryNewPalette()
{
Invalidate();
return CWnd::OnQueryNewPalette();
}
void CReportCtrl::OnPaletteChanged(CWnd* pFocusWnd)
{
CWnd::OnPaletteChanged(pFocusWnd);
if(pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
Invalidate();
}
void CReportCtrl::OnSize(UINT nType, int cx, int cy)
{
if(m_hEditWnd != NULL)
EndEdit();
CWnd::OnSize(nType, cx, cy);
CRect rect;
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
}
LRESULT CReportCtrl::OnGetFont(WPARAM wParam, LPARAM lParam)
{
return (LRESULT)m_font.m_hObject;
}
LRESULT CReportCtrl::OnSetFont(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = Default();
CFont *pFont = CFont::FromHandle((HFONT)wParam);
if(pFont)
{
LOGFONT lf;
pFont->GetLogFont(&lf);
m_font.DeleteObject();
m_font.CreateFontIndirect(&lf);
lf.lfWeight = FW_BOLD;
m_fontBold.DeleteObject();
m_fontBold.CreateFontIndirect(&lf);
}
CDC* pDC = GetDC();
if (pDC)
{
CFont* pFont = pDC->SelectObject(&m_font);
TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);
pDC->SelectObject(pFont);
ReleaseDC(pDC);
m_iDefaultHeight = tm.tmHeight + tm.tmExternalLeading + 2;
m_iDefaultHeight += m_dwStyle&RVS_SHOWHGRID ? 1:0;
m_sizeCheck.cx = m_iDefaultHeight-2;
m_sizeCheck.cy = m_iDefaultHeight-2;
}
if(::IsWindow(GetSafeHwnd()) && lParam)
{
CRect rect;
GetClientRect(rect);
Layout(rect.Width(), rect.Height());
}
return lResult;
}
BOOL CReportCtrl::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CReportCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
LONG lStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
if(lStyle & WS_BORDER)
::InflateRect(&lpncsp->rgrc[0], -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
Default();
}
void CReportCtrl::OnNcPaint()
{
Default();
LONG lStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
if(lStyle & WS_BORDER)
{
CWindowDC dc(this);
CRect rcBounds;
GetWindowRect(rcBounds);
ScreenToClient(rcBounds);
rcBounds.OffsetRect(-rcBounds.left, -rcBounds.top);
dc.DrawEdge(rcBounds, EDGE_SUNKEN, BF_RECT);
}
}
void CReportCtrl::OnPaint()
{
CPaintDC dc(this);
CPalette* pPalette = NULL;
if(dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
{
pPalette = dc.SelectPalette(&m_palette, FALSE);
dc.RealizePalette();
}
dc.ExcludeClipRect(m_rectHeader);
if(m_bDoubleBuffer)
{
CMemDC MemDC(&dc);
DrawCtrl(&MemDC);
if(m_hEditWnd != NULL)
{
RECT rect;
::GetWindowRect(m_hEditWnd, &rect);
ScreenToClient(&rect);
dc.ExcludeClipRect(&rect);
}
}
else
DrawCtrl(&dc);
if(pPalette && dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
dc.SelectPalette(pPalette, FALSE);
}
void CReportCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
INT iScrollPos = GetScrollPos32(SB_HORZ);
INT iScroll;
if(m_hEditWnd != NULL)
EndEdit();
switch (nSBCode)
{
case SB_LINERIGHT:
iScroll = min(m_iVirtualWidth-(m_rectReport.Width()+iScrollPos), m_rectReport.Width()>>3);
ScrollWindow(SB_HORZ, iScrollPos + iScroll);
break;
case SB_LINELEFT:
iScroll = min(iScrollPos, m_rectReport.Width()>>3);
ScrollWindow(SB_HORZ, iScrollPos - iScroll);
break;
case SB_PAGERIGHT:
iScrollPos = min(m_iVirtualWidth, iScrollPos + m_rectReport.Width());
ScrollWindow(SB_HORZ, iScrollPos);
break;
case SB_PAGELEFT:
iScrollPos = max(0, iScrollPos - m_rectReport.Width());
ScrollWindow(SB_HORZ, iScrollPos);
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
iScrollPos = nPos;
ScrollWindow(SB_HORZ, iScrollPos);
break;
case SB_RIGHT:
ScrollWindow(SB_HORZ, m_iVirtualWidth);
break;
case SB_LEFT:
ScrollWindow(SB_HORZ, 0);
break;
default:
break;
}
}
void CReportCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
INT iFirst = GetScrollPos32(SB_VERT), iLast;
INT iItems = GetVisibleRows(TRUE, &iFirst, &iLast);
if(m_hEditWnd != NULL)
EndEdit();
switch(nSBCode)
{
case SB_LINEUP:
if(iFirst>0)
iFirst--;
break;
case SB_LINEDOWN:
if(iFirst+iItems < m_iVirtualHeight)
iFirst++;
break;
case SB_PAGEUP:
GetVisibleRows(TRUE, &iLast, &iFirst, TRUE);
iFirst = iLast-1;
iFirst = iFirst<0 ? 0:iFirst;
break;
case SB_PAGEDOWN:
iFirst += iItems;
GetVisibleRows(TRUE, &iFirst, &iLast);
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
iFirst = nPos;
GetVisibleRows(TRUE, &iFirst, &iLast);
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
break;
case SB_TOP:
iFirst = 0;
break;
case SB_BOTTOM:
iLast = m_iVirtualHeight-1;
GetVisibleRows(TRUE, &iFirst, &iLast, TRUE);
break;
default:
return;
}
ScrollWindow(SB_VERT, iFirst);
}
void CReportCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
RVHITTESTINFO rvhti;
rvhti.point = point;
HitTest(&rvhti);
if(Notify(RVN_ITEMCLICK, nFlags, &rvhti))
{
CWnd::OnLButtonDown(nFlags, point);
return;
}
INT iFocusRow = m_iFocusRow, iFocusColumn = m_iFocusColumn;
m_iFocusColumn = m_dwStyle&RVS_FOCUSSUBITEMS? rvhti.iColumn:-1;
if(rvhti.iItem >= -1)
{
INT iRow = GetRowFromItem(rvhti.iItem);
ASSERT(iRow >= -1);
switch(nFlags&(MK_CONTROL|MK_SHIFT))
{
case MK_CONTROL:
SelectRows(iRow, iRow, TRUE, TRUE, TRUE);
m_iSelectRow = iRow;
break;
case MK_SHIFT:
SelectRows(m_iSelectRow, iRow, TRUE);
break;
case MK_CONTROL|MK_SHIFT:
SelectRows(m_iSelectRow, iRow, TRUE, TRUE);
m_iSelectRow = iRow;
break;
default:
SelectRows(iRow, iRow, TRUE);
m_iSelectRow = iRow;
if(m_iFocusRow == iFocusRow && m_iFocusColumn == iFocusColumn)
BeginEdit(m_iFocusRow, m_iFocusColumn, VK_LBUTTON);
break;
}
}
}
void CReportCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
RVHITTESTINFO rvhti;
rvhti.point = point;
HitTest(&rvhti);
if(Notify(RVN_ITEMDBCLICK, nFlags, &rvhti))
{
CWnd::OnLButtonDblClk(nFlags, point);
return;
}
}
UINT CReportCtrl::OnGetDlgCode()
{
return DLGC_WANTARROWS;
}
void CReportCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
INT iFirst = GetScrollPos32(SB_VERT), iLast;
GetVisibleRows(TRUE, &iFirst, &iLast);
switch (nChar)
{
case VK_SPACE:
SelectRows(m_iFocusRow, m_iFocusRow, TRUE, TRUE, IsCtrlDown() ? TRUE:FALSE);
return;
case VK_LEFT:
if(m_dwStyle&RVS_FOCUSSUBITEMS)
{
m_iFocusColumn -= m_iFocusColumn>0 ? 1:0;
EnsureVisibleColumn(m_iFocusColumn);
iFirst = GetRowFromItem(m_iFocusRow);
RedrawItems(iFirst, iFirst);
}
else
SendMessage(WM_HSCROLL, LOWORD(SB_LINELEFT), NULL);
return;
case VK_RIGHT:
if(m_dwStyle&RVS_FOCUSSUBITEMS)
{
m_iFocusColumn += m_iFocusColumn<m_arrayColumns.GetSize()-1 ? 1:0;
EnsureVisibleColumn(m_iFocusColumn);
iFirst = GetRowFromItem(m_iFocusRow);
RedrawItems(iFirst, iFirst);
}
else
SendMessage(WM_HSCROLL, LOWORD(SB_LINERIGHT), NULL);
return;
case VK_DOWN:
if(m_iFocusRow<m_iVirtualHeight-1)
{
if(IsCtrlDown())
{
SelectRows(m_iFocusRow+1, m_iFocusRow+1, FALSE);
m_iSelectRow = m_iFocusRow;
}
else if(!IsShiftDown())
{
SelectRows(m_iFocusRow+1, m_iFocusRow+1, TRUE);
m_iSelectRow = m_iFocusRow;
}
else
SelectRows(m_iFocusRow+1, m_iSelectRow, TRUE);
EnsureVisible(GetItemFromRow(m_iFocusRow));
}
return;
case VK_UP:
if(
(m_dwStyle&RVS_SHOWEDITROW && m_iFocusRow > RVI_EDIT) ||
m_iFocusRow > RVI_FIRST
) {
if(IsCtrlDown())
{
SelectRows(m_iFocusRow-1, m_iFocusRow-1, FALSE);
m_iSelectRow = m_iFocusRow;
}
else if(!IsShiftDown())
{
SelectRows(m_iFocusRow-1, m_iFocusRow-1, TRUE);
m_iSelectRow = m_iFocusRow;
}
else
SelectRows(m_iFocusRow-1, m_iSelectRow, TRUE);
EnsureVisible(GetItemFromRow(m_iFocusRow));
}
return;
case VK_NEXT:
if(m_iFocusRow == iLast)
{
SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
iFirst = GetScrollPos32(SB_VERT);
GetVisibleRows(TRUE, &iFirst, &iLast);
}
if(IsCtrlDown())
{
SelectRows(iLast, iLast, FALSE);
m_iSelectRow = m_iFocusRow;
return;
}
else if(!IsShiftDown())
{
iFirst = iLast;
m_iSelectRow = iLast;
}
else
iFirst = m_iSelectRow;
SelectRows(iLast, iFirst, TRUE);
return;
case VK_PRIOR:
if(m_iFocusRow == iFirst)
{
SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
iFirst = GetScrollPos32(SB_VERT);
}
if(IsCtrlDown())
{
SelectRows(iFirst, iFirst, FALSE);
m_iSelectRow = m_iFocusRow;
return;
}
else if(!IsShiftDown())
{
iLast = iFirst;
m_iSelectRow = iFirst;
}
else
iLast = m_iSelectRow;
SelectRows(iFirst, iLast, TRUE);
return;
case VK_HOME:
if(m_iFocusRow>0)
{
SendMessage(WM_VSCROLL, SB_TOP, 0);
if(!IsShiftDown())
m_iSelectRow = 0;
SelectRows(0, m_iSelectRow, IsCtrlDown()?FALSE:TRUE);
}
break;
case VK_END:
if(m_iFocusRow<m_iVirtualHeight)
{
SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
if(!IsShiftDown())
m_iSelectRow = m_iVirtualHeight-1;
SelectRows(m_iSelectRow, m_iVirtualHeight-1, IsCtrlDown()?FALSE:TRUE);
}
break;
}
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CReportCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(!IsCtrlDown() && nChar != VK_ESCAPE)
if(BeginEdit(m_iFocusRow, m_iFocusColumn, nChar))
return;
CWnd::OnChar(nChar, nRepCnt, nFlags);
}
BOOL CReportCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
int i;
// A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
// wheel scrolls whole pages, not just lines.
if (m_nRowsPerWheelNotch == -1)
{
int iPagesScrolled = zDelta / 120;
if (iPagesScrolled > 0)
for (i=0;i<iPagesScrolled;i++)
PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
else
for (i=0;i>iPagesScrolled;i--)
PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
}
else
{
int iRowsScrolled = (int)m_nRowsPerWheelNotch * zDelta / 120;
if (iRowsScrolled>0)
for (i=0;i<iRowsScrolled;i++)
PostMessage(WM_VSCROLL, SB_LINEUP, 0);
else
for (i=0;i>iRowsScrolled;i--)
PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
}
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
void CReportCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if(!nFlags && m_dwStyle&RVS_EXPANDSUBITEMS && m_hEditWnd == NULL)
{
RVHITTESTINFO rvhti;
rvhti.point = point;
if(HitTest(&rvhti) != RVI_INVALID)
{
TCHAR szText[REPORTCTRL_MAX_TEXT];
RVITEM rvi;
rvi.iItem = rvhti.iItem;
rvi.iSubItem = rvhti.iSubItem;
rvi.lpszText = szText;
rvi.iTextMax = REPORTCTRL_MAX_TEXT;
rvi.nMask = RVIM_TEXT|RVIM_STATE;
GetItem(&rvi);
if(rvi.nMask&RVIM_TEXT && _tcslen(rvi.lpszText))
m_wndTip.Show(
rvhti.rect,
rvi.lpszText,
rvi.nState&RVIS_BOLD ? &m_fontBold:&m_font
);
}
}
CWnd::OnMouseMove(nFlags, point);
}
void CReportCtrl::OnHdnItemChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
LPHDITEM lphdi = (LPHDITEM)((LPNMHEADER)pNMHDR)->pitem;
if(m_hEditWnd != NULL)
EndEdit();
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_ORDER|HDI_LPARAM;
m_wndHeader.GetItem(((LPNMHEADER)pNMHDR)->iItem, &hdi);
if(lphdi->mask&HDI_FORMAT)
m_arraySubItems[hdi.lParam].nFormat = lphdi->fmt&HDF_JUSTIFYMASK;
if(lphdi->mask&HDI_WIDTH)
{
m_iVirtualWidth += lphdi->cxy - m_arraySubItems[hdi.lParam].iWidth;
ASSERT(m_iVirtualWidth >= 0);
m_arraySubItems[hdi.lParam].iWidth = lphdi->cxy;
}
ScrollWindow(SB_HORZ, GetScrollPos32(SB_HORZ));
Notify(RVN_LAYOUTCHANGED, -1, (INT)hdi.lParam);
*pResult = FALSE;
}
void CReportCtrl::OnHdnItemClick(NMHDR* pNMHDR, LRESULT* pResult)
{
LPHDITEM lphdi = (LPHDITEM)((LPNMHEADER)pNMHDR)->pitem;
if(m_hEditWnd != NULL)
EndEdit();
HDITEM hdi;
hdi.mask = HDI_ORDER|HDI_LPARAM;
m_wndHeader.GetItem(((LPNMHEADER)pNMHDR)->iItem, &hdi);
if(!Notify(RVN_COLUMNCLICK, -1, (INT)hdi.lParam))
{
if(!(m_dwStyle&(RVS_NOSORT|RVS_OWNERDATA)))
{
BOOL bAscending;
if(((LPNMHEADER)pNMHDR)->iItem == m_wndHeader.GetSortColumn(&bAscending))
bAscending = !bAscending;
else
bAscending = TRUE;
VERIFY(SortItems((INT)hdi.lParam, bAscending));
}
}
pResult = FALSE;
}
void CReportCtrl::OnHdnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMHEADER lpnmhdr = (LPNMHEADER)pNMHDR;
if(m_hEditWnd != NULL)
EndEdit();
pResult = FALSE;
}
void CReportCtrl::OnHdnEndDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMHEADER lpnmhdr = (LPNMHEADER)pNMHDR;
if(m_wndHeader.GetDropResult())
{
if(m_dwStyle&RVS_ALLOWCOLUMNREMOVAL && m_arrayColumns.GetSize()>1)
DeactivateColumn(lpnmhdr->pitem->lParam);
*pResult = TRUE;
}
else
{
m_bColumnsReordered = TRUE;
Invalidate();
*pResult = FALSE;
}
}
void CReportCtrl::OnRvnEndItemEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMRVITEMEDIT lpnmrvie = (LPNMRVITEMEDIT)pNMHDR;
ASSERT(m_iEditItem == lpnmrvie->iItem);
ASSERT(m_iEditSubItem == lpnmrvie->iSubItem);
NMRVITEMEDIT nmrvie;
nmrvie.hdr.hwndFrom = GetSafeHwnd();
nmrvie.hdr.idFrom = GetDlgCtrlID();
nmrvie.hdr.code = RVN_ENDITEMEDIT;
nmrvie.iItem = m_iEditItem;
nmrvie.iSubItem = m_iEditSubItem;
nmrvie.hWnd = lpnmrvie->hWnd;
nmrvie.nKey = lpnmrvie->nKey;
nmrvie.lpszText = lpnmrvie->lpszText;
BOOL bResult = FALSE;
CWnd* pWnd = GetParent();
if(pWnd != NULL)
bResult = pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvie);
if(bResult)
EndEdit(FALSE);
else
EndEdit(nmrvie.nKey != VK_ESCAPE, &nmrvie);
pResult = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CReportColumnListCtrl
CReportColumnListCtrl::CReportColumnListCtrl()
{
m_pReportCtrl = NULL;
m_iColumn = -1;
m_pDragWnd = NULL;
}
CReportColumnListCtrl::~CReportColumnListCtrl()
{
}
BEGIN_MESSAGE_MAP(CReportColumnListCtrl, CDragListBox)
//{{AFX_MSG_MAP(CReportColumnListCtrl)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportColumnListCtrl attributes
BOOL CReportColumnListCtrl::SetReportCtrl(CReportCtrl* pReportCtrl)
{
ASSERT_KINDOF(CReportCtrl, pReportCtrl);
m_pReportCtrl = pReportCtrl;
ResetContent();
return TRUE;
}
CReportCtrl* CReportColumnListCtrl::GetReportCtrl()
{
return m_pReportCtrl;
}
/////////////////////////////////////////////////////////////////////////////
// CReportColumnListCtrl operations
BOOL CReportColumnListCtrl::UpdateList()
{
INT iColumn, iColumns = m_pReportCtrl->m_arraySubItems.GetSize();
ResetContent();
for(iColumn=0;iColumn<iColumns;iColumn++)
{
if(!m_pReportCtrl->IsActiveColumn(iColumn) && Include(iColumn))
{
INT iItem = AddString(m_pReportCtrl->m_arraySubItems[iColumn].strText);
SetItemData(iItem, iColumn);
}
}
return TRUE;
}
BOOL CReportColumnListCtrl::Include(INT iColumn)
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CReportColumnListCtrl message handlers
void CReportColumnListCtrl::PreSubclassWindow()
{
CDragListBox::PreSubclassWindow();
SetItemHeight(0, GetItemHeight(0)+2);
}
void CReportColumnListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rcItem(lpDrawItemStruct->rcItem);
if(GetCount() > 0)
{
pDC->DrawFrameControl(rcItem, DFC_BUTTON, DFCS_BUTTONPUSH);
rcItem.DeflateRect(2, 2);
if(lpDrawItemStruct->itemState&ODS_SELECTED)
{
pDC->FillRect(rcItem, &CBrush(::GetSysColor(COLOR_3DSHADOW)));
pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
}
else
pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(
m_pReportCtrl->m_arraySubItems[lpDrawItemStruct->itemData].strText,
-1,
rcItem,
DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_VCENTER|DT_END_ELLIPSIS|DT_LEFT);
}
else
pDC->FillSolidRect(rcItem, ::GetSysColor(COLOR_WINDOW));
}
BOOL CReportColumnListCtrl::BeginDrag(CPoint pt)
{
if(GetCount() <= 0)
return FALSE;
BOOL bAutoScroll = FALSE;
INT iItem = ItemFromPt(pt);
if(iItem >= 0)
{
GetClientRect(m_rcDragWnd);
m_rcDragWnd.bottom = m_rcDragWnd.top + GetItemHeight(0);
m_iColumn = GetItemData(iItem);
_tcscpy(m_szColumnText, m_pReportCtrl->m_arraySubItems[m_iColumn].strText);
m_hdiColumn.mask = HDI_WIDTH|HDI_TEXT|HDI_FORMAT;
m_hdiColumn.cxy = m_rcDragWnd.Width();
m_hdiColumn.pszText = m_szColumnText;
m_hdiColumn.cchTextMax = sizeof(m_szColumnText);
m_hdiColumn.fmt = HDF_STRING|HDF_LEFT;
m_pDragWnd = new CFHDragWnd;
if(m_pDragWnd)
m_pDragWnd->Create(m_rcDragWnd, &m_pReportCtrl->m_wndHeader, -2, &m_hdiColumn);
GetWindowRect(m_rcDropTarget1);
m_pReportCtrl->m_wndHeader.GetWindowRect(m_rcDropTarget2);
}
m_iDropIndex = -1;
return TRUE;
}
UINT CReportColumnListCtrl::Dragging(CPoint pt)
{
CPoint point = pt;
point.Offset(-(m_rcDragWnd.Width()>>1), -(m_rcDragWnd.Height()>>1));
if(m_pDragWnd != NULL)
m_pDragWnd->SetWindowPos(
&wndTop,
point.x, point.y,
0, 0, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE
);
if(m_rcDropTarget1.PtInRect(pt))
return DL_MOVECURSOR;
m_iDropIndex = m_pReportCtrl->m_wndHeader.SendMessage(HDM_SETHOTDIVIDER, TRUE, MAKELONG(pt.x, pt.y));
if(m_rcDropTarget2.PtInRect(pt))
return DL_MOVECURSOR;
return DL_STOPCURSOR;
}
void CReportColumnListCtrl::CancelDrag(CPoint pt)
{
m_pReportCtrl->m_wndHeader.SendMessage(HDM_SETHOTDIVIDER, FALSE, -1);
if(m_pDragWnd != NULL)
{
m_pDragWnd->DestroyWindow();
m_pDragWnd = NULL;
}
}
void CReportColumnListCtrl::Dropped(INT iSrcIndex, CPoint pt)
{
m_pReportCtrl->m_wndHeader.SendMessage(HDM_SETHOTDIVIDER, FALSE, -1);
if(m_pDragWnd != NULL)
{
m_pDragWnd->DestroyWindow();
m_pDragWnd = NULL;
}
if(m_iDropIndex >= 0)
m_pReportCtrl->ActivateColumn(m_iColumn, m_iDropIndex);
}
/////////////////////////////////////////////////////////////////////////////
// CReportEditCtrl
CReportEditCtrl::CReportEditCtrl(INT iItem, INT iSubItem)
{
m_bEndEdit = FALSE;
m_iItem = iItem;
m_iSubItem = iSubItem;
m_nLastKey = VK_RETURN;
}
CReportEditCtrl::~CReportEditCtrl()
{
}
void CReportEditCtrl::PostNcDestroy()
{
CEdit::PostNcDestroy();
delete this;
}
BEGIN_MESSAGE_MAP(CReportEditCtrl, CEdit)
//{{AFX_MSG_MAP(CReportEditCtrl)
ON_WM_KILLFOCUS()
ON_WM_GETDLGCODE()
ON_WM_CHAR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportEditCtrl operations
void CReportEditCtrl::EndEdit()
{
CString str;
if(m_bEndEdit)
return;
m_bEndEdit = TRUE;
GetWindowText(str);
NMRVITEMEDIT nmrvie;
nmrvie.hdr.hwndFrom = GetSafeHwnd();
nmrvie.hdr.idFrom = GetDlgCtrlID();
nmrvie.hdr.code = RVN_ENDITEMEDIT;
nmrvie.iItem = m_iItem;
nmrvie.iSubItem = m_iSubItem;
nmrvie.hWnd = nmrvie.hdr.hwndFrom;
nmrvie.nKey = m_nLastKey;
nmrvie.lpszText = (LPCTSTR)str;
CWnd* pWnd = GetOwner();
if(pWnd != NULL)
pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvie);
PostMessage(WM_CLOSE, 0, 0);
m_bEndEdit = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CReportEditCtrl message handlers
void CReportEditCtrl::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
EndEdit();
}
UINT CReportEditCtrl::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
void CReportEditCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
{
m_nLastKey = nChar;
GetParent()->SetFocus();
return;
}
CEdit::OnChar(nChar, nRepCnt, nFlags);
}
BOOL CReportEditCtrl::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_SYSCHAR)
return TRUE;
return CEdit::PreTranslateMessage(pMsg);
}
/////////////////////////////////////////////////////////////////////////////
// CReportComboCtrl
CReportComboCtrl::CReportComboCtrl(INT iItem, INT iSubItem)
{
m_bEndEdit = FALSE;
m_iItem = iItem;
m_iSubItem = iSubItem;
m_nLastKey = VK_RETURN;
}
CReportComboCtrl::~CReportComboCtrl()
{
}
void CReportComboCtrl::PostNcDestroy()
{
CComboBox::PostNcDestroy();
delete this;
}
BEGIN_MESSAGE_MAP(CReportComboCtrl, CComboBox)
//{{AFX_MSG_MAP(CReportComboCtrl)
ON_WM_KILLFOCUS()
ON_WM_GETDLGCODE()
ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillfocus)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportComboCtrl operations
void CReportComboCtrl::EndEdit()
{
CString str;
if(m_bEndEdit)
return;
m_bEndEdit = TRUE;
GetWindowText(str);
NMRVITEMEDIT nmrvie;
nmrvie.hdr.hwndFrom = GetSafeHwnd();
nmrvie.hdr.idFrom = GetDlgCtrlID();
nmrvie.hdr.code = RVN_ENDITEMEDIT;
nmrvie.iItem = m_iItem;
nmrvie.iSubItem = m_iSubItem;
nmrvie.hWnd = nmrvie.hdr.hwndFrom;
nmrvie.nKey = m_nLastKey;
nmrvie.lpszText = (LPCTSTR)str;
CWnd* pWnd = GetOwner();
if(pWnd != NULL)
pWnd->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmrvie);
PostMessage(WM_CLOSE, 0, 0);
m_bEndEdit = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CReportComboCtrl message handlers
void CReportComboCtrl::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
if(IsChild(pNewWnd))
return;
EndEdit();
}
UINT CReportComboCtrl::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
BOOL CReportComboCtrl::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_CHAR &&
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
) {
m_nLastKey = pMsg->wParam;
GetParent()->SetFocus();
return TRUE;
}
if (pMsg->message == WM_SYSCHAR)
return TRUE;
return CComboBox::PreTranslateMessage(pMsg);
}
void CReportComboCtrl::OnKillfocus()
{
EndEdit();
}
/////////////////////////////////////////////////////////////////////////////
// CReportTipCtrl
CReportTipCtrl::CReportTipCtrl()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
if(!(::GetClassInfo(hInst, REPORTTIPCTRL_CLASSNAME, &wndcls)))
{
wndcls.style = CS_SAVEBITS ;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = LoadCursor(hInst, IDC_ARROW);
wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK+1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = REPORTTIPCTRL_CLASSNAME;
if(!AfxRegisterClass(&wndcls))
AfxThrowResourceException();
}
m_dwLastLButtonDown = ULONG_MAX;
m_dwDblClickMsecs = GetDoubleClickTime();
}
CReportTipCtrl::~CReportTipCtrl()
{
}
BEGIN_MESSAGE_MAP(CReportTipCtrl, CWnd)
//{{AFX_MSG_MAP(CReportTipCtrl)
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CReportTipCtrl message handlers
BOOL CReportTipCtrl::Create(CReportCtrl* pReportCtrl)
{
ASSERT_VALID(pReportCtrl);
DWORD dwStyle = WS_BORDER|WS_POPUP;
DWORD dwExStyle = WS_EX_TOOLWINDOW|WS_EX_TOPMOST;
m_pReportCtrl = pReportCtrl;
return CreateEx(dwExStyle, REPORTTIPCTRL_CLASSNAME, NULL, dwStyle,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL );
}
BOOL CReportTipCtrl::Show(CRect rectText, LPCTSTR lpszText, CFont* pFont)
{
ASSERT(::IsWindow(GetSafeHwnd()));
if(rectText.IsRectEmpty())
return FALSE;
if(IsWindowVisible())
return FALSE;
if(GetFocus() == NULL)
return FALSE;
m_rectText.top = -1;
m_rectText.left = -1;
m_rectText.right = rectText.Width()+1;
m_rectText.bottom = rectText.Height();
m_pReportCtrl->ClientToScreen(rectText);
CClientDC dc(this);
pFont = pFont == NULL ? m_pReportCtrl->GetFont():pFont;
CFont *pFontDC = dc.SelectObject(pFont);
CRect rectDisplay = rectText;
CSize size = dc.GetTextExtent(lpszText, _tcslen(lpszText));
rectDisplay.right = rectDisplay.left + size.cx + 2*m_pReportCtrl->m_iSpacing;
BOOL bResult = FALSE;
if(rectDisplay.right > rectText.right)
{
SetWindowPos(
&wndTop,
rectDisplay.left, rectDisplay.top,
rectDisplay.Width(), rectDisplay.Height(),
SWP_SHOWWINDOW|SWP_NOACTIVATE
);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(m_pReportCtrl->m_iSpacing-1, 0, lpszText);
SetCapture();
bResult = TRUE;
}
dc.SelectObject(pFontDC);
return bResult;
}
void CReportTipCtrl::Hide()
{
if (!::IsWindow(GetSafeHwnd()))
return;
if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
ReleaseCapture();
ShowWindow(SW_HIDE);
}
void CReportTipCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if(!m_rectText.PtInRect(point))
{
Hide();
ClientToScreen(&point);
CWnd *pWnd = WindowFromPoint(point);
if(pWnd == this)
pWnd = m_pReportCtrl;
INT iHitTest = (INT)pWnd->SendMessage(
WM_NCHITTEST,
0,
MAKELONG(point.x,point.y)
);
if(iHitTest == HTCLIENT)
{
pWnd->ScreenToClient(&point);
pWnd->PostMessage(
WM_MOUSEMOVE,
nFlags,
MAKELONG(point.x,point.y)
);
}
else
{
pWnd->PostMessage(
WM_NCMOUSEMOVE,
iHitTest,
MAKELONG(point.x,point.y)
);
}
}
}
BOOL CReportTipCtrl::PreTranslateMessage(MSG* pMsg)
{
DWORD dwTick = 0;
BOOL bDoubleClick = FALSE;
CWnd *pWnd;
INT iHitTest;
switch (pMsg->message)
{
case WM_LBUTTONDOWN:
dwTick = GetTickCount();
bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= m_dwDblClickMsecs);
m_dwLastLButtonDown = dwTick;
// Notice fall-through
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
{
POINTS points = MAKEPOINTS(pMsg->lParam);
POINT point;
point.x = points.x;
point.y = points.y;
ClientToScreen(&point);
pWnd = WindowFromPoint(point);
if(pWnd == this)
pWnd = m_pReportCtrl;
iHitTest = (INT)pWnd->SendMessage(
WM_NCHITTEST,
0,
MAKELONG(point.x, point.y)
);
if(iHitTest == HTCLIENT)
{
pWnd->ScreenToClient(&point);
pMsg->lParam = MAKELONG(point.x,point.y);
}
else
{
switch (pMsg->message)
{
case WM_LBUTTONDOWN: pMsg->message = WM_NCLBUTTONDOWN; break;
case WM_RBUTTONDOWN: pMsg->message = WM_NCRBUTTONDOWN; break;
case WM_MBUTTONDOWN: pMsg->message = WM_NCMBUTTONDOWN; break;
}
pMsg->wParam = iHitTest;
pMsg->lParam = MAKELONG(point.x,point.y);
}
Hide();
pWnd->PostMessage(
bDoubleClick ? WM_LBUTTONDBLCLK : pMsg->message,
pMsg->wParam,
pMsg->lParam
);
return TRUE;
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
Hide();
m_pReportCtrl->PostMessage(
pMsg->message,
pMsg->wParam,
pMsg->lParam
);
return TRUE;
}
if(GetFocus() == NULL)
{
Hide();
return TRUE;
}
return CWnd::PreTranslateMessage(pMsg);
}