//////////////////////////////////////////////////////////////////////////// // 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=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=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=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= 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(iColumn0); // 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;iItemiItem > 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(;iFirsttop += 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;iFirstleft += 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 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 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;ilpszText != 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= 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;iUpdateList(); 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 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;iUpdateList(); 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=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 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(iRowiLast) { 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;iHeaderItempoint)) break; rectItem.left = rectItem.right; } lprvhti->iSubItem = hdi.lParam; lprvhti->iColumn = iHeaderItem; if(iHeaderItemiSubItem; 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.ynFlags |= lprvhti->point.y>m_rectReport.bottom ? RVHT_BELOW:0; lprvhti->nFlags |= lprvhti->point.xnFlags |= 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;i0) || (!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;i0) || (!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;ipalPalEntry[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;ipalPalEntry[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;iRow0;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;iiLast) && 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= 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) -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 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= 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.bottomMoveTo(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.bottomMoveTo(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;iColumnMoveTo(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;iColumniSubItem = 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->iImageGetImageCount()); 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()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 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 0) for (i=0;iiPagesScrolled;i--) PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0); } else { int iRowsScrolled = (int)m_nRowsPerWheelNotch * zDelta / 120; if (iRowsScrolled>0) for (i=0;iiRowsScrolled;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;iColumnIsActiveColumn(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); }